You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 2838635
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: src/sqlbuild/.agents/skills/sqlbuild/references/docs/CONTENTS.md
+3-2Lines changed: 3 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -52,9 +52,10 @@ Bundled copies of every page on the SQLBuild documentation site, matching the in
52
52
-[Collections and Rendering](concepts/constants/collections-and-rendering.md) (`concepts/constants/collections-and-rendering`) - Define list, set, and object constants and control their adapter-specific SQL rendering.
53
53
-[Enum Model Contracts](concepts/enums/model-contracts.md) (`concepts/enums/model-contracts`) - Use an enum as a portable model-column domain with generated accepted-value validation.
54
54
-[Model-Private Values](concepts/model-private-values.md) (`concepts/model-private-values`) - Keep enums and constants inside one model when no other resource should use them.
55
-
-[Writing Macros](concepts/macros.md) (`concepts/macros`) - Write Python functions that generate reusable SQL fragments at compile time.
56
-
-[Composition and Context](concepts/macros/composition-and-context.md) (`concepts/macros/composition-and-context`) - Compose macros through Python, use compile context, and understand scoped imports.
55
+
-[Macros](concepts/macros.md) (`concepts/macros`) - Reuse SQL with typed SQL macros, or generate it with Python macros when it needs logic.
57
56
-[SQL Macros](concepts/macros/sql-macros.md) (`concepts/macros/sql-macros`) - Write typed, logic-free SQL fragments that the compiler checks and sees inside.
57
+
-[Python Macros](concepts/macros/python-macros.md) (`concepts/macros/python-macros`) - Write Python functions that generate SQL at compile time when the SQL needs logic.
58
+
-[Python Macro Composition and Context](concepts/macros/composition-and-context.md) (`concepts/macros/composition-and-context`) - Compose Python macros through imports, and use adapter, target, constants and enums.
58
59
-[Interpolation](concepts/interpolation.md) (`concepts/interpolation`) - How SQLBuild processes variables, context, and dynamic content in SQL and config.
59
60
-[Functions](concepts/functions.md) (`concepts/functions`) - User-defined functions and table functions managed as part of your project.
| Logic | None: the body is SQL | Any Python: loops, conditions, adapter and target context |
21
+
| Checks and tools | Each macro is checked on its own; `sqb format`, Rules and lineage see inside every call | Rules and lineage see the SQL each call returns |
26
22
27
-
## Create a macro
23
+
Prefer a SQL macro whenever no logic is needed: its calls stay readable, typed and checked, and
24
+
every tool sees the SQL it produces.
28
25
29
-
Put project-wide Python macros in Python files under `macros/python/`. SQL macros live next to
30
-
them in `macros/sql/`:
26
+
Typed, logic-free expressions, CTE lists and column lists.
27
+
Python functions that generate SQL when it needs logic.
28
+
29
+
## Where macros live
30
+
31
+
Each kind has its own folder:
31
32
32
33
```text
33
34
my_project/
34
35
├── macros/
35
36
│ ├── python/
36
-
│ │ └── currency.py
37
+
│ │ └── labels.py
37
38
│ └── sql/
39
+
│ └── cents_to_dollars.sql
38
40
├── models/
39
41
└── sqlbuild_project.toml
40
42
```
41
43
42
44
A file directly under a `macros/` folder fails with `D013`, which names the subfolder to move it
43
-
to. Folder-scoped macros use the same layout, such as `models/marts/_sqlbuild/_macros/python/`.
44
-
45
-
Every public function defined by a macro file becomes callable from SQL:
46
-
47
-
```python
48
-
# macros/python/currency.py
49
-
defcents_to_dollars(expression: str) -> str:
50
-
"""Convert a cents expression to dollars."""
51
-
returnf"ROUND(CAST({expression} AS DOUBLE) / 100, 2)"
52
-
```
45
+
to. A macro used by only part of the project can live in that folder instead, as
46
+
`_sqlbuild/macros/sql/` or `_sqlbuild/_macros/python/`, and is then visible only there. See
47
+
[Declarations and Scopes](declaration-scopes.md).
53
48
54
-
## Call a macro from SQL
49
+
## Call a macro
55
50
56
-
Use `@py.macro_name(...)` in a model query. Every macro call says its kind: `@py.` calls a Python
57
-
macro and `@sql.` a SQL macro. A bare `@macro_name(...)` fails with `P014`, which names both
58
-
spellings, and calling a macro with the other kind's prefix fails with `P020`.
51
+
Every call names the kind of macro it calls:
59
52
60
53
```sql
61
-
MODEL (
62
-
description "One row per order",
63
-
materialized table,
64
-
tags [marts],
65
-
);
66
-
67
54
SELECT
68
55
order_id,
69
-
@py.cents_to_dollars("amount_cents") AS amount_dollars
56
+
@sql.cents_to_dollars(amount_cents) AS amount_dollars,
57
+
@py.status_label("status") AS status_label
70
58
FROM __ref("stg_orders")
71
59
```
72
60
73
-
During compilation, SQLBuild replaces the call with the function's returned SQL:
74
-
75
-
```sql
76
-
ROUND(CAST(amount_cents AS DOUBLE) /100, 2)
77
-
```
78
-
79
-
A macro used directly in SQL must return a string.
80
-
81
-
## Arguments
82
-
83
-
Macro calls accept Python literal values:
84
-
85
-
- Strings: `"value"` or `'value'`
86
-
- Numbers: `42`, `3.14`, `-1`
87
-
- Booleans: `True`, `False`
88
-
- Lists: `[1, 2, 3]`
89
-
- Dictionaries: `{"key": "value"}`
90
-
-`None`
91
-
- The result of another macro call
92
-
-`__ref("model")`, `__source("source")`, and `__seed("seed")` references, alone or inside lists
93
-
and dictionaries
94
-
95
-
These inputs are rejected with an error. In a model body the error names the file line and
96
-
column; elsewhere it names the position within the macro's arguments:
97
-
98
-
- bytes (`b"text"`), complex numbers (`2j`), f-strings, and `...`
99
-
- a keyword argument passed twice, such as `@py.lit(a=1, a=2)`, which Python also rejects
100
-
- lone surrogate escapes such as `"\ud800"`; write a character outside the Basic Multilingual
101
-
Plane as one escape, such as `"\U0001F600"`, rather than as a surrogate pair
102
-
-`\N{...}` naming a multi-character named sequence; `\N` escapes name one character
103
-
- two values with no comma between them
104
-
105
-
Positional and keyword arguments are supported:
106
-
107
-
```sql
108
-
@py.mock_orders(count=5, status="completed")
109
-
```
110
-
111
-
Use quoted strings when passing SQL expressions such as column names. The macro decides how to
112
-
place that text into its returned SQL.
113
-
114
-
## Typed reference arguments
115
-
116
-
Pass the models, sources, and seeds a macro reads as reference arguments:
= help: write the reference in the model, or pass it in: @py.orders_base(__ref("stg_orders"))
149
-
= help: the current value is [references] enforce_explicit = true (from sqlbuild_project.toml or its default); while migrating a project, to allow macro-generated references, set this in sqlbuild_project.toml:
150
-
[references]
151
-
enforce_explicit = false
152
-
```
153
-
154
-
A dependency hidden inside a macro is invisible to reviewers of the model file and bypasses
155
-
declaration scopes. For projects migrating from other tools,
See [SQL Hooks](models/hooks/sql.md) for hook lifecycle and context syntax.
236
-
237
-
## Macros must be deterministic
238
-
239
-
A macro must return the same result whenever it is called with the same arguments and sees the same
240
-
context. Avoid module-level state such as counters, random values, the current time, and reads of
241
-
files or environment variables that the call does not receive.
242
-
243
-
SQLBuild relies on this contract to reuse macro results:
244
-
245
-
-[Compile reuse](../cli/compile.md) replays an unchanged compile without running macros again.
246
-
- A compile may run each distinct macro call once and reuse its result for identical calls
247
-
elsewhere in the project.
248
-
- A compile that fails stops at its first error. It does not run the project's macros a second
249
-
time to report that error.
250
-
- Macro call results are kept between compiles under `target/cache/` by default, so editing a
251
-
model does not run its unchanged macro calls again. They are recomputed when
252
-
macro or other Python files, configuration, declarations, seeds, sources, variables, the target,
253
-
the adapter, the installed packages, or the SQLBuild version change. Editing only model SQL keeps
254
-
them, and a changed call is always run again. Only the first compile in a process uses and saves
255
-
them: later compiles in the same process, such as in a notebook or a long-running server, run their
256
-
macros again. A compile that has loaded Python code it cannot read from a plain file, such as a
257
-
module imported from a zip archive, neither uses nor saves them.
258
-
259
-
Pass configuration through what SQLBuild compares: macro arguments (including `@@ENV:NAME` and
260
-
`@@var` values written in the calling SQL), `ctx.vars`, `ctx.target_name`, `ctx.adapter_name`,
261
-
and visible constants and enums. Environment variables a macro reads directly, for example with
262
-
`os.environ`, are compared only when their names start with `SQLBUILD_` or `SQB_`, the same set
263
-
compile reuse tracks. A macro whose result changes for any other reason may return a stale result.
74
+
The SQL macro expands first, and the Python macro receives its SQL as a string.
264
75
265
76
## Where macros work
266
77
@@ -275,8 +86,21 @@ Macros are supported in:
275
86
Macros are not accepted in ordinary `MODEL()` configuration fields. SQL hook entries are the
276
87
exception because their contents are SQL.
277
88
278
-
## Next steps
89
+
### Macros used only by tests
90
+
91
+
A macro that only tests use follows the usual [placement](declaration-scopes/placement.md)
92
+
rule: it must be private to the narrowest folder that contains its uses, so the project-wide
93
+
`macros/` directory rejects it with `S024`. Put it in `_sqlbuild/_macros/python/` or
94
+
`_sqlbuild/_macros/sql/` in the folder of the tests that call it, such as
95
+
`tests/unit/orders/_sqlbuild/_macros/python/`, or, when those tests define `__expected__` output
96
+
for a model, in that model's `_sqlbuild/_macros/`. The `S024` error names the folder to use.
97
+
`tests/unit/_sqlbuild/` itself is rejected with `D013`.
98
+
99
+
## Choose the right tool
279
100
280
-
Write typed, logic-free SQL fragments the compiler checks and sees inside.
281
-
Compose macros through Python imports and use adapter or target context.
282
-
Limit a macro to one folder, or to that folder and its child folders.
101
+
| Use | When |
102
+
|---|---|
103
+
|[SQL macro](macros/sql-macros.md)| The fragment is plain SQL with typed inputs: a calculation, a filter, a set of CTEs or columns you repeat. The compiler sees inside it. |
104
+
|[Python macro](macros/python-macros.md)| Generating the SQL needs logic: loops, conditions on arguments, the adapter or target, or reading project context. |
105
+
|[SQL function](functions.md)| The logic belongs in the warehouse, to be called by other tools or evaluated per row there, or it is too large to inline everywhere. |
106
+
|[Generic audit](audits.md)| The SQL checks data quality on a model rather than producing part of its query. |
0 commit comments