AshScylla.DataLayer.FilterValidator (AshScylla v0.7.0)

Copy Markdown View Source

Validates that filter columns are queryable in ScyllaDB/Cassandra.

ScyllaDB/Cassandra requires that WHERE clause columns are either:

  • Part of the primary key
  • Have a secondary index defined

Filtering on non-indexed columns would require ALLOW FILTERING, which is an anti-pattern that causes full cluster scans. This module catches such issues at query-build time and provides actionable error messages.

Ash 3.0+ Support

This validator supports:

  • Aggregate filter validation (COUNT, SUM, AVG, MIN, MAX)
  • Calculation filter validation
  • Relationship filter validation (belongs_to, has_one, has_many, many_to_many)
  • EXISTS filter type
  • IN filter with list values
  • Base filter validation
  • Ash error type integration for better error messages

Summary

Functions

Returns the list of columns that are safe to filter on for a resource.

Validates aggregate filters for a resource.

Comprehensive validation that runs all filter validators.

Validates base_filter expressions from the resource DSL.

Validates calculation filters for a resource.

Validates EXISTS filter expressions.

Validates that all filter columns on a resource are queryable.

Validates IN filter expressions with list values.

Validates relationship filters for a resource.

Functions

queryable_columns(resource)

@spec queryable_columns(module()) :: [atom()]

Returns the list of columns that are safe to filter on for a resource.

validate_aggregate_filters(resource, aggregates)

@spec validate_aggregate_filters(module(), list()) :: :ok | no_return()

Validates aggregate filters for a resource.

Ensures that aggregate queries reference valid columns and that the aggregate type is supported by ScyllaDB.

Supported aggregate types: :count, :sum, :avg, :min, :max

Parameters

  • resource - The Ash resource module
  • aggregates - List of aggregate maps with :type, :name, and optional :field keys

Examples

FilterValidator.validate_aggregate_filters(MyApp.User, [%{type: :count, name: :total}])
# => :ok

FilterValidator.validate_aggregate_filters(MyApp.User, [%{type: :sum, name: :total_age, field: :age}])
# => :ok

validate_all(resource, filters, opts \\ [])

@spec validate_all(module(), list(), keyword()) :: :ok | no_return()

Comprehensive validation that runs all filter validators.

This is the recommended entry point for validating all aspects of a query against a resource.

Parameters

  • resource - The Ash resource module
  • filters - List of Ash filter expressions
  • opts - Keyword list of options:
    • :aggregates - List of aggregate maps
    • :calculations - List of calculation maps
    • :validate_base - Whether to validate the base_filter (default: true)
    • :validate_relationships - Whether to validate relationship filters (default: true)
    • :validate_exists - Whether to validate EXISTS filters (default: true)
    • :validate_in - Whether to validate IN filters (default: true)

validate_base_filter(resource)

@spec validate_base_filter(module()) :: :ok | no_return()

Validates base_filter expressions from the resource DSL.

Ensures that the base_filter references valid columns and that those columns are queryable (primary key or indexed).

Parameters

  • resource - The Ash resource module

validate_calculation_filters(resource, calculations)

@spec validate_calculation_filters(module(), list()) :: :ok | no_return()

Validates calculation filters for a resource.

Ensures that calculation expressions reference valid attributes and that the calculation module (if specified) exists and implements the required behaviour.

Parameters

  • resource - The Ash resource module
  • calculations - List of calculation maps with :name, :type, and :expression keys

validate_exists_filters(resource, filters)

@spec validate_exists_filters(module(), list()) :: :ok | no_return()

Validates EXISTS filter expressions.

EXISTS filters check for the presence of a value (IS NOT NULL in CQL). This is valid for any column that exists on the resource.

Parameters

  • resource - The Ash resource module
  • filters - List of filter expressions that may include EXISTS checks

validate_filters(resource, filters)

@spec validate_filters(module(), list()) :: :ok | no_return()

Validates that all filter columns on a resource are queryable.

Returns :ok if all filters are on primary key columns or indexed columns. Raises AshScylla.Error with an actionable message if a filter would require ALLOW FILTERING.

Parameters

  • resource - The Ash resource module
  • filters - List of Ash filter expressions

Examples

AshScylla.DataLayer.FilterValidator.validate_filters(MyApp.User, filters)
# => :ok

AshScylla.DataLayer.FilterValidator.validate_filters(MyApp.User, [{:non_indexed_col, :eq, "value"}])
# => raises AshScylla.Error with suggestion to add secondary_index

validate_in_filters(resource, filters)

@spec validate_in_filters(module(), list()) :: :ok | no_return()

Validates IN filter expressions with list values.

IN filters are valid when:

  • The column is a primary key or indexed
  • The value list is not empty
  • All values in the list are of a compatible type

Parameters

  • resource - The Ash resource module
  • filters - List of filter expressions that may include IN checks

validate_relationship_filters(resource, filters)

@spec validate_relationship_filters(module(), list()) :: :ok | no_return()

Validates relationship filters for a resource.

Ensures that relationship filters reference valid relationships and that the relationship target columns are queryable.

Parameters

  • resource - The Ash resource module
  • filters - List of filter expressions that may reference relationships

Examples

FilterValidator.validate_relationship_filters(MyApp.Post, [%{path: [:author, :name], op: :eq, value: "Alice"}])
# => :ok if :author is a valid belongs_to relationship