Source code for loom.etl.backends._historify._common

"""Common helpers shared by all Historify backends."""

from __future__ import annotations

from datetime import timedelta
from typing import TYPE_CHECKING, Any, cast

if TYPE_CHECKING:
    from _typeshed import SupportsRichComparison

from loom.etl.declarative.expr._params import ParamExpr
from loom.etl.declarative.target._history import (
    HistorifyInputMode,
    HistorifyRepairReport,
    HistorifySpec,
    HistoryDateType,
)

_DATE_DELTA = timedelta(days=1)
_TS_DELTA = timedelta(microseconds=1)


[docs] def resolve_effective_date(spec: HistorifySpec, params_instance: object) -> Any: """Resolve effective date to a scalar (SNAPSHOT) or column name (LOG).""" if spec.mode is HistorifyInputMode.LOG: return spec.effective_date if isinstance(spec.effective_date, ParamExpr): return eval_param_expr(spec.effective_date, params_instance) return spec.effective_date
[docs] def eval_param_expr(expr: ParamExpr, params_instance: object) -> Any: """Walk the ParamExpr attribute path and return the resolved value.""" value: Any = params_instance for attr in expr.path: value = getattr(value, attr) return value
[docs] def resolve_track_cols(spec: HistorifySpec, frame_cols: list[str]) -> tuple[str, ...]: """Return tracked columns — explicit or all non-key, non-history columns.""" if spec.track is not None: return spec.track excluded = set(spec.keys) | {spec.valid_from, spec.valid_to} return tuple(c for c in frame_cols if c not in excluded)
[docs] def prev_period_value(eff_date: Any, spec: HistorifySpec) -> Any: """Return one unit before eff_date (one day or one microsecond).""" delta = _DATE_DELTA if spec.date_type is HistoryDateType.DATE else _TS_DELTA return eff_date - delta
def build_rewind_report( future_rows: list[tuple[object, ...]], eff_date: object, ) -> HistorifyRepairReport | None: """Build a repair report from collected ``keys + valid_from`` tuples. Args: future_rows: One tuple per existing row with ``valid_from`` strictly after ``eff_date``, shaped as ``(*entity key values, valid_from)``. eff_date: Effective date of the temporal rerun. Returns: The repair report, or ``None`` when no future rows exist. """ if not future_rows: return None date_values = cast("set[SupportsRichComparison]", {row[-1] for row in future_rows}) dates = tuple(sorted(date_values)) warning = ( f"Temporal rerun at {eff_date} rewound {len(future_rows)} future row(s) " f"with valid_from between {dates[0]} and {dates[-1]}; " "downstream loads for those dates require a rerun." ) return HistorifyRepairReport( affected_keys=frozenset(row[:-1] for row in future_rows), dates_requiring_rerun=dates, warnings=(warning,), )