mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Re-runs of a First Run batch re-save a property's data; that must replace, not duplicate (ADR-0012 idempotent batch writes). - `EpcPostgresRepository.save` deletes the property's existing EPC graph (parent + all child tables, floor-dims via their building parts) before inserting, when a `property_id` is given. Anonymous saves still insert. - `BaselinePostgresRepository.save` deletes the existing row for the `property_id` before inserting — no more unique-constraint violation on re-save; also what the re-score-on-override path needs. - Solar already upserts, so it's unchanged. The #1129 round-trip fidelity test stays green (delete-first is a no-op on a first save). 2 new tests (re-save replaces, not duplicates). pyright strict clean; AAA. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
52 lines
1.8 KiB
Python
52 lines
1.8 KiB
Python
"""A re-run of First Run re-saves a property's EPC; that must replace the prior
|
|
row, not duplicate it (ADR-0012 idempotent batch writes, #1138)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import dataclasses
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from sqlalchemy import Engine
|
|
from sqlmodel import Session, select
|
|
|
|
from datatypes.epc.domain.epc_property_data import EpcPropertyData
|
|
from datatypes.epc.domain.mapper import EpcPropertyDataMapper
|
|
from infrastructure.postgres.epc_property_table import EpcPropertyModel
|
|
from repositories.epc.epc_postgres_repository import EpcPostgresRepository
|
|
|
|
_JSON_SAMPLES = Path(__file__).resolve().parents[3] / "backend/epc_api/json_samples"
|
|
|
|
|
|
def _load_epc() -> EpcPropertyData:
|
|
raw: dict[str, Any] = json.loads(
|
|
(_JSON_SAMPLES / "RdSAP-Schema-21.0.0" / "epc.json").read_text()
|
|
)
|
|
return EpcPropertyDataMapper.from_api_response(raw)
|
|
|
|
|
|
def test_resaving_an_epc_for_a_property_replaces_rather_than_duplicates(
|
|
db_engine: Engine,
|
|
) -> None:
|
|
# Arrange — same property re-ingested with a changed field.
|
|
original = _load_epc()
|
|
updated = dataclasses.replace(original, status="re-run-sentinel")
|
|
|
|
# Act — save twice for the same property_id (a re-run).
|
|
with Session(db_engine) as session:
|
|
repo = EpcPostgresRepository(session)
|
|
repo.save(original, property_id=10)
|
|
repo.save(updated, property_id=10)
|
|
session.commit()
|
|
|
|
# Assert — exactly one EPC row for the property, holding the latest data.
|
|
with Session(db_engine) as session:
|
|
rows = session.exec(
|
|
select(EpcPropertyModel).where(EpcPropertyModel.property_id == 10)
|
|
).all()
|
|
reloaded = EpcPostgresRepository(session).get_for_property(10)
|
|
|
|
assert len(rows) == 1
|
|
assert reloaded is not None
|
|
assert reloaded.status == "re-run-sentinel"
|