from __future__ import annotations from sqlmodel import Session, col, select from domain.property.properties import Properties from domain.property.property import Property, PropertyIdentity from infrastructure.postgres.property_table import PropertyRow from repositories.epc.epc_repository import EpcRepository from repositories.property.property_repository import PropertyRepository class PropertyPostgresRepository(PropertyRepository): """Hydrates the Property aggregate from the FE-owned ``property`` row plus the EPC slice (via an injected `EpcRepository`). Reads only from repos — no external IO — so a hydrated Property is a pure function of repository state (ADR-0003). """ def __init__(self, session: Session, epc_repo: EpcRepository) -> None: self._session = session self._epc_repo = epc_repo def get(self, property_id: int) -> Property: row = self._session.get(PropertyRow, property_id) if row is None: raise ValueError(f"property {property_id} not found") identity = PropertyIdentity( portfolio_id=row.portfolio_id, postcode=row.postcode, address=row.address, uprn=row.uprn, landlord_property_id=row.landlord_property_id, ) return Property( identity=identity, epc=self._epc_repo.get_for_property(property_id), ) def get_many(self, property_ids: list[int]) -> Properties: if not property_ids: return Properties([]) rows = self._session.exec( select(PropertyRow).where(col(PropertyRow.id).in_(property_ids)) ).all() row_by_id = {row.id: row for row in rows} epcs = self._epc_repo.get_for_properties(property_ids) items: list[Property] = [] for property_id in property_ids: row = row_by_id.get(property_id) if row is None: raise ValueError(f"property {property_id} not found") items.append( Property( identity=PropertyIdentity( portfolio_id=row.portfolio_id, postcode=row.postcode, address=row.address, uprn=row.uprn, landlord_property_id=row.landlord_property_id, ), epc=epcs.get(property_id), ) ) return Properties(items)