dodil/erp-brick-contracts

scripts/gen_schema.py

#!/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 — plus the capability claim and log tables erp_platform prints for a provider.
tests/test_schema.py fails when src/brick_contracts/schema.sql drifts from it.

    python scripts/gen_schema.py > src/brick_contracts/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 erp_platform import capabilities  # noqa: E402

from brick_contracts.infrastructure.tables import md  # noqa: E402

HEAD = """-- brick-contracts: contracts, the clause library, templates and simple e-signature evidence. GENERATED from
-- src/brick_contracts/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. ct_signature_event is APPEND-ONLY (written by plain INSERT, never updated).
-- DataK3 enforces no foreign key: this brick being the ONLY writer of ct_* 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")
    out.append("-- The capability claims and action log of a PROVIDER (contracts.draft / send / status / fetch_executed),\n"
               "-- named by the platform after the brick (contracts_), not ct_.\n" + capabilities.ddl("contracts"))
    return "\n".join(out)


if __name__ == "__main__":
    sys.stdout.write(render())