bdv / src /db /schema.py
stephmnt's picture
Sync from GitHub Actions
46f9144 verified
from __future__ import annotations
import os
from typing import Optional
import sqlalchemy as sa
from sqlalchemy import Column, Date, Float, ForeignKey, Integer, MetaData, String, Table, UniqueConstraint
from sqlalchemy.engine import Engine
metadata = MetaData()
communes = Table(
"communes",
metadata,
Column("id", Integer, primary_key=True, autoincrement=True),
Column("name_normalized", String(255), nullable=True),
Column("insee_code", String(12), nullable=False, unique=True, index=True),
)
bureaux = Table(
"bureaux",
metadata,
Column("id", Integer, primary_key=True, autoincrement=True),
Column("commune_id", Integer, ForeignKey("communes.id"), nullable=False),
Column("bureau_code", String(32), nullable=False),
Column("bureau_label", String(255), nullable=True),
UniqueConstraint("commune_id", "bureau_code", name="uq_bureau_commune_code"),
)
elections = Table(
"elections",
metadata,
Column("id", Integer, primary_key=True, autoincrement=True),
Column("election_type", String(32), nullable=False),
Column("election_year", Integer, nullable=False),
Column("round", Integer, nullable=True),
Column("date", Date, nullable=True),
UniqueConstraint("election_type", "election_year", "round", name="uq_election_unique"),
)
categories = Table(
"categories",
metadata,
Column("id", Integer, primary_key=True, autoincrement=True),
Column("name", String(64), nullable=False, unique=True),
)
results_local = Table(
"results_local",
metadata,
Column("id", Integer, primary_key=True, autoincrement=True),
Column("bureau_id", Integer, ForeignKey("bureaux.id"), nullable=False),
Column("election_id", Integer, ForeignKey("elections.id"), nullable=False),
Column("category_id", Integer, ForeignKey("categories.id"), nullable=False),
Column("share_pct", Float, nullable=True),
Column("votes", Float, nullable=True),
Column("expressed", Float, nullable=True),
Column("turnout_pct", Float, nullable=True),
UniqueConstraint("bureau_id", "election_id", "category_id", name="uq_local_bureau_election_category"),
)
results_national = Table(
"results_national",
metadata,
Column("id", Integer, primary_key=True, autoincrement=True),
Column("election_id", Integer, ForeignKey("elections.id"), nullable=False),
Column("category_id", Integer, ForeignKey("categories.id"), nullable=False),
Column("share_pct", Float, nullable=True),
Column("votes", Float, nullable=True),
Column("expressed", Float, nullable=True),
Column("turnout_pct", Float, nullable=True),
UniqueConstraint("election_id", "category_id", name="uq_nat_election_category"),
)
def _build_url_from_env() -> Optional[str]:
user = os.getenv("DB_USER") or os.getenv("POSTGRES_USER")
password = os.getenv("DB_PASSWORD") or os.getenv("POSTGRES_PASSWORD")
host = os.getenv("DB_HOST", "localhost")
port = os.getenv("DB_PORT", os.getenv("POSTGRES_PORT", "5432"))
db_name = os.getenv("DB_NAME") or os.getenv("POSTGRES_DB")
if user and password and db_name:
return f"postgresql+psycopg2://{user}:{password}@{host}:{port}/{db_name}"
return None
def get_engine(url: Optional[str] = None) -> Engine:
db_url = url or os.getenv("DATABASE_URL") or _build_url_from_env()
if not db_url:
raise RuntimeError("DATABASE_URL or DB_* env vars must be set.")
return sa.create_engine(db_url)
def create_schema(engine: Engine) -> None:
metadata.create_all(engine)