# `AshScylla.DataLayer.FilterValidator`
[🔗](https://github.com/ohhi-vn/ash_scylla/blob/main/lib/ash_scylla/data_layer/filter_validator.ex#L15)

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

# `queryable_columns`

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

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

# `validate_aggregate_filters`

```elixir
@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`

```elixir
@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_or` - Whether to validate OR filters (default: true)

# `validate_base_filter`

```elixir
@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`

```elixir
@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`

```elixir
@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`

```elixir
@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`

```elixir
@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_or_filters`

```elixir
@spec validate_or_filters(list()) :: :ok | no_return()
```

Validates that filters do not contain cross-field OR expressions.

CQL does not support OR across different fields — the WHERE clause only
allows a flat list of AND-ed predicates.  This validator catches OR
expressions that cannot be rewritten to IN (i.e. OR on different columns
or with non-equality operators) and raises a clear error with workarounds.

# `validate_relationship_filters`

```elixir
@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

---

*Consult [api-reference.md](api-reference.md) for complete listing*
