Skip to content

Commit 612351a

Browse files
fix(macros): extract the audit subquery table from its FROM clause
Signed-off-by: sravankumarkunadi <sravankumarkunadi@users.noreply.github.com>
1 parent 16aca69 commit 612351a

2 files changed

Lines changed: 40 additions & 7 deletions

File tree

sqlmesh/core/macros.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,15 +1379,17 @@ def resolve_template(
13791379
"""
13801380
Generates either a String literal or an exp.Table representing a physical table location, based on rendering the provided template String literal.
13811381
1382-
Note: It relies on the @this_model variable being available in the evaluation context (@this_model resolves to an exp.Table object
1383-
representing the current physical table).
1382+
Note: It relies on the @this_model variable being available in the evaluation context. @this_model usually resolves to an
1383+
exp.Table object representing the current physical table, but in an audit on a model with a time column it resolves to a
1384+
subquery that selects from that table and filters it down to the audited time range. In that case the placeholders below
1385+
are resolved against the physical table the subquery selects from.
13841386
Therefore, the @resolve_template macro must be used at creation or evaluation time and not at load time.
13851387
13861388
Args:
13871389
template: Template string literal. Can contain the following placeholders:
1388-
@{catalog_name} -> replaced with the catalog of the exp.Table returned from @this_model
1389-
@{schema_name} -> replaced with the schema of the exp.Table returned from @this_model
1390-
@{table_name} -> replaced with the name of the exp.Table returned from @this_model
1390+
@{catalog_name} -> replaced with the catalog of the physical table @this_model refers to
1391+
@{schema_name} -> replaced with the schema of the physical table @this_model refers to
1392+
@{table_name} -> replaced with the name of the physical table @this_model refers to
13911393
mode: What to return.
13921394
'literal' -> return an exp.Literal string
13931395
'table' -> return an exp.Table
@@ -1400,13 +1402,24 @@ def resolve_template(
14001402
>>> evaluator.locals.update({"this_model": exp.to_table("test_catalog.sqlmesh__test.test__test_model__2517971505")})
14011403
>>> evaluator.transform(parse_one(sql)).sql()
14021404
"'s3://data-bucket/prod/test_catalog/sqlmesh__test/test__test_model__2517971505'"
1405+
1406+
The same template resolves to the same location when @this_model is the time-filtered
1407+
subquery that audits on models with a time column receive:
1408+
1409+
>>> table = exp.to_table("test_catalog.sqlmesh__test.test__test_model__2517971505")
1410+
>>> subquery = exp.select("*").from_(table).where(exp.column("ds").eq("2020-01-01")).subquery()
1411+
>>> evaluator.locals.update({"this_model": subquery})
1412+
>>> evaluator.transform(parse_one(sql)).sql()
1413+
"'s3://data-bucket/prod/test_catalog/sqlmesh__test/test__test_model__2517971505'"
14031414
"""
14041415
if "this_model" in evaluator.locals:
14051416
this_model_expr = evaluator.locals["this_model"]
14061417
if isinstance(this_model_expr, exp.Subquery):
14071418
# Audits on models with a time column render @this_model as a subquery that filters the
1408-
# physical table on the audited time range, so extract the table it selects from
1409-
this_model_expr = this_model_expr.find(exp.Table) or this_model_expr
1419+
# physical table on the audited time range, so resolve against the table it selects from
1420+
from_ = this_model_expr.unnest().args.get("from_")
1421+
if from_ is not None and isinstance(from_.this, exp.Table):
1422+
this_model_expr = from_.this
14101423

14111424
this_model = exp.to_table(this_model_expr, dialect=evaluator.dialect)
14121425
template_str: str = template.this

tests/core/test_macros.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,26 @@ def test_resolve_template_subquery():
11601160
== 'SELECT * FROM "test_catalog"."sqlmesh__test"."test__test_model__2517971505$partitions"'
11611161
)
11621162

1163+
# the table is taken from the subquery's FROM clause, so other tables referenced elsewhere
1164+
# in it (here, in a WHERE subquery) can't be picked up instead
1165+
evaluator.locals.update(
1166+
{
1167+
"this_model": exp.select("*")
1168+
.from_(exp.to_table("test_catalog.sqlmesh__test.test__test_model__2517971505"))
1169+
.where(
1170+
exp.column("ds").isin(
1171+
query=exp.select("ds").from_(exp.to_table("other_catalog.other_schema.other"))
1172+
)
1173+
)
1174+
.subquery()
1175+
}
1176+
)
1177+
1178+
assert (
1179+
evaluator.transform(parsed_sql).sql(identify=True)
1180+
== 'SELECT * FROM "test_catalog"."sqlmesh__test"."test__test_model__2517971505$partitions"'
1181+
)
1182+
11631183

11641184
def test_macro_with_spaces():
11651185
evaluator = MacroEvaluator()

0 commit comments

Comments
 (0)