Model/infrastructure/postgres/property_details_spatial_table.py
Khalim Conn-Kowlessar a1c60d2fba feat(spatial): per-UPRN cache repo for the OS spatial reference
Slice 3c.2. The OS Open-UPRN reference set is too large to host in Postgres, so
it lives in S3 and is cached per-UPRN in the existing `property_details_spatial`
table (ADR-0020). `PropertyDetailsSpatialRow` mirrors that table (uprn unique);
`SpatialRepository` / `SpatialPostgresRepository` upsert one shared row per UPRN
and read the planning protections back by UPRN (a null flag reads as
unrestricted; absent UPRNs are omitted so the caller defaults them).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 17:15:51 +00:00

29 lines
1.3 KiB
Python

from __future__ import annotations
from typing import ClassVar, Optional
from sqlmodel import Field, SQLModel
class PropertyDetailsSpatialRow(SQLModel, table=True):
"""Per-UPRN cache of the Ordnance Survey spatial reference data.
The OS Open-UPRN set is tens of millions of rows — too large for Postgres —
so Ingestion resolves it from S3 and writes the row it used here, keyed by
UPRN (one shared row per UPRN, not per Property). The front-end reads the
planning flags off this table to show why a Property did or did not get a
given measure; Modelling hydrates them onto the Property (ADR-0020). Coords
are retained for parity with the legacy ``property_details_spatial`` shape.
"""
__tablename__: ClassVar[str] = "property_details_spatial" # pyright: ignore[reportIncompatibleVariableOverride]
id: Optional[int] = Field(default=None, primary_key=True)
uprn: int = Field(index=True, unique=True)
x_coordinate: Optional[float] = Field(default=None)
y_coordinate: Optional[float] = Field(default=None)
latitude: Optional[float] = Field(default=None)
longitude: Optional[float] = Field(default=None)
conservation_status: Optional[bool] = Field(default=None)
is_listed_building: Optional[bool] = Field(default=None)
is_heritage_building: Optional[bool] = Field(default=None)