55 lines
2.9 KiB
Python
55 lines
2.9 KiB
Python
"""Read-only structural consistency checks; no PostgreSQL execution claims."""
|
|
import csv, hashlib, json, re
|
|
from pathlib import Path
|
|
root=Path(__file__).resolve().parents[2]
|
|
base=root/'docs/investmoz'
|
|
schema=json.loads((base/'schema.json').read_text(encoding='utf-8'))
|
|
legacy=json.loads((base/'legacy-schema.json').read_text(encoding='utf-8'))
|
|
tables={t['name']:t for t in legacy['tables']+schema['tables']}
|
|
def rows(name):
|
|
return list(csv.DictReader((base/name).open(encoding='utf-8',newline='')))
|
|
catalog=rows('table-catalog.csv')
|
|
assert {r['Tabela'] for r in catalog}==set(tables)
|
|
dictionary=rows('data-dictionary.csv')
|
|
fields={(t,c['name']) for t,v in tables.items() for c in v['columns']}
|
|
assert {(r['Tabela'],r['Campo']) for r in dictionary}==fields
|
|
assert len(dictionary)==len(fields)
|
|
trace=rows('traceability.csv')
|
|
assert {(r['Tabela'],r['Campo']) for r in trace}==fields
|
|
erd=(base/'erd.mmd').read_text(encoding='utf-8')
|
|
erd_fields=set()
|
|
for table,body in re.findall(r'^\s+(\w+) \{\n(.*?)^\s+\}',erd,re.M|re.S):
|
|
for line in body.splitlines():
|
|
if line.strip(): erd_fields.add((table,line.split()[1]))
|
|
assert erd_fields==fields
|
|
seen=set(t['name'] for t in legacy['tables'])
|
|
for t in schema['tables']:
|
|
sql=(root/t['migration']).read_text(encoding='utf-8')
|
|
assert t['sql'] in sql
|
|
for rel in schema['relationships']:
|
|
if rel['table']!=t['name']: continue
|
|
assert rel['target'] in seen or rel['target']==t['name'],rel
|
|
target=tables[rel['target']]
|
|
ct=next(c['type'] for c in t['columns'] if c['name']==rel['column'])
|
|
rt=next(c['type'] for c in target['columns'] if c['name']==rel['target_column'])
|
|
assert ct==rt,(rel,ct,rt)
|
|
assert f"{rel['target']} "+('|o' if rel['nullable'] else '||')+f" --o{{ {rel['table']} : {rel['column']}" in erd
|
|
seen.add(t['name'])
|
|
for item in schema['indexes']:
|
|
assert item['sql'] in (root/item['migration']).read_text(encoding='utf-8')
|
|
names=[i['name'] for i in schema['indexes']]+[c['name'] for c in schema['constraints']]
|
|
assert len(names)==len(set(names))
|
|
assert all(len(n)<=63 for n in names)
|
|
migrations=list((root/'database/migrations').glob('2026_09_24_*_investmoz_*.php'))
|
|
assert len(migrations)==15,len(migrations)
|
|
for path in migrations:
|
|
php=path.read_text(encoding='utf-8')
|
|
down=php.split('public function down(): void')[1]
|
|
assert not re.search(r'DROP .* CASCADE|DROP EXTENSION',down)
|
|
assert php.count("<<<'SQL'")==php.count('\nSQL);')
|
|
for line in (base/'checksums.sha256').read_text(encoding='utf-8').splitlines():
|
|
digest,path=line.split(' ',1)
|
|
assert hashlib.sha256((root/path).read_bytes()).hexdigest()==digest,path
|
|
print(f"PASS: {len(tables)} tables, {len(fields)} columns, {len(schema['relationships'])+len(legacy['relationships'])} FKs, 15 migrations; catalogue/dictionary/ERD/checksums coherent.")
|
|
print("PostgreSQL/PostGIS lifecycle, authorization and performance are NOT validated by this static check.")
|