# `Selecto.Expr`

Ergonomic constructors for Selecto filter and selector AST.

This module returns the tuple and list shapes that Selecto already accepts,
making dynamic query composition easier without introducing a new execution
path.

# `expr`

```elixir
@type expr() :: term()
```

A helper expression that normalizes into Selecto's existing AST.

# `and`

Builds an `AND` filter group.

# `append_filter`

```elixir
@spec append_filter(Selecto.Types.t(), term()) :: Selecto.Types.t()
```

Appends a filter when a normalized filter is present.

# `append_group_by`

```elixir
@spec append_group_by(Selecto.Types.t(), term()) :: Selecto.Types.t()
```

Appends a group-by expression when present.

# `append_order_by`

```elixir
@spec append_order_by(Selecto.Types.t(), term()) :: Selecto.Types.t()
```

Appends an order-by expression when present.

# `append_select`

```elixir
@spec append_select(Selecto.Types.t(), term()) :: Selecto.Types.t()
```

Appends a selector when a normalized selector is present.

# `array_contained`

```elixir
@spec array_contained(term(), [term()]) :: tuple()
```

Builds an array contained-by filter.

# `array_contains`

```elixir
@spec array_contains(term(), [term()]) :: tuple()
```

Builds an array contains filter.

# `array_eq`

```elixir
@spec array_eq(term(), [term()]) :: tuple()
```

Builds an array equality filter.

# `array_overlap`

```elixir
@spec array_overlap(term(), [term()]) :: tuple()
```

Builds an array overlap filter.

# `as`

```elixir
@spec as(term(), String.t() | atom()) :: tuple()
```

Adds an alias to any selector expression.

# `asc`

```elixir
@spec asc(term()) :: tuple()
```

Builds an ascending order spec.

# `asc_nulls_first`

```elixir
@spec asc_nulls_first(term()) :: tuple()
```

Builds an ascending order spec with nulls first.

# `asc_nulls_last`

```elixir
@spec asc_nulls_last(term()) :: tuple()
```

Builds an ascending order spec with nulls last.

# `avg`

```elixir
@spec avg(term()) :: tuple()
```

Builds an `AVG(...)` selector.

# `between`

```elixir
@spec between(term(), term(), term()) :: tuple()
```

Builds a `BETWEEN` filter.

# `boolean_search`

```elixir
@spec boolean_search(term(), term() | keyword(), keyword()) :: tuple()
```

Builds a shared boolean/operator text search filter.

# `case_when`

```elixir
@spec case_when([{term(), term()}], term()) :: tuple()
```

Builds a CASE expression using `{filter, result}` pairs.

# `coalesce`

```elixir
@spec coalesce([term()]) :: tuple()
```

Builds a `COALESCE(...)` selector.

# `compact_and`

```elixir
@spec compact_and([term()]) :: term() | nil
```

Drops nil/empty fragments and wraps the remainder in an `AND` group.

# `compact_or`

```elixir
@spec compact_or([term()]) :: term() | nil
```

Drops nil/empty fragments and wraps the remainder in an `OR` group.

# `concat`

```elixir
@spec concat([term()]) :: tuple()
```

Builds a `CONCAT(...)` selector.

# `contains`

```elixir
@spec contains(term(), term()) :: tuple()
```

Builds a contains filter using Selecto's existing `:contains` operator.

# `count`

```elixir
@spec count(term()) :: tuple()
```

Builds `COUNT(*)` or `COUNT(field)` selectors.

# `count_distinct`

```elixir
@spec count_distinct(term()) :: tuple()
```

Builds `COUNT(DISTINCT ...)` selectors.

# `desc`

```elixir
@spec desc(term()) :: tuple()
```

Builds a descending order spec.

# `desc_nulls_first`

```elixir
@spec desc_nulls_first(term()) :: tuple()
```

Builds a descending order spec with nulls first.

# `desc_nulls_last`

```elixir
@spec desc_nulls_last(term()) :: tuple()
```

Builds a descending order spec with nulls last.

# `ends_with`

```elixir
@spec ends_with(term(), String.t()) :: tuple()
```

Builds a suffix `LIKE` filter.

# `eq`

```elixir
@spec eq(term(), term()) :: tuple()
```

Builds an equality filter.

# `exists`

```elixir
@spec exists(term(), [term()]) :: tuple()
```

Builds an `EXISTS (...)` filter.

# `field`

```elixir
@spec field(term()) :: tuple()
```

Wraps a field reference or selector expression.

# `field_exists`

```elixir
@spec field_exists(term()) :: tuple()
```

Builds a field-path existence filter for JSONB paths or non-null fields.

# `frame`

```elixir
@spec frame(:rows | :range, term(), term()) :: tuple()
```

Builds a frame tuple for window expressions.

# `func`

```elixir
@spec func(String.t(), term()) :: tuple()
```

Builds a generic function selector.

# `greatest`

```elixir
@spec greatest([term()] | term(), term() | nil) :: tuple()
```

Builds a `GREATEST(...)` selector.

# `grouping_set`

```elixir
@spec grouping_set(term()) :: tuple()
```

Builds a composite grouping element for use inside `ROLLUP(...)`.

# `gt`

```elixir
@spec gt(term(), term()) :: tuple()
```

Builds a greater-than filter.

# `gte`

```elixir
@spec gte(term(), term()) :: tuple()
```

Builds a greater-than-or-equal filter.

# `ilike`

```elixir
@spec ilike(term(), term()) :: tuple()
```

Builds an `ILIKE` filter.

# `in`

Builds an `IN (...)` filter.

# `is_null`

```elixir
@spec is_null(term()) :: tuple()
```

Builds an `IS NULL` filter.

# `json_agg`

Builds a JSON aggregate tuple for `Selecto.json_select/2`.

# `json_contains`

```elixir
@spec json_contains(term(), term()) :: tuple()
```

Builds a JSON contains filter for `Selecto.json_filter/2`.

# `json_extract`

Builds a JSON extract tuple for `Selecto.json_select/2` or `Selecto.json_order_by/2`.

# `json_extract_text`

Builds a JSON text extract tuple for `Selecto.json_select/2` or `Selecto.json_order_by/2`.

# `json_object_agg`

Builds a JSON object aggregate tuple for `Selecto.json_select/2`.

# `json_path_exists`

```elixir
@spec json_path_exists(term(), term()) :: tuple()
```

Builds a JSON path-exists filter for `Selecto.json_filter/2`.

# `least`

```elixir
@spec least([term()] | term(), term() | nil) :: tuple()
```

Builds a `LEAST(...)` selector.

# `like`

```elixir
@spec like(term(), term()) :: tuple()
```

Builds a `LIKE` filter.

# `lit`

```elixir
@spec lit(term()) :: tuple()
```

Wraps a literal selector value.

# `lt`

```elixir
@spec lt(term(), term()) :: tuple()
```

Builds a less-than filter.

# `lte`

```elixir
@spec lte(term(), term()) :: tuple()
```

Builds a less-than-or-equal filter.

# `match_against`

```elixir
@spec match_against(term(), term() | keyword(), keyword()) :: tuple()
```

Builds a MySQL-oriented full-text search filter that maps onto `:text_search`.

# `max`

```elixir
@spec max(term()) :: tuple()
```

Builds a `MAX(...)` selector.

# `maybe`

```elixir
@spec maybe(term(), (term() -&gt; term())) :: term() | nil
```

Alias for `when_present/2`.

# `maybe_group_by`

```elixir
@spec maybe_group_by(Selecto.Types.t(), term(), (term() -&gt; term())) ::
  Selecto.Types.t()
```

Conditionally appends a group-by expression when the value is present.

# `maybe_order_by`

```elixir
@spec maybe_order_by(Selecto.Types.t(), term(), (term() -&gt; term())) ::
  Selecto.Types.t()
```

Conditionally appends an order-by expression when the value is present.

# `merge_where`

```elixir
@spec merge_where(Selecto.Types.t(), [term()]) :: Selecto.Types.t()
```

Compacts a list of filters with `AND` semantics and appends it to the query.

# `min`

```elixir
@spec min(term()) :: tuple()
```

Builds a `MIN(...)` selector.

# `neq`

```elixir
@spec neq(term(), term()) :: tuple()
```

Builds a not-equal filter.

# `normalize`

```elixir
@spec normalize(expr()) :: term()
```

Normalizes helper-friendly expression forms into Selecto AST.

# `not`

Builds a negated filter.

# `not_in`

```elixir
@spec not_in(term(), [term()]) :: tuple()
```

Builds a `NOT IN (...)` filter.

# `not_null`

```elixir
@spec not_null(term()) :: tuple()
```

Builds an `IS NOT NULL` filter.

# `nullif`

```elixir
@spec nullif(term(), term()) :: tuple()
```

Builds a `NULLIF(...)` selector.

# `or`

Builds an `OR` filter group.

# `phrase_search`

```elixir
@spec phrase_search(term(), term() | keyword(), keyword()) :: tuple()
```

Builds a shared phrase-intent text search filter.

# `pipe_if`

```elixir
@spec pipe_if(term(), term(), (term() -&gt; term())) :: term()
```

Conditionally applies a query pipeline function.

# `plain_search`

```elixir
@spec plain_search(term(), term() | keyword(), keyword()) :: tuple()
```

Builds a shared plain-token text search filter.

# `rollup`

```elixir
@spec rollup(term()) :: keyword()
```

Builds a `GROUP BY ROLLUP(...)` keyword spec.

# `starts_with`

```elixir
@spec starts_with(term(), String.t()) :: tuple()
```

Builds a prefix `LIKE` filter.

# `stddev`

```elixir
@spec stddev(term()) :: tuple()
```

Builds a `STDDEV(...)` selector.

# `subquery_in`

```elixir
@spec subquery_in(term(), term(), [term()]) :: tuple()
```

Builds a field `IN (subquery)` filter.

# `sum`

```elixir
@spec sum(term()) :: tuple()
```

Builds a `SUM(...)` selector.

# `text_search`

```elixir
@spec text_search(term(), term() | keyword(), keyword()) :: tuple()
```

Builds a full-text search filter using Selecto's `:text_search` operator.

# `udf`

```elixir
@spec udf(String.t() | atom(), term()) :: tuple()
```

Builds a registered UDF selector or predicate expression.

# `variance`

```elixir
@spec variance(term()) :: tuple()
```

Builds a `VARIANCE(...)` selector.

# `web_search`

```elixir
@spec web_search(term(), term() | keyword(), keyword()) :: tuple()
```

Builds a shared web-style text search filter.

# `when_present`

```elixir
@spec when_present(term(), (term() -&gt; term())) :: term() | nil
```

Builds an expression only when the value is present.

# `window`

```elixir
@spec window(atom(), term(), keyword()) :: tuple()
```

Builds a window-function selector for `Selecto.select/2`.

---

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