Files
InternalAuditInterprise/backend/app/datahub/bitemporal_repo.py
T
2026-06-16 00:38:57 +08:00

84 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""双时态事实仓储:写入与"按历史时点回放"查询。
对应需求 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()