diff --git a/docs/concepts/macros/jinja_macros.md b/docs/concepts/macros/jinja_macros.md index 49b5f81912..018224d5cc 100644 --- a/docs/concepts/macros/jinja_macros.md +++ b/docs/concepts/macros/jinja_macros.md @@ -321,6 +321,6 @@ Some SQL dialects interpret double and single quotes differently. We could repla ## Mixing macro systems -SQLMesh supports both the Jinja and [SQLMesh](./sqlmesh_macros.md) macro systems. We strongly recommend using only one system in a single model - if both are present, they may fail or behave in unintuitive ways. +SQLMesh supports both the Jinja and [SQLMesh](./sqlmesh_macros.md) macro systems. -[Predefined SQLMesh macro variables](./macro_variables.md) can be used in a query containing user-defined Jinja variables and functions. However, predefined variables passed as arguments to a user-defined Jinja macro function must use the Jinja curly brace syntax `{{ start_ds }}` instead of the SQLMesh macro `@` prefix syntax `@start_ds`. Note that curly brace syntax may require quoting to generate the equivalent of the `@` syntax. +Mixing the two systems is not supported, i.e., a SQL model may either use Jinja syntax, or SQLMesh macro syntax, but not both. diff --git a/docs/concepts/macros/sqlmesh_macros.md b/docs/concepts/macros/sqlmesh_macros.md index f28e77e203..7f8de569b3 100644 --- a/docs/concepts/macros/sqlmesh_macros.md +++ b/docs/concepts/macros/sqlmesh_macros.md @@ -2119,4 +2119,6 @@ Typed macros in SQLMesh not only enhance the development experience by making ma ## Mixing macro systems -SQLMesh supports both SQLMesh and [Jinja](./jinja_macros.md) macro systems. We strongly recommend using only one system in a model - if both are present, they may fail or behave in unintuitive ways. +SQLMesh supports both the Jinja and [SQLMesh](./sqlmesh_macros.md) macro systems. + +Mixing the two systems is not supported, i.e., a SQL model may either use Jinja syntax, or SQLMesh macro syntax, but not both. diff --git a/examples/sushi/models/waiter_as_customer_by_day.sql b/examples/sushi/models/waiter_as_customer_by_day.sql index 7dc12db873..9f8f54e498 100644 --- a/examples/sushi/models/waiter_as_customer_by_day.sql +++ b/examples/sushi/models/waiter_as_customer_by_day.sql @@ -27,6 +27,6 @@ SELECT FROM sushi.waiters AS w JOIN sushi.customers as c ON w.waiter_id = c.customer_id JOIN sushi.waiter_names as wn ON w.waiter_id = wn.id -WHERE w.event_date BETWEEN @start_date AND @end_date; +WHERE w.event_date BETWEEN CAST('{{ start_date }}' AS DATE) AND CAST('{{ end_date }}' AS DATE); JINJA_END; diff --git a/sqlmesh/core/renderer.py b/sqlmesh/core/renderer.py index 8b733d4c55..c3304533bb 100644 --- a/sqlmesh/core/renderer.py +++ b/sqlmesh/core/renderer.py @@ -188,32 +188,38 @@ def _resolve_table(table: str | exp.Table) -> str: **kwargs, } + jinja_env_kwargs = render_kwargs.copy() variables = kwargs.pop("variables", {}) - jinja_env_kwargs = { - **{ - **render_kwargs, - **_prepare_python_env_for_jinja(macro_evaluator, self._python_env), - **variables, - }, - "snapshots": snapshots or {}, - "table_mapping": table_mapping, - "deployability_index": deployability_index, - "default_catalog": self._default_catalog, - "runtime_stage": runtime_stage.value, - "resolve_table": _resolve_table, - } + if this_model: render_kwargs["this_model"] = this_model jinja_env_kwargs["this_model"] = this_model.sql( dialect=self._dialect, identify=True, comments=False ) - jinja_env = self._jinja_macro_registry.build_environment(**jinja_env_kwargs) - expressions = [self._expression] if isinstance(self._expression, d.Jinja): + # Mixing Jinja and SQLMesh macros is not supported + render_sqlmesh_macros = False + + jinja_env_kwargs.update( + { + **{ + **_prepare_python_env_for_jinja(macro_evaluator, self._python_env), + **variables, + }, + "snapshots": snapshots or {}, + "table_mapping": table_mapping, + "deployability_index": deployability_index, + "default_catalog": self._default_catalog, + "runtime_stage": runtime_stage.value, + "resolve_table": _resolve_table, + } + ) try: expressions = [] + + jinja_env = self._jinja_macro_registry.build_environment(**jinja_env_kwargs) rendered_expression = jinja_env.from_string(self._expression.name).render() logger.debug( f"Rendered Jinja expression for model '{self._model_fqn}' at '{self._path}': '{rendered_expression}'" @@ -229,30 +235,34 @@ def _resolve_table(table: str | exp.Table) -> str: raise ConfigError( f"Could not render or parse jinja at '{self._path}'.\n{ex}" ) from ex - - macro_evaluator.locals.update(render_kwargs) - - if variables: - macro_evaluator.locals.setdefault(c.SQLMESH_VARS, {}).update(variables) - - for definition in self._macro_definitions: - try: - macro_evaluator.evaluate(definition) - except Exception as ex: - raise_config_error( - f"Failed to evaluate macro '{definition}'.\n\n{ex}\n", self._path - ) + else: + render_sqlmesh_macros = True + macro_evaluator.locals.update(render_kwargs) + + if variables: + macro_evaluator.locals.setdefault(c.SQLMESH_VARS, {}).update(variables) + + for definition in self._macro_definitions: + try: + macro_evaluator.evaluate(definition) + except Exception as ex: + raise_config_error( + f"Failed to evaluate macro '{definition}'.\n\n{ex}\n", self._path + ) resolved_expressions: t.List[t.Optional[exp.Expression]] = [] for expression in expressions: - try: - transformed_expressions = ensure_list(macro_evaluator.transform(expression)) - except Exception as ex: - raise_config_error( - f"Failed to resolve macros for\n\n{expression.sql(dialect=self._dialect, pretty=True)}\n\n{ex}\n", - self._path, - ) + if render_sqlmesh_macros: + try: + transformed_expressions = ensure_list(macro_evaluator.transform(expression)) + except Exception as ex: + raise_config_error( + f"Failed to resolve macros for\n\n{expression.sql(dialect=self._dialect, pretty=True)}\n\n{ex}\n", + self._path, + ) + else: + transformed_expressions = [expression] for expression in t.cast(t.List[exp.Expression], transformed_expressions): with self._normalize_and_quote(expression) as expression: