Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1d2e325
DEV-1608: Cube → SLayer ingestion (Stage 1)
ZmeiGorynych Jun 29, 2026
c1990c4
DEV-1608: address PR review feedback (Sonar gate + Codex)
ZmeiGorynych Jun 30, 2026
3ac7590
DEV-1608: final review nits (Sonar complexity + spec markdown)
ZmeiGorynych Jun 30, 2026
2f55c37
DEV-1608: clarify facade joined-measure doc example (CodeRabbit)
ZmeiGorynych Jul 1, 2026
3959d5f
DEV-1608: report path honors --models-dir (CodeRabbit)
ZmeiGorynych Jul 1, 2026
488f5d0
DEV-1608: address CodeRabbit review batch
ZmeiGorynych Jul 1, 2026
0d9d030
Merge remote-tracking branch 'origin/egor/dev-1625-variable-substitut…
ZmeiGorynych Aug 3, 2026
b31318c
Merge remote-tracking branch 'origin/main' into egor/dev-1608-cube-to…
ZmeiGorynych Aug 3, 2026
75d1aa7
feat(DEV-1730): list-valued {variable} substitution for IN pushdown
ZmeiGorynych Aug 3, 2026
30173ab
fix(DEV-1608/DEV-1730): address CodeRabbit + Sonar + Codex review
ZmeiGorynych Aug 3, 2026
00ba92b
feat(DEV-1730): Cube JS ingestion + FILTER_PARAMS representability
ZmeiGorynych Aug 4, 2026
2bb0428
Merge remote-tracking branch 'origin/egor/dev-1608-cube-to-slayer-ing…
ZmeiGorynych Aug 4, 2026
9648d6b
feat(DEV-1727): dialect-aware / complete escaping for Mode-A {var} su…
ZmeiGorynych Aug 4, 2026
ad365f9
Merge origin/egor/dev-1608-cube-to-slayer-ingestion into DEV-1727
ZmeiGorynych Aug 4, 2026
a944208
fix(DEV-1730): address CodeRabbit + Codex + Sonar review
ZmeiGorynych Aug 4, 2026
c8485d0
refactor(DEV-1730): reduce cognitive complexity (Sonar S3776)
ZmeiGorynych Aug 4, 2026
4016f4a
test(DEV-1727): isolate the throwing call in two raises-blocks (Sonar…
ZmeiGorynych Aug 4, 2026
6dec2dc
docs(DEV-1730): demonstrate optional blocks in the variable-substitut…
ZmeiGorynych Aug 4, 2026
8970bc7
Merge pull request #278 from MotleyAI/egor/dev-1727-dialect-aware-com…
ZmeiGorynych Aug 4, 2026
f4a7c71
docs(DEV-1730): clarify optional-block + list contract (CodeRabbit)
ZmeiGorynych Aug 4, 2026
0d8be1c
Merge remote-tracking branch 'origin/egor/dev-1608-cube-to-slayer-ing…
ZmeiGorynych Aug 4, 2026
6cb9e7b
refactor(DEV-1730): keep substitute_variables under S3776 after DEV-1…
ZmeiGorynych Aug 4, 2026
17bf5ce
Merge pull request #275 from MotleyAI/egor/dev-1730-cube-js-config-in…
ZmeiGorynych Aug 4, 2026
9bb846e
fix(DEV-1730): coerce scalars for declared list-valued {variable}s
ZmeiGorynych Aug 4, 2026
ef5a738
fix(DEV-1730): make the declared-variable bag self-identifying
ZmeiGorynych Aug 4, 2026
fb16a22
fix(DEV-1730): require a non-empty member in a variable declaration
ZmeiGorynych Aug 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/skills/slayer-models.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Saved query-backed models support two access patterns:

Variable precedence (highest first): runtime kwarg > stage `.variables` > outer query `.variables` > `model.query_variables`.

**Variables in model SQL (DEV-1625)**: the same `{var}` mechanism also substitutes into a model's **raw-SQL (Mode A) surfaces** — `SlayerModel.sql`, `SlayerModel.filters`, `Column.sql`, `Column.filter` — for a query's **direct source model** (the primitive for parameterizing hand-written SQL, e.g. Cube `FILTER_PARAMS`). Same precedence and `{{`/`}}` escaping. Contract: **raise-on-missing once any variable is in play** (a `query_variables` default or a caller value); a **fully variable-free execution leaves braces as literals** so raw brace literals like `'{1,2,3}'` survive untouched. String values are Mode-A-escaped (write the quotes yourself: `WHERE region = '{region}'`; trusted input — not dialect-aware, so avoid untrusted values on backslash-escaping backends like MySQL); `inspect_model` shows the literal `{var}` template. Nested `source_queries` stages, query-backed direct sources, join targets, and cross-model targets are deferred (DEV-1678) — a `{var}` there stays literal and errors on the stray placeholder.
**Variables in model SQL (DEV-1625)**: the same `{var}` mechanism also substitutes into a model's **raw-SQL (Mode A) surfaces** — `SlayerModel.sql`, `SlayerModel.filters`, `Column.sql`, `Column.filter` — for a query's **direct source model** (the primitive for parameterizing hand-written SQL, e.g. Cube `FILTER_PARAMS`). Same precedence and `{{`/`}}` escaping. Contract: **raise-on-missing once any variable is in play** (a `query_variables` default or a caller value); a **fully variable-free execution leaves braces as literals** so raw brace literals like `'{1,2,3}'` survive untouched. String values are Mode-A-escaped (write the quotes yourself: `WHERE region = '{region}'`; trusted input — not dialect-aware, so avoid untrusted values on backslash-escaping backends like MySQL); a **list** value renders an injection-safe `IN`-list body (`region IN ({regions})` with `{"regions": ["US","CA"]}` → `region IN ('US', 'CA')`; write the parens, elements auto-quoted; empty list raises); `inspect_model` shows the literal `{var}` template. Nested `source_queries` stages, query-backed direct sources, join targets, and cross-model targets are deferred (DEV-1678) — a `{var}` there stays literal and errors on the stray placeholder.

You **cannot** supply `columns` or `backing_query_sql` when saving a query-backed model — they're engine-managed cache; the save path rejects them. Caches refresh **only on save paths**: `engine.save_model()` and `create_model_from_query(save=True)`. `engine.execute()` never writes to storage — even on stale or empty caches.

Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/slayer-query.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Result column naming: `revenue:sum` → `orders.revenue_sum` (colon becomes unde

**Top-N filtering**: use `"rank(<measure>) <= N"` (e.g. `"rank(revenue:sum) <= 10"`) — dialect-portable and auto-promoted to a post-filter on the outer query. Raw `OVER (...)` SQL inside a filter or `ModelMeasure.formula` is rejected with an actionable error. Filtering on a `Column` whose `sql` contains a window function is also rejected (DEV-1369): use `rank()` / `dense_rank()` / `percent_rank()` / `ntile(n=<N>)` for top-N, or factor the windowed expression into an earlier stage of a multi-stage `source_queries` model.

**Variable substitution**: `{var}` placeholders in filter strings are substituted from the query's `variables` dict (or per-model defaults). Use `{{`/`}}` for literal braces. Write the surrounding quotes yourself (`status = '{status}'`); string values are auto-escaped so an embedded quote stays inside the literal. Numbers (incl. bool) insert verbatim; non-finite floats are rejected; undefined vars raise. The same `{var}` mechanism also fills the raw-SQL (Mode A) surfaces of the query's direct source model — `SlayerModel.sql`, `SlayerModel.filters`, `Column.sql`, `Column.filter` (DEV-1625). See slayer-models skill for details.
**Variable substitution**: `{var}` placeholders in filter strings are substituted from the query's `variables` dict (or per-model defaults). Use `{{`/`}}` for literal braces. Write the surrounding quotes yourself (`status = '{status}'`); string values are auto-escaped so an embedded quote stays inside the literal. Numbers (incl. bool) insert verbatim; non-finite floats are rejected; undefined vars raise. A **list** value renders an injection-safe `IN`-list for an `in`/`not in` filter (`region in ({regions})` with `{"regions": ["US","CA"]}` → `region IN ('US', 'CA')`) — write the parens, omit per-element quotes (auto-quoted); empty list raises. The same `{var}` mechanism also fills the raw-SQL (Mode A) surfaces of the query's direct source model — `SlayerModel.sql`, `SlayerModel.filters`, `Column.sql`, `Column.filter` (DEV-1625). See slayer-models skill for details.

## Executing

Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ data dir, override with `$SLAYER_STORAGE`.
- Dots denote join paths in queries (`customers.regions.name`); `__` denotes path aliases in model SQL (`customers__regions.name`)
- Models are keyed by `(data_source, name)`; joins resolve within the parent model's datasource
- Models/queries/datasource configs carry a `version` field; storage migrations run automatically on load (`slayer/storage/migrations.py`)
- Filters support `{variable}` placeholders from `query.variables`; datasource configs support `${ENV_VAR}`
- Filters support `{variable}` placeholders from `query.variables` (scalars, plus lists → injection-safe `IN`-list body: `region IN ({regions})`); datasource configs support `${ENV_VAR}`

## Database Support

Expand Down
Loading
Loading