ODBC only exposes Tables and non-hidden SELECT queries, so this used DAO COM automation (migration/catalog_objects.py, requires pywin32) to catalog Reports, Forms, and full Query SQL text across all four files instead. Key finding: SEGUROS 16.mdb, previously noted as having zero data tables, turns out to hold all 212 Reports/149 Forms/857 Queries for the insurance line - SEGUROS 16_be.mdb is confirmed pure data storage with zero saved objects. The renewal-notice reports also reveal a RENEW/RENEW2/RENEW3 multi-notice reminder cycle not visible in the table schema. docs/LEGACY_DATABASES_OBJECTS.md documents all of this with the full 751 real queries' SQL text (business logic: billing math, year- rollover batches, duplicate/delinquency detection). Raw output at migration/objects.json. Cross-linked from RESUME.md and the existing table-only LEGACY_DATABASES.md.
107 lines
3.7 KiB
Python
107 lines
3.7 KiB
Python
"""
|
|
Renders objects.json (from catalog_objects.py) into Markdown: Reports and
|
|
Forms as name lists (DAO's catalog interface doesn't expose RecordSource or
|
|
layout, only names/metadata - see catalog_objects.py docstring), real
|
|
(non-hidden) Queries with full SQL text since that's where the actual
|
|
business logic lives, hidden ~sq_ queries collapsed to a count.
|
|
|
|
Usage:
|
|
python render_objects_md.py objects.json --output objects.md
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
|
|
SOURCE_TITLES = {
|
|
"utilities": "UTILITIES.accdb",
|
|
"seguros_frontend": "SEGUROS 16.mdb (frontend)",
|
|
"seguros_backend": "SEGUROS 16_be.mdb (backend)",
|
|
"scothia": "SCOTHIA.mdb",
|
|
}
|
|
|
|
QUERY_TYPE_LABELS = {
|
|
0: "Select",
|
|
16: "Select (linked ODBC)",
|
|
32: "Crosstab",
|
|
48: "Delete",
|
|
64: "Update",
|
|
80: "Append",
|
|
96: "Make-Table",
|
|
112: "DDL",
|
|
128: "SQL Pass-Through",
|
|
144: "SQL Pass-Through (bulk)",
|
|
160: "Union",
|
|
176: "Procedure",
|
|
}
|
|
|
|
|
|
def render_name_list(title: str, names: list[str]) -> str:
|
|
lines = [f"##### {title} ({len(names)})", ""]
|
|
if not names:
|
|
lines.append("_none_")
|
|
lines.append("")
|
|
return "\n".join(lines)
|
|
for name in sorted(names):
|
|
lines.append(f"- `{name}`")
|
|
lines.append("")
|
|
return "\n".join(lines)
|
|
|
|
|
|
def render_queries(queries: list[dict]) -> str:
|
|
real = sorted((q for q in queries if not q["hidden"]), key=lambda q: q["name"])
|
|
hidden = [q for q in queries if q["hidden"]]
|
|
|
|
lines = [f"##### Queries ({len(queries)} total — {len(real)} real, {len(hidden)} hidden internal subqueries)", ""]
|
|
if hidden:
|
|
lines.append(f"_{len(hidden)} hidden `~sq_`-prefixed queries omitted — these are Access-generated internal subquery caches, not authored business logic._")
|
|
lines.append("")
|
|
|
|
for q in real:
|
|
type_label = QUERY_TYPE_LABELS.get(q["type"], f"type {q['type']}")
|
|
lines.append(f"###### `{q['name']}` ({type_label})")
|
|
lines.append("")
|
|
lines.append("```sql")
|
|
lines.append(q["sql"].strip() if q["sql"] else "-- (empty)")
|
|
lines.append("```")
|
|
lines.append("")
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
def render_source(source_name: str, source_data: dict) -> str:
|
|
title = SOURCE_TITLES.get(source_name, source_name)
|
|
lines = [f"### {title}", ""]
|
|
lines.append(render_name_list("Reports", source_data["reports"]))
|
|
lines.append(render_name_list("Forms", source_data["forms"]))
|
|
lines.append(render_queries(source_data["queries"]))
|
|
return "\n".join(lines)
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("catalog", type=Path)
|
|
parser.add_argument("--output", type=Path, default=Path("objects_appendix.md"))
|
|
args = parser.parse_args()
|
|
|
|
catalog = json.loads(args.catalog.read_text(encoding="utf-8"))
|
|
|
|
sections = [
|
|
"## Appendix: Reports, Forms & Queries",
|
|
"",
|
|
"Generated by `migration/catalog_objects.py` + `migration/render_objects_md.py` via DAO COM automation (not visible through plain ODBC). Reports and Forms are listed by name only — DAO's catalog interface doesn't expose RecordSource or visual layout without full MS Access installed. Queries include full SQL text, which is where the real computational business logic lives (billing math, renewal batching, filters).",
|
|
"",
|
|
]
|
|
for source_name in ["utilities", "seguros_frontend", "seguros_backend", "scothia"]:
|
|
if source_name in catalog:
|
|
sections.append(render_source(source_name, catalog[source_name]))
|
|
|
|
args.output.write_text("\n".join(sections), encoding="utf-8")
|
|
print(f"Wrote {args.output}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|