43 lines
1.8 KiB
Python
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 {})}
|