Query building functions for AshScylla data layer.
Provides optimized query building with filter-to-CQL conversion, prepared statement support, token-based pagination, aggregate queries, and support for Ash 3.0+ features including base_filter, select, distinct, keyset pagination, group by, CONTAINS/CONTAINS KEY, and TOKEN() functions.
Secondary Index Support
When filtering on non-primary key columns, this module checks if a secondary index exists and generates appropriate CQL. ScyllaDB/Cassandra can use secondary indexes for equality checks (=) but not for range queries.
Aggregate Queries
Supports COUNT, SUM, AVG, MIN, MAX aggregate functions with optional GROUP BY clauses for per-partition aggregation.
Keyset Pagination
Token-based pagination using the CQL TOKEN() function on partition keys, enabling efficient pagination without OFFSET overhead.
Summary
Functions
Converts aggregate type and field to CQL aggregate expression.
Applies the base_filter from the resource DSL to the query filters.
Builds an aggregate CQL query.
Builds a CONTAINS clause for collection type filtering.
Builds GROUP BY clause for aggregate queries.
Builds keyset pagination clause using TOKEN() function.
Builds an optimized CQL query from the data layer query struct.
Builds ORDER BY clause from sort items.
Builds WHERE clause from Ash filters.
Checks if a filter can use secondary indexes.
Converts Ash filter expressions to CQL (safe version).
Converts Ash filter expressions to CQL (bang version).
Functions
Converts aggregate type and field to CQL aggregate expression.
Applies the base_filter from the resource DSL to the query filters.
The base_filter is prepended to the query filters so it is always applied.
Builds an aggregate CQL query.
Supports COUNT, SUM, AVG, MIN, MAX with optional GROUP BY.
Examples
build_aggregate_query("users", "COUNT(*) AS total", "WHERE status = ?", ["active"])
# => {"SELECT COUNT(*) AS total FROM users WHERE status = ?", ["active"]}
Builds a CONTAINS clause for collection type filtering.
In CQL, CONTAINS is used to check if a collection column contains a value. CONTAINS KEY is used to check if a map column contains a key.
Builds GROUP BY clause for aggregate queries.
Builds keyset pagination clause using TOKEN() function.
Keyset pagination is more efficient than OFFSET for large datasets. It uses the CQL TOKEN() function on partition keys to fetch pages.
Examples
# For a single partition key column:
build_keyset_clause(%{partition_keys: [:id], values: [last_id], direction: :after})
# => {"WHERE TOKEN(id) > TOKEN(?)", [last_id]}
# For composite partition keys:
build_keyset_clause(%{partition_keys: [:org_id, :id], values: [last_org, last_id], direction: :after})
# => {"WHERE TOKEN(org_id, id) > TOKEN(?, ?)", [last_org, last_id]}
@spec build_optimized_query(AshScylla.DataLayer.t()) :: {String.t(), list()}
Builds an optimized CQL query from the data layer query struct.
Supports:
- Column selection (
:select) - DISTINCT on partition key columns
- Keyset pagination (
:keyset) - Aggregate queries (
:aggregates) - GROUP BY for aggregate queries
- Base filter from resource DSL
- Multiple ORDER BY columns
- IN queries with multiple values
- CONTAINS / CONTAINS KEY for collection types
- TOKEN() function for partition key queries
Builds ORDER BY clause from sort items.
Sort items can be:
- Maps with
:fieldand:directionkeys - Tuples like
{field, direction}(Ash standard format) - Bare atoms (default to ASC)
- Maps with only
:fieldkey (default to ASC)
Supports multiple columns for compound ordering.
Builds WHERE clause from Ash filters.
Checks if a filter can use secondary indexes.
Returns {:ok, indexed_columns} if the filter can use indexes,
or {:error, reason} if it cannot.
Converts Ash filter expressions to CQL (safe version).
Returns {cql, params} on success or {:error, {:unknown_filter, term()}} on failure.
Supports:
- Standard comparison operators: eq, not_eq, gt, gte, lt, lte
- IN with list values
- CONTAINS for collection type filtering
- CONTAINS KEY for map key filtering
- TOKEN() function for partition key queries
- EXISTS for existence checks
- AND/OR boolean combinations
- Nested expressions
Converts Ash filter expressions to CQL (bang version).
Raises ArgumentError on unknown filter expressions.