#!/usr/bin/env python3 from __future__ import annotations import argparse import json from pathlib import Path from typing import Any ROOT = Path(__file__).resolve().parents[1] TABLE_SCHEMAS: dict[str, str] = { "collection_runs": """ CREATE TABLE collection_runs ( run_id TEXT PRIMARY KEY, collector_name TEXT NOT NULL, started_at TEXT NOT NULL, finished_at TEXT, status TEXT NOT NULL, input_source TEXT, output_json_path TEXT, output_db_path TEXT, notes TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); """.strip(), "collection_snapshots": """ CREATE TABLE collection_snapshots ( run_id TEXT NOT NULL, dataset_name TEXT NOT NULL, ticker TEXT NOT NULL, name TEXT, sector TEXT, as_of_date TEXT, source_priority TEXT, source_status TEXT, payload_json TEXT NOT NULL, provenance_json TEXT NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW(), PRIMARY KEY (run_id, dataset_name, ticker) ); """.strip(), "collection_source_errors": """ CREATE TABLE collection_source_errors ( run_id TEXT NOT NULL, ticker TEXT, source_name TEXT NOT NULL, error_kind TEXT NOT NULL, error_message TEXT NOT NULL, payload_json TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); """.strip(), "sell_strategy_results": """ CREATE TABLE sell_strategy_results ( id BIGSERIAL PRIMARY KEY, code TEXT NOT NULL, generated_at TEXT NOT NULL, action TEXT, conviction TEXT, market_regime TEXT, composite_score DOUBLE PRECISION, rationale TEXT, raw_json TEXT NOT NULL, inserted_at TIMESTAMPTZ DEFAULT NOW() ); """.strip(), "satellite_recommendations": """ CREATE TABLE satellite_recommendations ( id BIGSERIAL PRIMARY KEY, ticker TEXT NOT NULL, generated_at TEXT NOT NULL, satellite_action TEXT, attractiveness_score DOUBLE PRECISION, market_regime TEXT, raw_json TEXT NOT NULL, inserted_at TIMESTAMPTZ DEFAULT NOW() ); """.strip(), } def main() -> int: ap = argparse.ArgumentParser(description="Emit PostgreSQL migration stub from current canonical row contract.") ap.add_argument("--output-json", type=Path, default=ROOT / "Temp" / "postgresql_upgrade_stub_v1.json") ap.add_argument("--output-sql", type=Path, default=ROOT / "Temp" / "postgresql_upgrade_stub_v1.sql") args = ap.parse_args() sql_lines = [ "-- PostgreSQL upgrade stub", "-- This file is a contract placeholder only. It is not executed by CI.", "", ] for name, ddl in TABLE_SCHEMAS.items(): sql_lines.append(f"-- {name}") sql_lines.append(ddl) sql_lines.append("") sql_text = "\n".join(sql_lines).rstrip() + "\n" args.output_sql.parent.mkdir(parents=True, exist_ok=True) args.output_sql.write_text(sql_text, encoding="utf-8") payload: dict[str, Any] = { "formula_id": "POSTGRESQL_UPGRADE_STUB_V1", "gate": "DATA_GATED", "tables": sorted(TABLE_SCHEMAS.keys()), "output_sql": str(args.output_sql), "note": "DDL stub only; execution deferred until PostgreSQL rollout.", } args.output_json.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8") print(json.dumps(payload, ensure_ascii=False, indent=2)) return 0 if __name__ == "__main__": raise SystemExit(main())