#!/usr/bin/env python
"""Print schema.sql from infrastructure/tables.py (the one source), DataK3's DDL subset: CREATE TABLE IF NOT EXISTS
with the full primary key. tests/test_schema.py fails when src/brick_hr/schema.sql drifts from it.
python scripts/gen_schema.py > src/brick_hr/schema.sql
"""
import pathlib
import sys
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1] / "src"))
from sqlalchemy.dialects import postgresql # noqa: E402
from brick_hr.infrastructure.tables import ADDED, md # noqa: E402
HEAD = """-- brick-hr: people, starters and leavers. GENERATED from src/brick_hr/infrastructure/tables.py by
-- scripts/gen_schema.py — edit tables.py, then regenerate. Additive only: a new column goes at the END of its
-- CREATE and as an explicit ALTER below it (erp-migrate refuses DROP / RENAME / type changes).
-- Natural keys only (never SERIAL); every child table's key starts with its aggregate root's key.
-- DataK3 enforces no foreign key: this brick being the ONLY writer of hr_* is the integrity.
"""
def render() -> str:
d = postgresql.dialect()
out = [HEAD]
for t in md.sorted_tables:
cols = []
for c in t.columns:
null = " NOT NULL" if (not c.nullable or c.primary_key) else ""
typ = c.type.compile(dialect=d).replace(" WITHOUT TIME ZONE", "").replace(", ", ",")
cols.append(f" {c.name} {typ}{null}")
pk = ", ".join(c.name for c in t.primary_key.columns)
out.append(f"CREATE TABLE IF NOT EXISTS {t.name} (\n" + ",\n".join(cols) + f",\n PRIMARY KEY ({pk})\n);\n")
if ADDED:
out.append("-- Columns added after their table first shipped, for a bucket that predates them (at the END of the CREATE\n"
"-- above too). erp-migrate marks these DISRUPTIVE: reads on the table stall for minutes after an ADD COLUMN,\n"
"-- so migrate the test copy first and the live one at a quiet hour.")
tables = {t.name: t for t in md.sorted_tables}
for table, column, why in ADDED:
typ = tables[table].c[column].type.compile(dialect=d).replace(" WITHOUT TIME ZONE", "")
out.append(f"-- {why}\nALTER TABLE {table} ADD COLUMN {column} {typ};")
out.append("")
return "\n".join(out)
if __name__ == "__main__":
sys.stdout.write(render())