SLayer 1.0.0
SLayer 1.0 is the release where the query language becomes consistent: if a query makes sense, it should run, and if it's impossible to resolve it to correct SQL, it should fail with an error that tells you why. Most of the work since 0.10.2 removes "not supported" refusals for queries that were well-defined, and closes the remaining cases where SLayer quietly returned plausible but wrong numbers.
More queries just work
window=now works on every aggregation, not onlysumandavg: rollingcount,min,max,count_distinct, statistics, your custom aggregations, andfirst/last(the earliest or latest value within the window). Parameters such asweight=are read per row within the window.- Downstream stages of a multi-stage query can now use time dimensions on their upstream's date columns, so you can, for example, bucket each customer's last order date by month in a second stage.
time_shift,change,cumsum, windows anddate_rangeall work there too. - Aggregating an expression that mixes columns from joined models, such as
sum(amount - customers.discount), now works, as does nesting a transform inside an aggregation (sum(cumsum(x) - 1)) or passing one as a parameter (weighted_avg(price, weight=rank(...))). - Filters that mix columns from several joined models under
ORorNOT, such astier = 'bronze' or orders.status = 'ok', are now applied correctly instead of being dropped with a warning. - A transform's own
partition_by=can now name a computed dimension, just like an aggregation's can. - Column SQL containing
:word, for example a regex like(?:...), no longer fails with a "value is required for bind parameter" error.
Fixes for silently wrong numbers
- Filtering on a joined one-to-many model (e.g. customers filtered by
orders.status = 'ok') no longer double-counts customers in partitioned, windowed,first/lastor raw-row queries. SLayer now keeps each customer that has at least one matching order, counted once. time_shift,changeandchange_pctover an expression that contains apartition_by=aggregation, afirst/last, or a windowed aggregation now keep each part's own grouping instead of recomputing it wrongly.- A time dimension finer than a column's existing bucket (a
daydimension over a column already truncated tomonth) is now an error instead of month rows labelled as days. You can declare this on your own columns with the newColumn.granularityfield; SLayer sets it automatically on query-backed models.
Breaking changes
- Saving a model now rejects a derived column or column filter that reaches across a one-to-many join (it is a set of values per row, not a single value; use an aggregation instead) or that loops back to a model already on its path. If SLayer cannot prove whether a join fans out, you get a warning instead.
join_pairsin a model's joins must name declared columns by theirname, not by expression columns or raw physical names. Stored models that use the physical name of a renamed column are migrated automatically when loaded; models that join on undeclared or expression columns need fixing. The Cube, dbt and OSI importers now produce compliant joins.- A column with a
filternow behaves exactly likeCASE WHEN filter THEN value ENDeverywhere, including as a dimension, in filters, inpartition_by=and as an aggregation parameter. time_shift,changeandchange_pcton a plain row column that is not one of the query's dimensions are now rejected (they used to multiply result rows).- A
rank-family transform's ownpartition_by=must be part of the grouping of the value it ranks, and repeating a keyword argument in any call is now an error. - Queries where
partition_by=or afirst/lastordering column would double-count across a one-to-many join now fail with an error naming the join, in everyto_many_handlingmode.
The docs and examples now use the functional aggregation syntax (sum(amount)) throughout; the colon form (amount:sum) still works but is deprecated.