move landlord overrides

This commit is contained in:
Jun-te Kim 2026-06-01 15:46:46 +00:00
parent 8a9d14a45c
commit 5470fa1d93
6 changed files with 21 additions and 15 deletions

View file

@ -16,14 +16,14 @@ from domain.epc.wall_type_construction_dates import (
)
from infrastructure.chatgpt.chatgpt import ChatGPT
from infrastructure.chatgpt.chatgpt_column_classifier import ChatGptColumnClassifier
from infrastructure.landlord_overrides.landlord_overrides_postgres_repository import (
LandlordOverridesRepository,
)
from infrastructure.postgres.config import PostgresConfig
from infrastructure.postgres.engine import commit_scope, make_engine, make_session
from infrastructure.postgres.landlord_built_form_type_override_table import (
LandlordBuiltFormTypeOverrideRow,
)
from infrastructure.postgres.landlord_overrides_postgres_repository import (
LandlordOverridesRepository,
)
from infrastructure.postgres.landlord_property_type_override_table import (
LandlordPropertyTypeOverrideRow,
)

View file

@ -53,24 +53,26 @@ The `WHERE existing.source = 'classifier'` guard is load-bearing: it lets the cl
This ADR also fixes a placement convention for Postgres adapters going forward. The codebase currently has the ChatGPT classifier split cleanly along DDD lines — port in `domain/`, adapter in `infrastructure/chatgpt/` — but the `tasks` Postgres adapter does not follow the same shape: its concrete class lives in `repositories/tasks/`, not `infrastructure/postgres/`.
The convention going forward is:
The convention going forward separates the persistence *behaviour* (grouped by aggregate) from the schema *mirrors* (grouped by technology, since they share pgEnums and engine metadata):
- **Port (protocol / abstract base):** `repositories/<aggregate>/<thing>_repository.py`
- **Postgres adapter (concrete):** `infrastructure/postgres/<thing>_postgres_repository.py`
- **SQLModel row class:** `infrastructure/postgres/<thing>_table.py`
- **Postgres repository adapter (concrete):** `infrastructure/<aggregate>/<aggregate>_postgres_repository.py`
- **SQLModel row class (`table=True` schema mirror):** `infrastructure/postgres/<thing>_table.py`
The `LandlordOverridesRepository` adapter follows this convention: the concrete class lives at `infrastructure/postgres/landlord_overrides_postgres_repository.py`, with one `…_table.py` per category alongside it. The `…Row` classes stay one-per-table — each mirrors a genuinely distinct Drizzle table and `value` pgEnum, so they are schema mirrors, not duplicated logic.
The `LandlordOverridesRepository` adapter follows this convention: the concrete class — the aggregate's "talker" to Postgres — lives at `infrastructure/landlord_overrides/landlord_overrides_postgres_repository.py`, while the per-category `…Row` classes stay in `infrastructure/postgres/`. The `…Row` classes are one-per-table — each mirrors a genuinely distinct Drizzle table and `value` pgEnum, and they share the single `override_source` pgEnum instance, so they belong together in the Postgres technology bucket as schema mirrors, not duplicated logic.
(This refines the placement first sketched in this ADR, which put the adapter in `infrastructure/postgres/` alongside the row classes. The adapter holds no schema — only the write path — so it groups by aggregate; only the `table=True` mirrors stay tech-bucketed.)
**Existing outliers to relocate in a follow-up:**
- `repositories/tasks/task_postgres_repository.py``infrastructure/postgres/task_postgres_repository.py`
- `repositories/tasks/subtask_postgres_repository.py``infrastructure/postgres/subtask_postgres_repository.py`
- `repositories/tasks/task_postgres_repository.py``infrastructure/tasks/task_postgres_repository.py`
- `repositories/tasks/subtask_postgres_repository.py``infrastructure/tasks/subtask_postgres_repository.py`
Both moves are mechanical (import-path updates only). They are intentionally out of scope for the present PR.
(Their `task_table.py` / `subtask_table.py` schema mirrors already sit correctly in `infrastructure/postgres/`.) Both moves are mechanical (import-path updates only). They are intentionally out of scope for the present PR.
## Out of scope (deferred to follow-up work)
- Relocating `task_postgres_repository.py` and `subtask_postgres_repository.py` into `infrastructure/postgres/` per the convention above.
- Relocating `task_postgres_repository.py` and `subtask_postgres_repository.py` into `infrastructure/tasks/` per the convention above.
- ~~Extracting a shared upsert helper / base class once a third `landlord_*_overrides` column lands — until then the per-category adapters' 95%-identical bodies are kept side-by-side for direct comparison.~~ **Done.** The per-category adapter bodies were byte-identical (varying only in their row class), so they were consolidated into one generic `LandlordOverridesRepository[E]` parameterised by row class rather than waiting for a third column.
- Switching `applications/landlord_description_overrides/handler.py` to acquire its `Session` via a `@subtask_handler()`-style decorator instead of building its own engine.
- A cross-repo PR amending ADR-0002 to point at this ADR.

View file

@ -11,7 +11,11 @@ category enum ``E`` and pass the matching ``…Row`` class:
LandlordOverridesRepository[PropertyType](session, LandlordPropertyTypeOverrideRow)
Per ADR-0003 §File layout, Postgres adapters live in ``infrastructure/postgres/``.
This adapter -- the aggregate's "talker" to Postgres -- lives under
``infrastructure/landlord_overrides/``, grouped by aggregate. The ``table=True``
SQLModel row classes it writes through stay in ``infrastructure/postgres/`` as
schema mirrors (they share the ``override_source`` pgEnum and register against
the same engine metadata). See ADR-0003 §File layout.
"""
from __future__ import annotations

View file

@ -16,7 +16,7 @@ class LandlordOverrideRepository(ABC, Generic[E]):
interface and never names a concrete table.
A single concrete adapter,
``infrastructure/postgres/landlord_overrides_postgres_repository.LandlordOverridesRepository``,
``infrastructure/landlord_overrides/landlord_overrides_postgres_repository.LandlordOverridesRepository``,
serves every category (see ADR-0003) -- it is parameterised by the
SQLModel row class for the target table.
"""

View file

@ -27,10 +27,10 @@ from sqlmodel import Session, SQLModel, select
from domain.epc.property_type import PropertyType
from domain.epc.wall_type import WallType
from infrastructure.postgres.landlord_override_enums import OverrideSource
from infrastructure.postgres.landlord_overrides_postgres_repository import (
from infrastructure.landlord_overrides.landlord_overrides_postgres_repository import (
LandlordOverridesRepository,
)
from infrastructure.postgres.landlord_override_enums import OverrideSource
from infrastructure.postgres.landlord_property_type_override_table import (
LandlordPropertyTypeOverrideRow,
)