Files
nvi/api/composer/encodings.py

43 lines
1.8 KiB
Python

"""Storage-encoding library — how a column's raw storage maps to a value the
composer can compare against.
Some warehouses store logical types in surprising physical encodings (BIRD
ships YYMMDD-encoded *integer* "dates", for instance). The composer needs a way
to coerce such a column to a comparable value without baking any one dataset's
quirk into the generic SQL builder.
The model is **defaults with override**:
- `DEFAULT_ENCODINGS` ships the generic, reusable patterns here — keyed by the
`Column.semantic_type` a dataset declares in `schema_docs.yaml`.
- A dataset may add a novel encoding or override a default via the optional
`encodings:` section of its `schema_docs.yaml` (carried onto
`Recon.encodings`). The dataset always wins.
Each encoding is plain data: a map of role → SQL template with a `{col}`
placeholder for the (already-qualified) column reference. Today the only role
is `as_date` — the expression that yields a DATE for `date_range` filters; new
roles are additive.
"""
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from api.recon.types import Recon
DEFAULT_ENCODINGS: dict[str, dict[str, str]] = {
# BIRD-style YYMMDD stored as a 6-digit integer → real DATE.
"date_yymmdd": {"as_date": "TO_DATE(LPAD({col}::text, 6, '0'), 'YYMMDD')"},
# Add further reusable patterns here (e.g. epoch_seconds, julian_day) as
# they recur across datasets — never a single dataset's one-off quirk.
}
def effective_encodings(recon: "Recon") -> dict[str, dict[str, str]]:
"""The encoding map the composer should use for `recon`: built-in defaults
overlaid with the dataset's own `encodings` (dataset entries win)."""
return {**DEFAULT_ENCODINGS, **(recon.encodings or {})}