# `BoxTurtle.Schema.Query.Helpers`
[🔗](https://github.com/twajjo/box_turtle/blob/v0.1.0/lib/schema/query/helpers.ex#L1)

Option handling and query assembly used by the functions `BoxTurtle.Schema.Query` generates.

Public so custom query extensions can reuse them; `add_filters/2` in particular is handy for adding
filters to the options an extension receives.

# `add_filters`

```elixir
@spec add_filters(keyword(), keyword()) :: keyword()
```

Merges `filters` into the `:filters` already present in `opts`.

# `aggregate?`

```elixir
@spec aggregate?(keyword()) :: boolean()
```

True when the options request an aggregate (e.g. a count).

# `aggregate_distinction`

```elixir
@spec aggregate_distinction(keyword(), list()) :: [atom()]
```

The columns to count distinctly in an aggregate (sort directions dropped).

# `aggregate_query!`

```elixir
@spec aggregate_query!(Ecto.Queryable.t(), :count, module(), keyword()) ::
  Ecto.Query.t()
```

Builds an aggregate query. Only `:count` is supported.

# `aggregate_result!`

```elixir
@spec aggregate_result!(Ecto.Queryable.t(), :count, [atom()], module(), keyword()) ::
  integer() | [map()]
```

Runs an aggregate query: a single integer without grouping, otherwise a list of maps holding the grouped
columns and `:count`.

# `aggregation`

```elixir
@spec aggregation(keyword()) :: atom() | nil
```

The `:aggregate` option, or nil.

# `build_listings!`

```elixir
@spec build_listings!(Ecto.Queryable.t(), module(), list(), keyword(), pos_integer()) ::
  Ecto.Queryable.t()
```

Applies sorting and pagination.

# `build_query!`

```elixir
@spec build_query!(Ecto.Queryable.t(), module(), keyword()) :: Ecto.Queryable.t()
```

Applies grouping and filters.

# `distinct_on!`

```elixir
@spec distinct_on!(list(), module()) :: list()
```

Returns the `:distinct` `columns` unchanged if `repo`'s adapter supports `DISTINCT ON`, and raises
`ArgumentError` if it is known not to (SQLite3, MyXQL, Tds). The adapter would otherwise only fail
once the query runs.

Counts are not affected: `count(distinct: ...)` uses `COUNT(DISTINCT column)`, which every adapter supports.

# `get_opt`

```elixir
@spec get_opt(keyword(), atom(), any(), any()) :: any()
```

Fetches a call-time option, falling back to `module_default`, or to `no_default_value` when the
`ignore_defaults: true` option is set.

# `group`

```elixir
@spec group(Ecto.Queryable.t(), nil | atom() | String.t() | [atom() | String.t()]) ::
  Ecto.Queryable.t()
```

Adds `group_by` clauses. String column names must already exist as atoms.

# `grouping`

```elixir
@spec grouping(keyword()) :: list()
```

The `:group_by` columns.

# `ignore_defaults?`

```elixir
@spec ignore_defaults?(keyword()) :: boolean()
```

True when the `ignore_defaults: true` option is set.

# `joining`

```elixir
@spec joining(list(), keyword()) :: list()
```

The associations to preload.

# `paging`

```elixir
@spec paging(keyword()) :: BoxTurtle.Schema.Pagination.page_spec()
```

The `:page` option (see `BoxTurtle.Schema.Pagination`).

# `preloads`

```elixir
@spec preloads(Ecto.Queryable.t(), nil | atom() | list(), atom()) ::
  Ecto.Queryable.t()
```

Preloads associations through `LEFT JOIN`s, so rows and their associations come back from the
database in a single query instead of one extra query per association.

`assocs` takes the usual preload shapes, nested to any depth: `:author`, `[:author, :tags]`,
`[author: [:company], comments: :user]`. Duplicates are merged.

Joining a to-many association repeats each parent row once per child, so `LIMIT`, `OFFSET` and
`DISTINCT` would count child rows. When the query has any of them, they are applied in a subquery
selecting `primary_key`, and the joins are made against that selection.

# `query_distinction`

```elixir
@spec query_distinction(keyword(), list()) :: list()
```

The `:distinct` columns for list queries.

# `sorting`

```elixir
@spec sorting(list(), keyword()) :: list()
```

The sort specification.

# `unique`

```elixir
@spec unique(Ecto.Queryable.t(), nil | atom() | list()) :: Ecto.Queryable.t()
```

Adds a `distinct` clause.

# `where_key`

```elixir
@spec where_key(Ecto.Queryable.t(), term(), atom()) :: Ecto.Query.t()
```

Restricts the query to one key: a single value for `primary_key`, or a map/keyword list of
column values for composite keys.

---

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