diff --git a/backend/app/db/models/recommendations.py b/backend/app/db/models/recommendations.py index 8fad1ff3..7d03bdba 100644 --- a/backend/app/db/models/recommendations.py +++ b/backend/app/db/models/recommendations.py @@ -28,19 +28,18 @@ from backend.app.db.base import Base from backend.app.db.models.portfolio import Portfolio, PortfolioGoal, PropertyModel from infrastructure.postgres.modelling import ( - PlanRow, + PlanModel, PlanType, - RecommendationMaterialRow, - RecommendationRow, + RecommendationMaterialModel, + RecommendationModel, ) # Legacy names → the single SQLModel definitions now in # `infrastructure/postgres/modelling/`. The `plan_recommendations` m2m is # retired (ADR-0017 amendment) — measures link to their Plan via # `recommendation.plan_id`. -Recommendation = RecommendationRow -RecommendationMaterials = RecommendationMaterialRow -PlanModel = PlanRow +Recommendation = RecommendationModel +RecommendationMaterials = RecommendationMaterialModel PlanTypeEnum = PlanType @@ -167,5 +166,5 @@ def enum_values(e: Iterable[PlanType]) -> list[str]: class PlanPersistence(NamedTuple): - plan: PlanRow + plan: PlanModel scenario: ScenarioModel diff --git a/infrastructure/postgres/modelling/__init__.py b/infrastructure/postgres/modelling/__init__.py index 6b882b25..8236549b 100644 --- a/infrastructure/postgres/modelling/__init__.py +++ b/infrastructure/postgres/modelling/__init__.py @@ -8,15 +8,15 @@ One canonical SQLModel per physical table — `plan`, `recommendation`, `plan_recommendations` m2m is retired. """ -from infrastructure.postgres.modelling.plan_table import PlanRow, PlanType +from infrastructure.postgres.modelling.plan_table import PlanModel, PlanType from infrastructure.postgres.modelling.recommendation_table import ( - RecommendationMaterialRow, - RecommendationRow, + RecommendationMaterialModel, + RecommendationModel, ) __all__ = [ - "PlanRow", + "PlanModel", "PlanType", - "RecommendationRow", - "RecommendationMaterialRow", + "RecommendationModel", + "RecommendationMaterialModel", ] diff --git a/infrastructure/postgres/modelling/plan_table.py b/infrastructure/postgres/modelling/plan_table.py index 7cbed104..75485c9d 100644 --- a/infrastructure/postgres/modelling/plan_table.py +++ b/infrastructure/postgres/modelling/plan_table.py @@ -25,7 +25,7 @@ class PlanType(enum.Enum): EXTRACTION_ECO = "extraction_eco" -class PlanRow(SQLModel, table=True): +class PlanModel(SQLModel, table=True): """The single SQLModel definition of the live ``plan`` table (ADR-0017 amendment). Full legacy column parity; out-of-cluster references (``portfolio_id`` / ``property_id`` / ``scenario_id``) are plain indexed @@ -87,7 +87,7 @@ class PlanRow(SQLModel, table=True): scenario_id: int, portfolio_id: int, is_default: bool, - ) -> "PlanRow": + ) -> "PlanModel": return cls( portfolio_id=portfolio_id, property_id=property_id, diff --git a/infrastructure/postgres/modelling/recommendation_table.py b/infrastructure/postgres/modelling/recommendation_table.py index 67b327a3..77af71fc 100644 --- a/infrastructure/postgres/modelling/recommendation_table.py +++ b/infrastructure/postgres/modelling/recommendation_table.py @@ -16,7 +16,7 @@ from domain.modelling.plan import PlanMeasure _KG_PER_TONNE = 1000.0 -class RecommendationRow(SQLModel, table=True): +class RecommendationModel(SQLModel, table=True): """The single SQLModel definition of the live ``recommendation`` table (ADR-0017 amendment) — one row per persisted Plan Measure. @@ -68,7 +68,7 @@ class RecommendationRow(SQLModel, table=True): @classmethod def from_domain( cls, measure: PlanMeasure, *, property_id: int, plan_id: int - ) -> "RecommendationRow": + ) -> "RecommendationModel": return cls( property_id=property_id, plan_id=plan_id, @@ -87,7 +87,7 @@ class RecommendationRow(SQLModel, table=True): ) -class RecommendationMaterialRow(SQLModel, table=True): +class RecommendationMaterialModel(SQLModel, table=True): """The live ``recommendation_materials`` table — one row per material used by a Recommendation. ``recommendation_id`` is an intra-cluster FK; ``material_id`` is a plain int (out-of-cluster, mirror convention).""" diff --git a/repositories/plan/plan_postgres_repository.py b/repositories/plan/plan_postgres_repository.py index 75e9096c..376cf8b8 100644 --- a/repositories/plan/plan_postgres_repository.py +++ b/repositories/plan/plan_postgres_repository.py @@ -3,7 +3,7 @@ from __future__ import annotations from sqlmodel import Session, col, delete from domain.modelling.plan import Plan -from infrastructure.postgres.modelling import PlanRow, RecommendationRow +from infrastructure.postgres.modelling import PlanModel, RecommendationModel from repositories.plan.plan_repository import PlanRepository @@ -28,13 +28,13 @@ class PlanPostgresRepository(PlanRepository): # cascades to its recommendation rows via the plan_id FK (ON DELETE # CASCADE), so a re-run overwrites rather than duplicating (ADR-0012). self._session.exec( # type: ignore[call-overload] - delete(PlanRow).where( - col(PlanRow.property_id) == property_id, - col(PlanRow.scenario_id) == scenario_id, + delete(PlanModel).where( + col(PlanModel.property_id) == property_id, + col(PlanModel.scenario_id) == scenario_id, ) ) - plan_row = PlanRow.from_domain( + plan_row = PlanModel.from_domain( plan, property_id=property_id, scenario_id=scenario_id, @@ -48,7 +48,7 @@ class PlanPostgresRepository(PlanRepository): for measure in plan.measures: self._session.add( - RecommendationRow.from_domain( + RecommendationModel.from_domain( measure, property_id=property_id, plan_id=plan_row.id ) ) diff --git a/tests/orchestration/test_ara_first_run_pipeline_integration.py b/tests/orchestration/test_ara_first_run_pipeline_integration.py index 70f2087c..b042ca77 100644 --- a/tests/orchestration/test_ara_first_run_pipeline_integration.py +++ b/tests/orchestration/test_ara_first_run_pipeline_integration.py @@ -26,7 +26,7 @@ from infrastructure.postgres.property_baseline_performance_table import ( PropertyBaselinePerformanceModel, ) from infrastructure.postgres.epc_property_table import EpcPropertyModel -from infrastructure.postgres.modelling import PlanRow, RecommendationRow +from infrastructure.postgres.modelling import PlanModel, RecommendationModel from infrastructure.postgres.product_table import MaterialRow from infrastructure.postgres.property_table import PropertyRow from tests.domain.sap10_calculator.worksheet._elmhurst_worksheet_000490 import ( @@ -269,12 +269,12 @@ def test_modelling_optimises_and_persists_a_multi_measure_plan( # (ADR-0016). Each is priced and attributed, linked by plan_id. with Session(db_engine) as session: plan = session.exec( - select(PlanRow).where(col(PlanRow.property_id) == 30) + select(PlanModel).where(col(PlanModel.property_id) == 30) ).first() assert plan is not None rec_rows = session.exec( - select(RecommendationRow).where( - col(RecommendationRow.plan_id) == plan.id + select(RecommendationModel).where( + col(RecommendationModel.plan_id) == plan.id ) ).all() @@ -413,12 +413,12 @@ def test_modelling_recommends_nothing_when_already_at_the_target_band( # post-retrofit figure is the unchanged baseline (still band D). with Session(db_engine) as session: plan = session.exec( - select(PlanRow).where(col(PlanRow.property_id) == 31) + select(PlanModel).where(col(PlanModel.property_id) == 31) ).first() assert plan is not None rec_rows = session.exec( - select(RecommendationRow).where( - col(RecommendationRow.plan_id) == plan.id + select(RecommendationModel).where( + col(RecommendationModel.plan_id) == plan.id ) ).all() diff --git a/tests/repositories/plan/test_plan_postgres_repository.py b/tests/repositories/plan/test_plan_postgres_repository.py index 94033b00..8ee0f0f8 100644 --- a/tests/repositories/plan/test_plan_postgres_repository.py +++ b/tests/repositories/plan/test_plan_postgres_repository.py @@ -18,7 +18,7 @@ from domain.modelling.scoring.package_scorer import Score from domain.modelling.plan import Plan, PlanMeasure from domain.modelling.recommendation import Cost from domain.modelling.scoring.scoring import MeasureImpact -from infrastructure.postgres.modelling import PlanRow, RecommendationRow +from infrastructure.postgres.modelling import PlanModel, RecommendationModel from repositories.plan.plan_postgres_repository import PlanPostgresRepository @@ -64,10 +64,10 @@ def test_save_persists_plan_and_its_measures_with_tonnes_and_band( # Assert with Session(db_engine) as session: - plan_row = session.get(PlanRow, plan_id) + plan_row = session.get(PlanModel, plan_id) rec_rows = session.exec( - select(RecommendationRow).where( - col(RecommendationRow.plan_id) == plan_id + select(RecommendationModel).where( + col(RecommendationModel.plan_id) == plan_id ) ).all() @@ -139,7 +139,7 @@ def test_save_persists_null_per_measure_savings_when_unbilled( # Assert — the savings columns persist as NULL (ADR-0014 amendment) with Session(db_engine) as session: rec_rows = session.exec( - select(RecommendationRow).where(col(RecommendationRow.plan_id) == plan_id) + select(RecommendationModel).where(col(RecommendationModel.plan_id) == plan_id) ).all() assert len(rec_rows) == 1 assert rec_rows[0].kwh_savings is None @@ -166,10 +166,10 @@ def test_save_is_idempotent_on_rerun_for_the_same_property_and_scenario( # Assert — replaced, not duplicated (cascade removed the old measures) with Session(db_engine) as session: plan_rows = session.exec( - select(PlanRow).where(col(PlanRow.property_id) == 10) + select(PlanModel).where(col(PlanModel.property_id) == 10) ).all() rec_rows = session.exec( - select(RecommendationRow).where(col(RecommendationRow.property_id) == 10) + select(RecommendationModel).where(col(RecommendationModel.property_id) == 10) ).all() assert len(plan_rows) == 1