Skip to content

Commit 5e9f405

Browse files
authoredMar 14, 2025
Feat: support dynamic blueprinting (#3997)
1 parent 54a2b42 commit 5e9f405

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed
 

‎sqlmesh/core/model/definition.py

+17-1
Original file line numberDiff line numberDiff line change
@@ -1928,7 +1928,7 @@ def load_sql_based_models(
19281928
**loader_kwargs: t.Any,
19291929
) -> t.List[Model]:
19301930
gateway: t.Optional[exp.Expression] = None
1931-
blueprints: t.Optional[t.List[t.Optional[exp.Expression]]] = None
1931+
blueprints: t.Optional[exp.Expression] = None
19321932

19331933
model_meta = seq_get(expressions, 0)
19341934
for prop in (isinstance(model_meta, d.Model) and model_meta.expressions) or []:
@@ -1937,6 +1937,22 @@ def load_sql_based_models(
19371937
elif prop.name == "blueprints":
19381938
blueprints = prop.args["value"]
19391939

1940+
if isinstance(blueprints, d.MacroFunc):
1941+
rendered_blueprints = render_expression(
1942+
expression=blueprints,
1943+
module_path=module_path,
1944+
macros=loader_kwargs.get("macros"),
1945+
jinja_macros=loader_kwargs.get("jinja_macros"),
1946+
variables=get_variables(None),
1947+
path=path,
1948+
dialect=dialect,
1949+
default_catalog=loader_kwargs.get("default_catalog"),
1950+
)
1951+
if not rendered_blueprints:
1952+
raise_config_error("Failed to render blueprints property", path)
1953+
1954+
blueprints = t.cast(t.List, rendered_blueprints)[0]
1955+
19401956
return create_models_from_blueprints(
19411957
gateway=gateway,
19421958
blueprints=blueprints,

‎tests/core/test_model.py

+43
Original file line numberDiff line numberDiff line change
@@ -8233,6 +8233,49 @@ def entrypoint(evaluator):
82338233
)
82348234

82358235

8236+
def test_dynamic_blueprinting(tmp_path: Path) -> None:
8237+
init_example_project(tmp_path, dialect="duckdb", template=ProjectTemplate.EMPTY)
8238+
8239+
dynamic_template = tmp_path / "models/dynamic_template.sql"
8240+
dynamic_template.parent.mkdir(parents=True, exist_ok=True)
8241+
dynamic_template.write_text(
8242+
"""
8243+
MODEL (
8244+
name @customer.some_table,
8245+
kind FULL,
8246+
blueprints @gen_blueprints(),
8247+
);
8248+
8249+
SELECT
8250+
@field_a,
8251+
@{field_b} AS field_b
8252+
FROM @customer.some_source
8253+
8254+
"""
8255+
)
8256+
8257+
gen_blueprints = tmp_path / "macros/gen_blueprints.py"
8258+
gen_blueprints.parent.mkdir(parents=True, exist_ok=True)
8259+
gen_blueprints.write_text(
8260+
"""from sqlmesh import macro
8261+
8262+
@macro()
8263+
def gen_blueprints(evaluator):
8264+
return (
8265+
"((customer := customer1, field_a := x, field_b := y),"
8266+
" (customer := customer2, field_a := z, field_b := w))"
8267+
)"""
8268+
)
8269+
8270+
ctx = Context(
8271+
config=Config(model_defaults=ModelDefaultsConfig(dialect="duckdb")), paths=tmp_path
8272+
)
8273+
8274+
assert len(ctx.models) == 2
8275+
assert '"memory"."customer1"."some_table"' in ctx.models
8276+
assert '"memory"."customer2"."some_table"' in ctx.models
8277+
8278+
82368279
@time_machine.travel("2020-01-01 00:00:00 UTC")
82378280
def test_dynamic_date_spine_model(assert_exp_eq):
82388281
@macro()

0 commit comments

Comments
 (0)