From e778d1fb973d56236b880e37ab95632dc08d3614 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 3 Jun 2026 11:53:34 +0000 Subject: [PATCH] feat(modelling): expose scenario/product/plan repos on the UnitOfWork (#1157) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Slice 4a. The Modelling stage reads the Scenario + Product catalogue and writes the Plan + its Plan Measures on one session, committed once (ADR-0012/0017). Adds uow.scenario / uow.product / uow.plan to the UnitOfWork port and constructs them in PostgresUnitOfWork.__enter__. Additive — existing stages and the bare-stub Modelling wiring are unaffected. Wiring test asserts the unit exposes the three ports. Co-Authored-By: Claude Opus 4.8 --- repositories/postgres_unit_of_work.py | 10 ++++++++++ repositories/unit_of_work.py | 8 ++++++++ tests/repositories/test_unit_of_work.py | 15 +++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/repositories/postgres_unit_of_work.py b/repositories/postgres_unit_of_work.py index da91604b..3a10b087 100644 --- a/repositories/postgres_unit_of_work.py +++ b/repositories/postgres_unit_of_work.py @@ -10,9 +10,16 @@ from repositories.property_baseline.property_baseline_postgres_repository import PropertyBaselinePostgresRepository, ) from repositories.epc.epc_postgres_repository import EpcPostgresRepository +from repositories.plan.plan_postgres_repository import PlanPostgresRepository +from repositories.product.product_postgres_repository import ( + ProductPostgresRepository, +) from repositories.property.property_postgres_repository import ( PropertyPostgresRepository, ) +from repositories.scenario.scenario_postgres_repository import ( + ScenarioPostgresRepository, +) from repositories.solar.solar_postgres_repository import SolarPostgresRepository from repositories.unit_of_work import UnitOfWork @@ -36,6 +43,9 @@ class PostgresUnitOfWork(UnitOfWork): self.epc = epc_repo self.solar = SolarPostgresRepository(self._session) self.property_baseline = PropertyBaselinePostgresRepository(self._session) + self.scenario = ScenarioPostgresRepository(self._session) + self.product = ProductPostgresRepository(self._session) + self.plan = PlanPostgresRepository(self._session) return self def __exit__( diff --git a/repositories/unit_of_work.py b/repositories/unit_of_work.py index cb1cc1d8..a8a27cdb 100644 --- a/repositories/unit_of_work.py +++ b/repositories/unit_of_work.py @@ -6,7 +6,10 @@ from typing import Optional from repositories.property_baseline.property_baseline_repository import PropertyBaselineRepository from repositories.epc.epc_repository import EpcRepository +from repositories.plan.plan_repository import PlanRepository +from repositories.product.product_repository import ProductRepository from repositories.property.property_repository import PropertyRepository +from repositories.scenario.scenario_repository import ScenarioRepository from repositories.solar.solar_repository import SolarRepository @@ -26,6 +29,11 @@ class UnitOfWork(ABC): epc: EpcRepository solar: SolarRepository property_baseline: PropertyBaselineRepository + # Modelling-stage repos (ADR-0017): read the Scenario, read the Product + # catalogue, write the Plan + its Plan Measures — all on the one session. + scenario: ScenarioRepository + product: ProductRepository + plan: PlanRepository @abstractmethod def commit(self) -> None: ... diff --git a/tests/repositories/test_unit_of_work.py b/tests/repositories/test_unit_of_work.py index 03018562..e3ee2f73 100644 --- a/tests/repositories/test_unit_of_work.py +++ b/tests/repositories/test_unit_of_work.py @@ -9,7 +9,10 @@ from sqlmodel import Session from datatypes.epc.domain.epc import Epc from domain.property_baseline.property_baseline_performance import PropertyBaselinePerformance from domain.property_baseline.performance import Performance +from repositories.plan.plan_repository import PlanRepository from repositories.postgres_unit_of_work import PostgresUnitOfWork +from repositories.product.product_repository import ProductRepository +from repositories.scenario.scenario_repository import ScenarioRepository def _session_factory(db_engine: Engine) -> Callable[[], Session]: @@ -60,6 +63,18 @@ def test_an_exception_in_the_block_rolls_the_batch_back(db_engine: Engine) -> No assert uow.property_baseline.get_for_property(10) is None +def test_unit_exposes_the_modelling_repos_bound_to_its_session( + db_engine: Engine, +) -> None: + # Arrange / Act + with PostgresUnitOfWork(_session_factory(db_engine)) as uow: + # Assert — the Modelling stage reads Scenario + Product and writes Plan + # through the same unit (ADR-0017). + assert isinstance(uow.scenario, ScenarioRepository) + assert isinstance(uow.product, ProductRepository) + assert isinstance(uow.plan, PlanRepository) + + def test_leaving_the_block_without_commit_persists_nothing(db_engine: Engine) -> None: # Arrange new_unit = lambda: PostgresUnitOfWork(_session_factory(db_engine))