BoxTurtle.Schema.Query.Helpers (BoxTurtle v0.1.0)

Copy Markdown View Source

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.

Summary

Functions

Merges filters into the :filters already present in opts.

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

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

Builds an aggregate query. Only :count is supported.

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

The :aggregate option, or nil.

Applies grouping and filters.

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.

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

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

The :group_by columns.

True when the ignore_defaults: true option is set.

The associations to preload.

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

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

The :distinct columns for list queries.

The sort specification.

Adds a distinct clause.

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

Functions

add_filters(opts, filters)

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

Merges filters into the :filters already present in opts.

aggregate?(opts)

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

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

aggregate_distinction(opts, default_distinct \\ [])

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

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

aggregate_query!(query, atom, filter_module, opts)

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

Builds an aggregate query. Only :count is supported.

aggregate_result!(query, atom, grouping, repo, opts)

@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(opts)

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

The :aggregate option, or nil.

build_listings!(query, sorting_module, default_sort, opts, page_size \\ default_page_size())

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

Applies sorting and pagination.

build_query!(query, filter_module, opts \\ [])

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

Applies grouping and filters.

distinct_on!(columns, repo)

@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(opts, option, module_default, no_default_value)

@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(query, column)

@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(opts)

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

The :group_by columns.

ignore_defaults?(opts)

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

True when the ignore_defaults: true option is set.

joining(default_preloads, opts)

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

The associations to preload.

paging(opts)

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

preloads(query, assocs, primary_key \\ :id)

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

Preloads associations through LEFT JOINs, 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(opts, default_distinct \\ [])

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

The :distinct columns for list queries.

sorting(default_sort, opts)

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

The sort specification.

unique(query, columns)

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

Adds a distinct clause.

where_key(query, key, primary_key)

@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.