Model/repositories/plan/plan_repository.py
Daniel Roth 9c6b477025 Batch plan saves reduce RDS CPU during bulk modelling runs 🟥
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 15:04:54 +00:00

56 lines
1.9 KiB
Python

from __future__ import annotations
from abc import ABC, abstractmethod
from dataclasses import dataclass
from domain.modelling.plan import Plan
@dataclass(frozen=True)
class PlanSaveRequest:
"""Bundles the five fields the plan repository needs to persist one Plan.
Mirrors ``EpcSaveRequest`` in shape — used by ``PlanRepository.save_batch()``
to accumulate write intent before the batch is flushed in one Unit of Work."""
plan: Plan
property_id: int
scenario_id: int
portfolio_id: int
is_default: bool
class PlanRepository(ABC):
"""Persists a Plan (and its Plan Measures) for a Property + Scenario.
A re-run INSERTs a fresh Plan and keeps the prior one as history rather than
deleting it. When the new Plan is the default, prior default Plans for the
same (Property, Scenario) are demoted to `is_default=False`, so the current
Plan is the one with `is_default=True` (ADR-0012 / ADR-0017). `portfolio_id`
and `is_default` are supplied by the orchestrator (the former from the
trigger, the latter from the Scenario).
"""
@abstractmethod
def save(
self,
plan: Plan,
*,
property_id: int,
scenario_id: int,
portfolio_id: int,
is_default: bool,
) -> int:
"""Persist ``plan`` and return its Plan id. Keeps prior Plans for
``(property_id, scenario_id)`` as history; when ``is_default`` is True,
demotes those prior Plans to ``is_default=False``."""
...
@abstractmethod
def save_batch(self, requests: list[PlanSaveRequest]) -> list[int]:
"""Persist a batch of Plans in three statements regardless of batch size.
Returns one plan id per request in input order. Fires a single demote
UPDATE only when at least one request has ``is_default=True``. Keeps
prior Plans as history (ADR-0017)."""
...