Model/domain/property/properties.py
Khalim Conn-Kowlessar 92de07efba feat(property): Property aggregate + PropertyRepository (#1132)
Add the Ara modelling aggregate root (ADR-0002): domain/property/ with
PropertyIdentity, SiteNotes, Property, Properties. Property.source_path
implements the two disjoint source paths + Recency Tie-Break (ADR-0001;
survey wins on an equal date); effective_epc resolves to the surveyed data
(Site Notes path) or the public EPC (epc_with_overlay path — Landlord
Overrides overlay is a later slice). Pure dataclasses, no infrastructure imports.

PropertyRepository port + PropertyPostgresRepository hydrate the aggregate
whole from a defensive view of the FE-owned 'property' table (identity columns)
plus the EPC slice via EpcRepository.get_for_property. Reads only from repos
(ADR-0003). 8 domain + 1 hydration test; pyright strict clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 19:39:54 +00:00

25 lines
740 B
Python

from __future__ import annotations
from collections.abc import Callable, Iterator
from dataclasses import dataclass
from domain.property.property import Property
@dataclass
class Properties:
"""A first-class collection of Property objects — the unit of bulk operation
in services (CONTEXT.md: Properties). Services take and return `Properties`
rather than bare lists so batch operations read clearly.
"""
items: list[Property]
def __iter__(self) -> Iterator[Property]:
return iter(self.items)
def __len__(self) -> int:
return len(self.items)
def filter(self, predicate: Callable[[Property], bool]) -> "Properties":
return Properties([p for p in self.items if predicate(p)])