Skip to content

v1.3.0: Fewer round-trips

Choose a tag to compare

@ZmeiGorynych ZmeiGorynych released this 16 Oct 10:07
82a40b3

SLayer 1.3.0: Fewer round-trips

This release lets more questions fit into a single query.

Combine models with no join path

You can now use aggregates from a model that has no join path to your query's root. For example, rooted at customers, {"formula": "count(events.id) / count(*)"} answers "events per customer" in one query. The unrelated aggregate is computed over all of its own rows, repeated on every result row (or per bucket, if you group by a time_spine time dimension), and flagged with an unrelated_dataset warning. A filter on that model restricts only the rows feeding its aggregates. Grouping, ordering or filtering by its columns alongside another model's columns is still an error, so your result rows never multiply. recommend_root_model now accepts such items too and marks them unrelated.

Clear-intent mistakes just work

Queries whose meaning is obvious but whose spelling isn't canonical now run as intended:

  • count(distinct x) (same as count_distinct(x))
  • the method-call form order_items.count(*)
  • date-part aliases such as isodow(order_date) or day_of_year, and extract(month from order_date)
  • measures named after a transform, such as change
  • an order column given as {"name": "<expression>"}
  • partition_by=[month(order_date)] over a monthly time dimension
  • a refinement that restates a saved measure by name

Ambiguous names like dow and weekday still fail, with an error that names both weekday conventions.

Other changes

Division by zero in a formula now returns NULL on every backend. Calling an unknown function now gives an "Unknown function" error instead of "Unknown aggregation". The MCP tool descriptions now lead with "one question, one query" and say when a multi-stage query is actually needed.

Additional technical details

TagFilteredStorage is renamed to AccessFilteredStorage and moved from slayer.storage.tag_filtered to slayer.storage.access_filtered, with no compatibility alias. ItemPath gains an unrelated: bool field on every recommend_root_model surface. A stage join with empty join_pairs still raises a ValidationError, and its message now points to the aggregate form.