From eb1513767c5366fbfcc8698dbea1a5efcb96af4a Mon Sep 17 00:00:00 2001 From: Kevin Longe <273747162+kvlonge@users.noreply.github.com> Date: Fri, 25 Sep 2026 11:10:16 +0100 Subject: [PATCH] fix: use the current declaration layout in the playground --- .../sqlbuild/references/docs/CONTENTS.md | 3 +- .../sqlbuild/references/docs/cli/janitor.md | 92 +++++++++++++++++-- .../sqlbuild/references/docs/cli/plan.md | 1 + .../docs/concepts/models/configuration.md | 2 + .../docs/concepts/models/migrations.md | 90 ++++++++++++++++++ .../docs/concepts/project-configuration.md | 12 ++- .../sqlbuild/references/docs/quickstart.md | 14 +-- .../cli/commands/_helpers/playground/copy.py | 3 +- .../{ => _sqlbuild}/_macros/currency.py.txt | 0 .../{ => _sqlbuild}/_macros/datetime.py.txt | 0 .../main/playground/test_playground.py | 11 ++- 11 files changed, 205 insertions(+), 23 deletions(-) create mode 100644 src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/models/migrations.md rename src/sqlbuild/cli/commands/_helpers/playground/templates/waffle_shop/models/marts/{ => _sqlbuild}/_macros/currency.py.txt (100%) rename src/sqlbuild/cli/commands/_helpers/playground/templates/waffle_shop/models/marts/{ => _sqlbuild}/_macros/datetime.py.txt (100%) diff --git a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/CONTENTS.md b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/CONTENTS.md index 6cdf75a7e2..25e70c7cb0 100644 --- a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/CONTENTS.md +++ b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/CONTENTS.md @@ -36,6 +36,7 @@ Bundled copies of every page on the SQLBuild documentation site, matching the in - [Schemas](concepts/models/schemas.md) (`concepts/models/schemas`) - Declare model columns inline or reuse canonical inherited schemas. - [Type Enforcement](concepts/models/type-enforcement.md) (`concepts/models/type-enforcement`) - Understand declared model types, static checks, and runtime casting. - [Contracts](concepts/models/contracts.md) (`concepts/models/contracts`) - Validate required or exact model output schemas. +- [Model migrations](concepts/models/migrations.md) (`concepts/models/migrations`) - Keep the history of an incremental or snapshot model when you rename it. - [Hooks](concepts/models/hooks.md) (`concepts/models/hooks`) - Run SQL or Python lifecycle hooks around model materialization. - [SQL Hooks](concepts/models/hooks/sql.md) (`concepts/models/hooks/sql`) - Define, parameterize, compile, and invoke reusable or inline SQL lifecycle hooks. - [Python Hooks](concepts/models/hooks/python.md) (`concepts/models/hooks/python`) - Define Python lifecycle hooks with runtime context, providers, SQL access, and skips. @@ -137,7 +138,7 @@ Bundled copies of every page on the SQLBuild documentation site, matching the in - [dag](cli/dag.md) (`cli/dag`) - Generate the static DAG artifact for Dagster and other integrations. - [query](cli/query.md) (`cli/query`) - Run ad hoc SQL queries against the project database. - [debug](cli/debug.md) (`cli/debug`) - Validate project configuration and test the warehouse connection. -- [janitor](cli/janitor.md) (`cli/janitor`) - Clean up stale warehouse relations. +- [janitor](cli/janitor.md) (`cli/janitor`) - Archive and then delete stale warehouse relations. - [clean](cli/clean.md) (`cli/clean`) - Remove compiled artifacts from the target directory. - [dbt](cli/dbt.md) (`cli/dbt`) - Coordinate dbt and SQLBuild projects. - [state](cli/state.md) (`cli/state`) - Manage the virtual mode state store. diff --git a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/cli/janitor.md b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/cli/janitor.md index 60356ca55b..f9c4d58bf1 100644 --- a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/cli/janitor.md +++ b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/cli/janitor.md @@ -2,13 +2,27 @@ # janitor -> Clean up stale warehouse relations. +> Archive and then delete stale warehouse relations. Online: https://docs.sqlbuild.com/cli/janitor +## Contents + +- Usage +- Flags +- Direct-mode lifecycle +- Relation age +- Audit record +- Restoring an archive +- Configuration +- Examples +- State history pruning +- Virtual environments +- Safety + # sqb janitor -Identifies and removes stale warehouse relations that are no longer part of the project. Requires `janitor.enabled = true` in `sqlbuild_project.toml`. +Finds stale warehouse relations that are no longer part of the project, archives them, and deletes archives once they expire. Requires `janitor.enabled = true` in `sqlbuild_project.toml`. ## Usage @@ -20,8 +34,61 @@ sqb --project-dir janitor [flags] | Flag | Description | |------|-------------| -| `--auto-approve` | Skip the confirmation prompt and delete immediately | -| `--retention-days` | Override the configured retention period (days) | +| `--auto-approve` | Skip the confirmation prompt and run the planned actions immediately | +| `--retention-days` | Override the configured retention period (days) before a stale relation is archived | +| `--direct-state-history-versions` | Override how many state-history versions are kept per identity | + +## Direct-mode lifecycle + +In direct mode, the janitor never drops a live relation directly. Each stale relation goes through two stages: + +1. **Archive.** Once a relation has been stale for `retention_days`, the janitor renames it in place, in the same schema, to: + + ``` + _SQB_ARCHIVE____ + ``` + + For example, `stg_orders` becomes `_SQB_ARCHIVE__20260924T101500Z__stg_orders`. A rename copies no data, and keeps the relation's table type, grants and time travel. +2. **Delete.** Once an archive is older than `archive_retention_days`, the janitor drops it. + +Stale relations are identified exactly as before. A relation is a candidate only if it is in a schema the project writes to, it is not produced by the current complete project, it was tracked by SQLBuild (when `delete_tracked_only = true`), it matches no exclude pattern, and it is older than the retention period. + +The age of an archive comes from the timestamp in its name, so deletion needs no other state. The janitor only deletes relations whose names **strictly** match the archive format and that are in a schema the project writes to. Names that only look similar are reported and never touched. The janitor also only acts on relations whose names are plain lowercase identifiers (letters, digits and underscores), and that don't collide case-insensitively with another relation in the same schema. Anything else is reported and left alone. + +Archive names are written as unquoted lowercase identifiers, so warehouses that fold unquoted names show them in their own case. On Snowflake, for example, the archive appears as `_SQB_ARCHIVE__20260924T101500Z__STG_ORDERS`. + +Long names are shortened with a short hash so they fit the adapter's identifier limit. The prefix and timestamp are never shortened. + +Setting both `retention_days` and `archive_retention_days` to `0` archives and deletes stale relations in the same run. + +## Relation age + +`retention_days` is measured from the last time a relation was written, as reported by the warehouse. For a relation the project no longer builds, that is roughly when it stopped being built. + +| Adapter | Age source | +|---------|------------| +| Snowflake | `INFORMATION_SCHEMA.TABLES` `CREATED` and `LAST_ALTERED`, which change on every write | +| Databricks | `DESCRIBE DETAIL` `lastModified` for tables, and `INFORMATION_SCHEMA.TABLES` for views | +| BigQuery | `__TABLES__` `creation_time` and `last_modified_time` | +| PostgreSQL, SQL Server, DuckDB, MotherDuck | Not available | + +When the warehouse can't report a relation's age, the janitor skips that relation whenever `retention_days` is greater than `0`. SQL Server is in this group because its modification date ignores inserts and updates, so a recently written table could look old. + +Ages are only looked up for relations that are otherwise candidates, and not at all when `retention_days` is `0`. + +## Audit record + +Every archive and every delete is recorded in an append-only `_sqlbuild_janitor_events` table in the affected schema. It records the original name, the archive name, the time and the invocation. The janitor never reads this table to decide what to do. It exists for auditing, and for restoring archives whose names were shortened. + +## Restoring an archive + +Rename the archive back to its original name before it expires, using your warehouse's rename statement. For example, on Snowflake: + +```sql +ALTER TABLE analytics._SQB_ARCHIVE__20260924T101500Z__stg_orders RENAME TO analytics.stg_orders; +``` + +If the archive's name was shortened, look up the original name in `_sqlbuild_janitor_events`. After an archive has been deleted, your warehouse's own time travel or undrop feature may still be able to recover it within its retention window. ## Configuration @@ -30,20 +97,21 @@ Configure janitor behavior in `sqlbuild_project.toml`: ```toml [janitor] enabled = true -retention_days = 30 +retention_days = 14 +archive_retention_days = 14 delete_tracked_only = true exclude_patterns = ["audit_*", "tmp_*"] ``` -See [Project Configuration](../concepts/project-configuration.md) for details on janitor settings. +When `retention_days` is not set, direct mode uses `14` and virtual-environment mode uses `30`. See [Project Configuration](../concepts/project-configuration.md#janitor) for every janitor setting. ## Examples ```bash -# Interactive mode (prompts for confirmation) +# Interactive mode (shows the plan and prompts for confirmation) sqb janitor -# Auto-approve deletion +# Run the planned archives and deletes without prompting sqb janitor --auto-approve # Override retention to 7 days @@ -52,8 +120,12 @@ sqb janitor --retention-days 7 ## State history pruning -In addition to cleaning up stale relations, the janitor prunes old rows from `_sqlbuild_fingerprints` and `_sqlbuild_source_freshness` tables, retaining only the latest record per identity. This keeps state tables compact without affecting change detection. +In addition to archiving stale relations, the janitor prunes old rows from `_sqlbuild_fingerprints` and `_sqlbuild_source_freshness`, keeping the latest `direct_state_history_versions` rows per identity (default `20`). This is configured separately from relation retention. + +## Virtual environments + +In virtual-environment mode, the janitor also cleans up expired environments, old checkpoints and unreferenced physical versions. See [Virtual environments: janitor](../concepts/virtual-environments/janitor.md). Direct-mode archiving doesn't apply there. In both modes, relations whose names differ only by case from another relation in the same schema are reported and never dropped, and exclude patterns match regardless of case. ## Safety -Janitor prompts for confirmation before deleting. The confirmation requires typing an exact string to prevent accidental deletion. Use `--auto-approve` only in CI or when you're certain. +The janitor shows every planned archive and delete, with exact names, ages and expiry, then asks you to type an exact confirmation phrase. Use `--auto-approve` only in automation, or when you're certain. diff --git a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/cli/plan.md b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/cli/plan.md index 8614a3b64a..d950316ac4 100644 --- a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/cli/plan.md +++ b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/cli/plan.md @@ -25,6 +25,7 @@ sqb --project-dir plan [flags] | `--changes-only` | Virtual mode only: show work not already bound to its expected VDE version | | `--no-python` | Exclude read-side Python tasks and assets from the plan | | `--defer-to` | Resolve unselected model references against another target | +| `--as` | Compile for another target and show its plan, including [model migration](../concepts/models/migrations.md) decisions, using the current connection. Inspection only. | | `--json` | Output the plan as JSON | | `--full-refresh` | Plan a full rebuild for selected models unless a model sets `full_refresh false`; `full_refresh true` forces a model without this flag | | `--start-cursor-ts` | Override start cursor for timestamp incremental models (ISO format) | diff --git a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/models/configuration.md b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/models/configuration.md index f7c37aa2d2..b6c4fd8161 100644 --- a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/models/configuration.md +++ b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/models/configuration.md @@ -81,6 +81,8 @@ Table promotion mode is a project setting rather than a `MODEL()` field. Staged | `full_refresh` | Optional model execution override: `false` always runs incrementally, `true` always full-refreshes, and omission follows the command | | `on_schema_change` | `append_new_columns`, `sync_all_columns`, `ignore`, or `fail` | | `replay_on_change` | `forward`, `full`, or `bounded-` | +| `migrate_from` | Old model name (or `schema.name`) whose data this model takes over; see [Model migrations](migrations.md). Also valid on snapshot models | +| `migrate_force` | `true` replaces a destination that already has its own build history during a migration | See [Incremental](../incremental.md) for full semantics. diff --git a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/models/migrations.md b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/models/migrations.md new file mode 100644 index 0000000000..3ec30497a7 --- /dev/null +++ b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/models/migrations.md @@ -0,0 +1,90 @@ + + +# Model migrations + +> Keep the history of an incremental or snapshot model when you rename it. + +Online: https://docs.sqlbuild.com/concepts/models/migrations + +# Model migrations + +Renaming an incremental or snapshot model normally means rebuilding it from scratch under the new name, which loses any history the source data can no longer reproduce. A model migration moves the existing relation's data to the new name instead, then continues building incrementally. + +Migrations apply to incremental and snapshot models in direct mode. Virtual-environment builds reject `migrate_from`. + +## Declaring a migration + +Add `migrate_from` to the renamed model's header, naming the old model: + +```sql +MODEL ( + materialized incremental, + migrate_from stg_orders, + cursor order_date, + ... +); +``` + +Use `schema.name` when the old relation is in a different schema of the same database. + +On the next build, SQLBuild copies the old relation's data to the new name through a staging table (see [How a move runs](#how-a-move-runs)), records the move, and builds the model incrementally from the migrated state. There is no first-run rebuild, and no `replay_on_change` replay caused by the rename. The old relation is never modified or dropped. Once it is no longer part of the project, [janitor](../../cli/janitor.md) archives it like any other stale relation. + +After the move is recorded, `migrate_from` has no further effect, and SQLBuild tells you it can be removed. Keep it until every target that needs the move has built. + +## Decisions + +`sqb plan` shows the decision for every migration: + +| Decision | Meaning | +|----------|---------| +| `migrate` | The new relation doesn't exist. Move the old one's data to it. | +| `done` | The move is already recorded. Nothing to do. | +| `redo` | The new relation exists but has no build history and no recorded move, which is what an interrupted migration leaves behind. Move it again. | +| `superseded replace` | The new relation was itself the origin of the latest recorded move, for example after renaming a model back. Replace it with the newer data. | +| `forced replace` | The new relation has its own build history and `migrate_force true` is set. Replace it. | +| `conflict` | The new relation has its own build history. The build stops (`M103`) until you set `migrate_force true` or remove `migrate_from`. | +| `origin missing` | The old relation doesn't exist and no move was recorded. The build stops (`M102`). | + +The origin and destination must be compatible under the model's normal `on_schema_change` rules; otherwise the build stops (`M104`). + +`migrate_force true` only affects the `conflict` case and is safe to leave in the header. + +## Automatic discovery + +If a selected model has never been built, SQLBuild compares it with models that were removed from the project but whose relations still exist. When exactly one removed model has equivalent logic, it is migrated automatically. Equivalent means the same query and configuration, ignoring the model's own name, CTE and table alias names, comments, formatting, and storage-only settings. Renamed upstream models are matched first, so a renamed chain of models is migrated together. Removed models whose data was already moved on by a recorded migration are not candidates, so a model renamed several times matches its latest table. + +Renamed tables and views are matched the same way. They are still rebuilt under the new name, since they hold no history, but they keep their identity for change detection, so incremental models downstream of a renamed view are not replayed or rebuilt. These renames are recorded as `renamed` events. + +Automatic discovery never guesses. If a match is ambiguous, SQLBuild warns (`M107`) and builds from scratch; declare `migrate_from` to choose. An explicit `migrate_from` always wins. Automatic discovery covers renames within the project's schemas; use `migrate_from` to move a model to another schema. Relations last built before this feature carry no stored fingerprint and aren't matched automatically. + +## How a move runs + +A move never overwrites the destination directly: + +1. The old relation is cloned or copied into a new staging table named `_sqb_archive____migration_stage__`, with the destination's configured table type. +2. The staging table is checked: it must exist, have the expected columns and table type, and, for a physical copy, the same row count as the old relation. +3. The staging table is swapped in as the destination. If a destination already existed, for example after `superseded replace` or `forced replace`, it is kept as `_sqb_archive____migration_previous__` rather than dropped. +4. The move is recorded, then the model builds as usual. + +The old relation is never modified. Staging and replaced tables use the [janitor](../../cli/janitor.md) archive format, so an abandoned staging table or a replaced destination is deleted by janitor after `archive_retention_days`. A staging table left by an interrupted run is never reused; the next run stages again. Don't run janitor at the same time as a build in the same schema. + +`sqb plan` shows how each move will run, for example `physical copy, transient -> permanent, promote by swap`. + +## State + +Each move is recorded in an append-only `_sqlbuild_migrations` table in the destination schema. A missing record means completion is unrecorded; staging or promotion may already have happened. Re-running after an interruption recovers through the migration decisions above. + +## Adapter support + +| Adapter | Staging | Promotion | +|---------|---------|-----------| +| Snowflake | Zero-copy clone with `COPY GRANTS`. Transient → permanent is a physical copy, because Snowflake can't clone a transient table into a permanent one. | `ALTER TABLE … SWAP WITH` for an existing destination; rename for a missing destination | +| BigQuery | `CREATE TABLE … CLONE`, or `CREATE TABLE … COPY` when BigQuery refuses the clone | Two renames; the destination is briefly missing between them, and an interrupted run recovers on retry | +| Databricks | `DEEP CLONE` | Two renames, as for BigQuery | +| PostgreSQL, SQL Server, DuckDB, MotherDuck | Physical copy | Renames and the migration record in one transaction | + +On PostgreSQL, views that depend on the destination are re-pointed to the new table in the same transaction, keeping their options, owner and grants. Materialized views are not re-pointed. + +## Previewing another target + +`sqb plan --as ` compiles the project for another target, for example production, and shows its migration decisions using your current connection. It only inspects; nothing is written. diff --git a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/project-configuration.md b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/project-configuration.md index 177a0e55dc..10bef8ed84 100644 --- a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/project-configuration.md +++ b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/concepts/project-configuration.md @@ -372,12 +372,13 @@ See [Macros](macros.md) for details on variable substitution and how variables i ## Janitor -Configuration for the `sqb janitor` command, which cleans up stale warehouse relations: +Configuration for the `sqb janitor` command, which archives and then deletes stale warehouse relations: ```toml [janitor] enabled = false -retention_days = 30 +retention_days = 14 +archive_retention_days = 14 delete_tracked_only = true exclude_patterns = ["audit_*", "tmp_*"] ``` @@ -385,9 +386,14 @@ exclude_patterns = ["audit_*", "tmp_*"] | Field | Default | Description | |-------|---------|-------------| | `enabled` | `false` | Whether janitor is active | -| `retention_days` | `30` | Only clean relations older than this many days | +| `retention_days` | `14` in direct mode, `30` in virtual-environment mode | How many days a relation must be stale before it is archived (direct mode) or cleaned up (virtual-environment mode) | +| `archive_retention_days` | `14` | Direct mode only: how many days an archive is kept before it is deleted. `0` deletes it in the same run. | | `delete_tracked_only` | `true` | Only clean relations that appear in fingerprint tracking | | `exclude_patterns` | `[]` | Glob patterns for relations to skip | +| `direct_state_history_versions` | `20` | How many state-history rows to keep per identity in `_sqlbuild_fingerprints` and `_sqlbuild_source_freshness` | +| `max_checkpoints` | `20` | Virtual-environment mode: how many checkpoints to keep | + +See [janitor](../cli/janitor.md) for the archive and delete lifecycle. ## Scenario diff --git a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/quickstart.md b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/quickstart.md index 7dd8a6681d..5d7117be89 100644 --- a/src/sqlbuild/.agents/skills/sqlbuild/references/docs/quickstart.md +++ b/src/sqlbuild/.agents/skills/sqlbuild/references/docs/quickstart.md @@ -221,7 +221,9 @@ See [Incremental](concepts/incremental.md) for details on cursor-based strategie waffle-shop/ sqlbuild_project.toml # project config sources/ - raw.yml # source declarations (inline expression data) + raw.yml # source declarations (loader-managed and expression-backed) + loaders/ + waffle_sources.py # Python loaders for raw__customers and raw__orders seeds/ waffle_types.csv # seed data lookups.yml # seed declarations @@ -229,9 +231,6 @@ waffle-shop/ sql/ udf__is_completed_order.sql # scalar SQL UDF table_fn__customer_orders.sql # table function - schemas/ - orders/ - order.sql # reusable model column schema models/ staging/ stg_customers.sql # view (audits declared in MODEL() header) @@ -245,6 +244,10 @@ waffle-shop/ hourly_order_activity.sql # microbatch incremental hourly_activity_with_daily_context.sql # microbatch incremental daily_activity_rollup.sql # microbatch incremental + _sqlbuild/ + _macros/ # visible only to models directly in marts/ + currency.py # cents_to_dollars macro + datetime.py # adapter-portable timestamp_trunc intermediate/ customer_status_snapshot.sql # merge incremental order_status_index.sql # integer cursor incremental @@ -261,8 +264,7 @@ waffle-shop/ daily_revenue_minimal.sql # E2E scenario test daily_revenue_multi_order.sql # E2E scenario test macros/ - currency.py # cents_to_dollars macro - datetime.py # adapter-portable timestamp_trunc + currency.py # project-wide line_total_cents macro materializations/ partition_tracked.py # custom materialization ``` diff --git a/src/sqlbuild/cli/commands/_helpers/playground/copy.py b/src/sqlbuild/cli/commands/_helpers/playground/copy.py index c2fd26a0fe..93d4d684d0 100644 --- a/src/sqlbuild/cli/commands/_helpers/playground/copy.py +++ b/src/sqlbuild/cli/commands/_helpers/playground/copy.py @@ -81,8 +81,7 @@ _PYTHON_NODES_TASKS_PY: str = '''"""Task examples for the Python nodes playground.""" -from sqlbuild.compiler.python_nodes.types import SkipMode -from sqlbuild.tasks import task +from sqlbuild.tasks import SkipMode, task @task(tags=["python", "ingress"], group="ingress") diff --git a/src/sqlbuild/cli/commands/_helpers/playground/templates/waffle_shop/models/marts/_macros/currency.py.txt b/src/sqlbuild/cli/commands/_helpers/playground/templates/waffle_shop/models/marts/_sqlbuild/_macros/currency.py.txt similarity index 100% rename from src/sqlbuild/cli/commands/_helpers/playground/templates/waffle_shop/models/marts/_macros/currency.py.txt rename to src/sqlbuild/cli/commands/_helpers/playground/templates/waffle_shop/models/marts/_sqlbuild/_macros/currency.py.txt diff --git a/src/sqlbuild/cli/commands/_helpers/playground/templates/waffle_shop/models/marts/_macros/datetime.py.txt b/src/sqlbuild/cli/commands/_helpers/playground/templates/waffle_shop/models/marts/_sqlbuild/_macros/datetime.py.txt similarity index 100% rename from src/sqlbuild/cli/commands/_helpers/playground/templates/waffle_shop/models/marts/_macros/datetime.py.txt rename to src/sqlbuild/cli/commands/_helpers/playground/templates/waffle_shop/models/marts/_sqlbuild/_macros/datetime.py.txt diff --git a/tests/unit/src/sqlbuild/cli/commands/main/playground/test_playground.py b/tests/unit/src/sqlbuild/cli/commands/main/playground/test_playground.py index 8464c8cf7e..f93ced3ba9 100644 --- a/tests/unit/src/sqlbuild/cli/commands/main/playground/test_playground.py +++ b/tests/unit/src/sqlbuild/cli/commands/main/playground/test_playground.py @@ -37,6 +37,8 @@ Path("functions/sql/table_fn__customer_orders.sql"), Path("loaders/waffle_sources.py"), Path("macros/currency.py"), + Path("models/marts/_sqlbuild/_macros/currency.py"), + Path("models/marts/_sqlbuild/_macros/datetime.py"), Path("materializations/partition_tracked.py"), ), unexpected_paths=( @@ -44,6 +46,7 @@ Path("sqlbuild_local.toml"), Path("waffle_shop_control.duckdb"), Path("macros/__pycache__"), + Path("models/marts/_macros"), ), expected_file_fragments=( ( @@ -225,7 +228,12 @@ ), ( Path("tasks/orders.py"), - ("def prepare_raw_orders", "SkipMode.SOFT", "def export_window"), + ( + "from sqlbuild.tasks import SkipMode, task", + "def prepare_raw_orders", + "SkipMode.SOFT", + "def export_window", + ), ), ( Path("loaders/orders.py"), @@ -247,6 +255,7 @@ ), ), ), + unexpected_file_fragments=((Path("tasks/orders.py"), ("sqlbuild.compiler",)),), ), ], ids=lambda case: case.description,