31 lines
1.2 KiB
Python
31 lines
1.2 KiB
Python
"""Metric-fragment qualification.
|
|
|
|
Metric expressions in `metrics.yaml` are written *unaliased* — e.g.
|
|
`AVG(CASE WHEN status = 'B' THEN 1.0 WHEN status = 'A' THEN 0.0 END)`, `A13`,
|
|
`SUM(amount)`. Before such a fragment can sit in a multi-table query it has to
|
|
be bound to the metric's own table alias, so the composer can introduce other
|
|
tables via joins without ambiguity.
|
|
|
|
We parse the fragment with sqlglot and inject the alias as the table qualifier
|
|
on every bare column reference, returning the resulting expression node (not a
|
|
string) so it splices directly into the query tree the composer assembles.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sqlglot
|
|
from sqlglot import exp
|
|
|
|
|
|
def qualify_metric_expr(sql_fragment: str, table_alias: str) -> exp.Expression:
|
|
"""Parse `sql_fragment` and qualify its bare column refs to `table_alias`.
|
|
|
|
Used for both the metric's SELECT expression and its optional WHERE filter
|
|
(both are written as bare expressions over the metric's table)."""
|
|
tree = sqlglot.parse_one(sql_fragment, dialect="postgres")
|
|
for col in tree.find_all(exp.Column):
|
|
if col.table:
|
|
continue
|
|
col.set("table", exp.Identifier(this=table_alias, quoted=True))
|
|
return tree
|