Skip to content

Commit 5a8beb4

Browse files
authored
Chore: update macro docs to include runtime_stage macro (#1580)
* Chore: update macro docs to include runtime_stage macro * Rephrase * Rephrase * update example to use ALTER TYPE * Fixups * Rephrase sentence * Note that runtime_stage is only available to pre/post-statements * Don't constrain runtime stage usage * Update test
1 parent 7d4bd27 commit 5a8beb4

5 files changed

Lines changed: 61 additions & 4 deletions

File tree

docs/concepts/macros/macro_variables.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ We describe SQLMesh's predefined variables below; user-defined macro variables a
3737
## Predefined Variables
3838
SQLMesh comes with predefined variables that can be used in your queries. They are automatically set by the SQLMesh runtime.
3939

40-
These variables are related to time and comprise a combination of prefixes (start, end, execution) and postfixes (date, ds, ts, epoch, millis).
40+
These variables are mostly related to time and comprise a combination of prefixes (start, end, execution) and postfixes (date, ds, ts, epoch, millis).
4141

4242
SQLMesh uses the python [datetime module](https://docs.python.org/3/library/datetime.html) for handling dates and times. It uses the standard [Unix epoch](https://en.wikipedia.org/wiki/Unix_time) start of 1970-01-01. *All predefined variables with a time component use the [UTC time zone](https://en.wikipedia.org/wiki/Coordinated_Universal_Time).*
4343

@@ -86,3 +86,10 @@ All predefined macro variables:
8686
* @start_millis
8787
* @end_millis
8888
* @execution_millis
89+
90+
Other macro variables:
91+
92+
* @runtime_stage - A string value that denotes the current stage of the SQLMesh runtime. It can take one of the following values:
93+
* 'loading' - The project is currently being loaded into SQLMesh's runtime context.
94+
* 'creating' - The model tables are being created.
95+
* 'evaluating' - The models' logic is being evaluated.

docs/concepts/macros/sqlmesh_macros.md

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,10 +260,22 @@ It includes three elements:
260260
2. A value to return if the condition is `TRUE`
261261
3. A value to return if the condition is `FALSE` [optional]
262262

263-
These elements are specified as `@IF([logical condition], [value if TRUE], [value if FALSE])`.
263+
These elements are specified as:
264+
265+
```sql linenums="1"
266+
@IF([logical condition], [value if TRUE], [value if FALSE])
267+
```
264268

265269
The value to return if the condition is `FALSE` is optional - if it is not provided and the condition is `FALSE`, then the macro has no effect on the resulting query.
266270

271+
It's also possible to use this macro in order to conditionally execute pre/post-statements:
272+
273+
```sql linenums="1"
274+
@IF([logical condition], [statement to execute if TRUE]);
275+
```
276+
277+
The `@IF` pre/post-statement itself must end with a semi-colon, but the inner statement argument must not.
278+
267279
The logical condition should be written *in SQL* and is evaluated with [SQLGlot's](https://github.com/tobymao/sqlglot) SQL engine. It supports the following operators:
268280

269281
- Equality: `=` for equals, `!=` or `<>` for not equals
@@ -318,6 +330,33 @@ SELECT
318330
FROM table
319331
```
320332

333+
Another example is conditionally executing a pre/post-statement depending on the current [runtime stage](./macro_variables.md#predefined-variables). For instance, the following `@IF` post-statement will only be executed at model evaluation time:
334+
335+
```sql linenums="1"
336+
MODEL (
337+
name sqlmesh_example.full_model,
338+
kind FULL,
339+
cron '@daily',
340+
grain item_id,
341+
audits [assert_positive_order_ids],
342+
);
343+
344+
SELECT
345+
item_id,
346+
count(distinct id) AS num_orders,
347+
FROM
348+
sqlmesh_example.incremental_model
349+
GROUP BY item_id
350+
ORDER BY item_id;
351+
352+
@IF(
353+
@runtime_stage = 'evaluating',
354+
ALTER TABLE sqlmesh_example.full_model ALTER item_id TYPE VARCHAR
355+
);
356+
```
357+
358+
NOTE: we can also, say, alter the type of a column if the `@runtime_stage` is `'creating'`, but that will only have meaningful effects if the corresponding model is of an incremental kind, since `FULL` models are rebuilt on each evaluation and hence any changes made at their creation stage will be overwritten.
359+
321360
#### @EVAL
322361

323362
`@EVAL` evaluates its arguments with SQLGlot's SQL executor.

sqlmesh/core/renderer.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ def render(
327327
snapshots=snapshots,
328328
table_mapping=table_mapping,
329329
is_dev=is_dev,
330+
runtime_stage=runtime_stage,
330331
**kwargs,
331332
)
332333
except ParsetimeAdapterCallError:

sqlmesh/core/snapshot/evaluator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,14 @@ def apply(query_or_df: QueryOrDF, index: int = 0) -> None:
152152
end=end,
153153
execution_time=execution_time,
154154
has_intervals=bool(snapshot.intervals),
155+
runtime_stage=RuntimeStage.EVALUATING,
155156
**kwargs,
156157
)
157158

158159
render_statements_kwargs = dict(
159160
engine_adapter=self.adapter,
160161
snapshots=snapshots,
161162
is_dev=is_dev,
162-
runtime_stage=RuntimeStage.EVALUATING,
163163
**common_render_kwargs,
164164
)
165165

tests/core/test_snapshot_evaluator.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ def increment_stage_counter(evaluator) -> None:
171171
@increment_stage_counter();
172172
@if(@runtime_stage = 'evaluating', ALTER TABLE test_schema.foo MODIFY COLUMN c SET MASKING POLICY p);
173173
174-
SELECT 1 AS a;
174+
SELECT 1 AS a, @runtime_stage AS b;
175175
"""
176176
),
177177
macros=macro.get_registry(),
@@ -196,6 +196,16 @@ def increment_stage_counter(evaluator) -> None:
196196
[parse_one("ALTER TABLE test_schema.foo MODIFY COLUMN c SET MASKING POLICY p")]
197197
)
198198

199+
assert snapshot.model.render_query().sql() == '''SELECT 1 AS "a", 'loading' AS "b"'''
200+
assert (
201+
snapshot.model.render_query(runtime_stage=RuntimeStage.CREATING).sql()
202+
== '''SELECT 1 AS "a", 'creating' AS "b"'''
203+
)
204+
assert (
205+
snapshot.model.render_query(runtime_stage=RuntimeStage.EVALUATING).sql()
206+
== '''SELECT 1 AS "a", 'evaluating' AS "b"'''
207+
)
208+
199209

200210
def test_evaluate_paused_forward_only_upstream(mocker: MockerFixture, make_snapshot):
201211
model = SqlModel(name="test_schema.test_model", query=parse_one("SELECT a, ds"))

0 commit comments

Comments
 (0)