Model/repositories/property/property_repository.py
2026-06-05 12:18:13 +00:00

67 lines
2.6 KiB
Python

from __future__ import annotations
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Optional
from domain.property.properties import Properties
from domain.property.property import Property
@dataclass(frozen=True)
class PropertyIdentityInsert:
"""One row inserted into the FE-owned ``property`` table at Finalise (ADR-0013).
Mirrors the exact column set today's Next.js ``/finalize`` writes: nine fields
plus ``creation_status='READY'``. ``address``/``postcode`` are the resolved
(matched ?? user-inputted) values and may be ``None``.
"""
portfolio_id: int
uprn: Optional[int]
landlord_property_id: Optional[str]
address: Optional[str]
postcode: Optional[str]
user_inputted_address: Optional[str]
user_inputted_postcode: Optional[str]
lexiscore: Optional[float]
creation_status: str = "READY"
class PropertyRepository(ABC):
"""Reads and writes the FE-owned ``property`` table.
Reads hydrate the Property aggregate whole — never half a Property — from the
identity row plus its source-data slices (EPC today; Site Notes / enrichments
as later slices land) (ADR-0002, ADR-0012). Writes bulk-insert identity rows at
Finalise (ADR-0013). One repository per aggregate.
"""
@abstractmethod
def get(self, property_id: int) -> Property: ...
@abstractmethod
def get_many(self, property_ids: list[int]) -> Properties:
"""Load a batch of Properties whole, in a handful of per-table queries
rather than one round-trip per property (ADR-0012). Order follows the
input ids."""
...
@abstractmethod
def insert_all(self, rows: list[PropertyIdentityInsert]) -> int:
"""Bulk-insert identity rows, skipping any whose ``(portfolio_id, uprn)``
already exists (the FE partial unique index, ``WHERE uprn IS NOT NULL``).
Rows with no UPRN are always inserted. Returns the number actually
inserted; an empty list is a no-op returning 0 (ADR-0013)."""
...
@abstractmethod
def ids_by_uprn(self, portfolio_id: int, uprns: list[int]) -> dict[int, int]:
"""Map each given UPRN to its ``property.id`` within a portfolio.
Used by the finaliser to attach ``property_overrides`` to UPRN-matched
rows (ADR-0006) without a query per row — covers both rows just inserted
and pre-existing ones (re-found by ``(portfolio_id, uprn)``). UPRNs with
no matching property are simply absent from the result; an empty input is
a no-op returning ``{}``."""
...