"""双时态事实仓储:写入与"按历史时点回放"查询。 对应需求 R3 / ADR-0002: - 业务有效期 valid_from/valid_to(应用时间) - 系统记录期 system_from/system_to(事务时间) 回放 = 给定 (as_of_valid, as_of_system) 在两条时间线上各取"包含该时点"的记录。 """ from __future__ import annotations import datetime as dt import uuid from sqlalchemy import or_ from sqlalchemy.orm import Session from app.datahub.models import BitemporalFact def record_fact( session: Session, entity_id: uuid.UUID, attr_name: str, attr_value: dict, valid_from: dt.datetime, valid_to: dt.datetime | None = None, data_version_id: uuid.UUID | None = None, ) -> BitemporalFact: """记录一条双时态事实(system_from 自动取当前事务时间)。""" fact = BitemporalFact( entity_id=entity_id, attr_name=attr_name, attr_value=attr_value, valid_from=valid_from, valid_to=valid_to, data_version_id=data_version_id, ) session.add(fact) session.flush() return fact def as_of( session: Session, entity_id: uuid.UUID, attr_name: str, as_of_valid: dt.datetime, as_of_system: dt.datetime | None = None, ) -> BitemporalFact | None: """回放:返回在给定业务时点且按给定系统时点可见的事实。 - 业务时间线:valid_from <= as_of_valid < valid_to(或为空表示至今) - 系统时间线:system_from <= as_of_system < system_to(或为空表示当前可见) """ as_of_system = as_of_system or dt.datetime.now(dt.UTC) q = ( session.query(BitemporalFact) .filter(BitemporalFact.entity_id == entity_id) .filter(BitemporalFact.attr_name == attr_name) .filter(BitemporalFact.valid_from <= as_of_valid) .filter( or_(BitemporalFact.valid_to.is_(None), BitemporalFact.valid_to > as_of_valid) ) .filter(BitemporalFact.system_from <= as_of_system) .filter( or_( BitemporalFact.system_to.is_(None), BitemporalFact.system_to > as_of_system, ) ) .order_by(BitemporalFact.system_from.desc()) ) return q.first() def close_fact( session: Session, fact: BitemporalFact, system_to: dt.datetime | None = None ) -> None: """逻辑关闭一条事实的系统可见期(用于更正/失效,而非物理删除)。""" fact.system_to = system_to or dt.datetime.now(dt.UTC) session.add(fact) session.flush()