import json from datetime import datetime from typer.testing import CliRunner from tht.cli import app # the root Typer app that mounts schema_app as "schema" from tht.mschema.models import ColumnPhysical, PhysicalSchema, TablePhysical def _write_catalog(tmp_path): phys = PhysicalSchema( database="d", schema="s", introspected_at=datetime(2026, 1, 1), tables={ "dim_patient": TablePhysical( comment="Anagrafica", columns={ "cod_paz": ColumnPhysical(type="bigint", pk=True, comment="Codice paziente"), "nome": ColumnPhysical(type="text", comment="Nome"), }, ) }, ) out = tmp_path / "artifacts" / "mschema" / "physical.yaml" phys.to_yaml(out) return out def test_schema_columns_json(tmp_path, monkeypatch): _write_catalog(tmp_path) cfg = tmp_path / "workspace.yaml" cfg.write_text( "database: {database: d, schema: s, user: u, password: p, transport: direct}\n" f"paths: {{artifacts: {tmp_path/'artifacts'}, indexes: {tmp_path/'i'}, sessions: {tmp_path/'s'}}}\n" ) res = CliRunner().invoke(app, ["schema", "columns", "dim_patient", "--json", "-c", str(cfg)]) assert res.exit_code == 0, res.output data = json.loads(res.output) assert data["table"] == "dim_patient" assert data["description"] == "Anagrafica" assert {"name": "cod_paz", "description": "Codice paziente", "type": "bigint", "pk": True} in data["columns"] def _write_family_catalog(tmp_path): def _t(comment): return TablePhysical( comment=comment, columns={"cod_paz": ColumnPhysical(type="bigint", pk=True, comment="Codice paziente")}, ) phys = PhysicalSchema( database="d", schema="s", introspected_at=datetime(2026, 1, 1), tables={ "fact_sost_impianto_pmk": _t("Sost PMK"), "fact_sost_impianto_crt_d": _t("Sost CRT-D"), "fact_impianto_pacemaker": _t("Impianto PMK"), }, ) out = tmp_path / "artifacts" / "mschema" / "physical.yaml" phys.to_yaml(out) return out def _cfg(tmp_path): cfg = tmp_path / "workspace.yaml" cfg.write_text( "database: {database: d, schema: s, user: u, password: p, transport: direct}\n" f"paths: {{artifacts: {tmp_path/'artifacts'}, indexes: {tmp_path/'i'}, sessions: {tmp_path/'s'}}}\n" ) return cfg def test_schema_columns_glob_resolves_the_matching_family(tmp_path): _write_family_catalog(tmp_path) res = CliRunner().invoke( app, ["schema", "columns", "fact_sost_impianto_*", "--json", "-c", str(_cfg(tmp_path))] ) assert res.exit_code == 0, res.output data = json.loads(res.output) assert isinstance(data, list) # a pattern yields an array of per-table objects assert sorted(d["table"] for d in data) == ["fact_sost_impianto_crt_d", "fact_sost_impianto_pmk"] def test_schema_columns_glob_without_matches_errors(tmp_path): _write_family_catalog(tmp_path) res = CliRunner().invoke( app, ["schema", "columns", "fact_assente_*", "-c", str(_cfg(tmp_path))] ) assert res.exit_code == 1 assert "nessuna tabella corrisponde al pattern" in res.output def test_schema_columns_exact_miss_suggests_siblings(tmp_path): _write_family_catalog(tmp_path) res = CliRunner().invoke( app, ["schema", "columns", "fact_sost_impianto_xyz", "-c", str(_cfg(tmp_path))] ) assert res.exit_code == 1 assert "tabella non nel catalogo" in res.output assert "fact_sost_impianto_crt_d" in res.output # sibling suggested to aid recovery