#
View Source Ash.Query (ash v2.14.2)

Utilities around constructing/manipulating ash queries.

Ash queries are used for read actions and loads, and ultimately map to queries to a resource's data layer.

Queries are run by calling `read` on an API that contains the resource in question

Examples:

    MyApp.Post
    |> Ash.Query.filter(likes > 10)
    |> Ash.Query.sort([:title])
    |> MyApp.Api.read!()

    MyApp.Author
    |> Ash.Query.aggregate(:published_post_count, :posts, query: [filter: [published: true]])
    |> Ash.Query.sort(published_post_count: :desc)
    |> Ash.Query.limit(10)
    |> MyApp.Api.read!()

    MyApp.Author
    |> Ash.Query.load([:post_count, :comment_count])
    |> Ash.Query.load(posts: [:comments])
    |> MyApp.Api.read!()

# Link to this section Summary

## Types

t()

## Functions

accessing(query, types \\ [:attributes, :relationships, :calculations, :aggregates])

Returns a list of attributes, aggregates, relationships, and calculations that are being loaded

add_error(query, keys \\ [], message)
after_action(query, func)
aggregate(query, name, kind, relationship)

Adds an aggregation to the query.

aggregate(query, name, kind, relationship, opts)
aggregate(query, name, kind, relationship, agg_query, default \\ nil, filterable? \\ true, type \\ nil, constraints \\ [], implementation \\ nil, uniq? \\ false, read_action \\ nil, authorize? \\ true)

Adds an aggregation to the query.

before_action(query, func)
build(resource, api \\ nil, keyword)

Builds a query from a keyword list.

calculate(query, name, module_and_opts, type, context \\ %{}, constraints \\ [])

Adds a calculation to the query.

clear_result(changeset)

Removes a result set previously with `set_result/2`

data_layer_query(ash_query, opts \\ [])

Return the underlying data layer query for an ash query

delete_argument(query, argument_or_arguments)

Remove an argument from the query

deselect(query, fields)

Ensure the the specified attributes are `nil` in the query results.

distinct(query, distincts)

Get results distinct on the provided fields.

distinct_sort(query, sorts, opts \\ [])

Set a sort to determine how distinct records are selected.

ensure_selected(query, fields)

Ensures that the given attributes are selected.

equivalent_to(query, expr)

Determines if the filter statement of a query is equivalent to the provided expression.

equivalent_to?(query, expr)

Same as `equivalent_to/2` but always returns a boolean. `:maybe` returns `false`.

expr(body)

Creates an Ash expression for evaluation later.

fetch_argument(query, argument)

fetches the value of an argument provided to the query or `:error`

filter(query, filter)

Attach a filter statement to the query.

filter_input(query, filter)

Attach a filter statement to the query labelled as user input.

for_read(query, action_name, args \\ %{}, opts \\ [])

Creates a query for a given read action and prepares it.

get_argument(query, argument)

Gets the value of an argument provided to the query

is_expr?(value) deprecated

Returns true if the value is one of the expression structs.

limit(query, limit)

Limit the results returned from the query

load(query, fields)

Loads relationships, calculations, or aggregates on the resource.

load_calculation_as(query, calc_name, as_name, opts_or_args \\ %{}, opts \\ [])

Adds a resource calculation to the query as a custom calculation with the provided name.

load_through(query, type, name, load)

Adds a load statement to the result of an attribute or calculation.

loading?(query, item)

Returns true if the field/relationship or path to field/relationship is being loaded.

lock(query, lock_type)

Lock the query results.

new(resource, api \\ nil, opts \\ [])

Create a new query

offset(query, offset)

Skip the first n records

put_context(query, key, value)

Sets a specific context key to a specific value

select(query, fields, opts \\ [])

Ensure that only the specified attributes are present in the results.

selecting?(query, field)
set_api(query, api)

Set the query's api, and any loaded query's api

set_argument(query, argument, value)

Add an argument to the query, which can be used in filter templates on actions

set_arguments(query, map)

Merge a map of arguments to the arguments list

set_context(query, map)

Merge a map of values into the query context

set_result(changeset, result)

Set the result of the action. This will prevent running the underlying datalayer behavior

set_tenant(query, tenant)
sort(query, sorts, opts \\ [])

Sort the results based on attributes, aggregates or calculations.

struct?(arg1)
subset_of(query, expr)

Determines if the provided expression would return data that is a suprset of the data returned by the filter on the query.

subset_of?(query, expr)

Same as `subset_of/2` but always returns a boolean. `:maybe` returns `false`.

superset_of(query, expr)

Determines if the provided expression would return data that is a subset of the data returned by the filter on the query.

superset_of?(query, expr)

Same as `superset_of/2` but always returns a boolean. `:maybe` returns `false`.

timeout(query, timeout)
to_query(query)

Takes a resource or a query and returns a query.

unload(query, fields)

Removes a field from the list of fields to load

unset(query, keys)

# Link to this section Types

Link to this type

# t()

View Source

    @type t() :: %Ash.Query{
      __validated_for_action__: atom() | nil,
      action: Ash.Resource.Actions.Read.t() | nil,
      action_failed?: boolean(),
      after_action: [
        (t(), [Ash.Resource.record()] ->
           {:ok, [Ash.Resource.record()]}
           | {:ok, [Ash.Resource.record()], [Ash.Notifier.Notification.t()]}
           | {:error, any()})
      ],
      aggregates: %{optional(atom()) => Ash.Filter.t()},
      api: module() | nil,
      arguments: %{optional(atom()) => any()},
      before_action: [(t() -> t())],
      calculations: %{optional(atom()) => :wat},
      context: map(),
      distinct: [atom()],
      distinct_sort: term(),
      errors: [Ash.Error.t()],
      filter: Ash.Filter.t() | nil,
      invalid_keys: term(),
      limit: nil | non_neg_integer(),
      load: keyword(keyword()),
      load_through: term(),
      lock: term(),
      offset: non_neg_integer(),
      params: %{optional(atom() | binary()) => any()},
      phase: :preparing | :before_action | :after_action | :executing,
      resource: module(),
      select: nil | [atom()],
      sort: [atom() | {atom(), :asc | :desc}],
      tenant: any(),
      timeout: pos_integer() | nil,
      valid?: boolean()
    }

# Link to this section Functions

Link to this function

# accessing(query, types \\ [:attributes, :relationships, :calculations, :aggregates])

View Source

Returns a list of attributes, aggregates, relationships, and calculations that are being loaded

Provide a list of field types to narrow down the returned results.

Link to this function

# add_error(query, keys \\ [], message)

View Source
Link to this function

# after_action(query, func)

View Source

    @spec after_action(
      t(),
      (t(), [Ash.Resource.record()] ->
         {:ok, [Ash.Resource.record()]}
         | {:ok, [Ash.Resource.record()], [Ash.Notifier.Notification.t()]}
         | {:error, term()})
    ) :: t()

Link to this function

# aggregate(query, name, kind, relationship)

View Source

Adds an aggregation to the query.

Aggregations are made available on the `aggregates` field of the records returned

The filter option accepts either a filter or a keyword list of options to supply to build a limiting query for that aggregate. See the DSL docs for each aggregate type in `Ash.Resource.Dsl` for more information.

Options:

- query: The query over the destination resource to use as a base for aggregation
- default: The default value to use if the aggregate returns nil
- filterable?: Wether or not this aggregate may be referenced in filters
- type: The type of the aggregate
- constraints: Type constraints for the aggregate's type
- implementation: An implementation used when the aggregate kind is custom
- read_action: The read action to use on the destination resource
- authorize?: Wether or not to authorize access to this aggregate

Link to this function

# aggregate(query, name, kind, relationship, opts)

View Source

    @spec aggregate(
      t() | Ash.Resource.t(),
      atom(),
      Ash.Query.Aggregate.kind(),
      atom() | [atom()],
      t() | Keyword.t() | nil
    ) :: t()

Link to this function

# aggregate(query, name, kind, relationship, agg_query, default \\ nil, filterable? \\ true, type \\ nil, constraints \\ [], implementation \\ nil, uniq? \\ false, read_action \\ nil, authorize? \\ true)

View Source

Adds an aggregation to the query.

Aggregations are made available on the `aggregates` field of the records returned

The filter option accepts either a filter or a keyword list of options to supply to build a limiting query for that aggregate. See the DSL docs for each aggregate type in `Ash.Resource.Dsl` for more information.

Link to this function

# before_action(query, func)

View Source

    @spec before_action(
      t(),
      (t() -> t() | {t(), [Ash.Notifier.Notification.t()]})
    ) :: t()

Link to this function

# build(resource, api \\ nil, keyword)

View Source

    @spec build(Ash.Resource.t(), Ash.Api.t() | nil, Keyword.t()) :: t()

Builds a query from a keyword list.

This is used by certain query constructs like aggregates. It can also be used to manipulate a data structure before passing it to an ash query. It allows for building an entire query struct using only a keyword list.

For example:

    Ash.Query.build(MyResource, filter: [name: "fred"], sort: [name: :asc], load: [:foo, :bar], offset: 10)

If you want to use the expression style filters, you can use `expr/1`.

For example:

    import Ash.Expr, only: [expr: 1]

    Ash.Query.build(Myresource, filter: expr(name == "marge"))

##

options

Options

- `:filter` (`term/0`) - A filter keyword, expression or %Ash.Filter{}

- `:sort` (`term/0`) - A sort list or keyword

- `:distinct_sort` (`term/0`) - A distinct_sort list or keyword

- `:limit` (`integer/0`) - A limit to apply

- `:offset` (`integer/0`) - An offset to apply

- `:load` (`term/0`) - A load statement to add to the query

- `:select` (`term/0`) - A select statement to add to the query

- `:ensure_selected` (`term/0`) - An ensure_selected statement to add to the query

- `:aggregate` (`term/0`) - A custom aggregate to add to the query. Can be `{name, type, relationship}` or `{name, type, relationship, build_opts}`

- `:calculate` (`term/0`) - A custom calculation to add to the query. Can be `{name, module_and_opts}` or `{name, module_and_opts, context}`

- `:distinct` (list of `atom/0`) - A distinct clause to add to the query

- `:context` (`map/0`) - A map to merge into the query context

Link to this function

# calculate(query, name, module_and_opts, type, context \\ %{}, constraints \\ [])

View Source

Adds a calculation to the query.

Calculations are made available on the `calculations` field of the records returned

The `module_and_opts` argument accepts either a `module` or a `{module, opts}`. For more information on what that module should look like, see `Ash.Calculation`.

Link to this function

# clear_result(changeset)

View Source

    @spec clear_result(t()) :: t()

Removes a result set previously with `set_result/2`

Link to this function

# data_layer_query(ash_query, opts \\ [])

View Source

Return the underlying data layer query for an ash query

Link to this function

# delete_argument(query, argument_or_arguments)

View Source

Remove an argument from the query

Link to this function

# deselect(query, fields)

View Source

Ensure the the specified attributes are `nil` in the query results.

Link to this function

# distinct(query, distincts)

View Source

    @spec distinct(t() | Ash.Resource.t(), Ash.Sort.t()) :: t()

Get results distinct on the provided fields.

Takes a list of fields to distinct on. Each call is additive, so to remove the `distinct` use `unset/2`.

Examples:

    Ash.Query.distinct(query, [:first_name, :last_name])

    Ash.Query.distinct(query, :email)

Link to this function

# distinct_sort(query, sorts, opts \\ [])

View Source

Set a sort to determine how distinct records are selected.

If none is set, any sort applied to the query will be used.

This is useful if you want to control how the `distinct` records are selected without affecting (necessarily, it may affect it if there is no sort applied) the overall sort of the query

Link to this function

# ensure_selected(query, fields)

View Source

Ensures that the given attributes are selected.

The first call to `select/2` will limit the fields to only the provided fields. Use `ensure_selected/2` to say "select this field (or these fields) without deselecting anything else".

See `select/2` for more.

Link to this macro

# equivalent_to(query, expr)

View Source (macro)

Determines if the filter statement of a query is equivalent to the provided expression.

This uses the satisfiability solver that is used when solving for policy authorizations. In complex scenarios, or when using custom database expressions, (like fragments in ash_postgres), this function may return `:maybe`. Use `supserset_of?` to always return a boolean.

Link to this macro

# equivalent_to?(query, expr)

View Source (macro)

Same as `equivalent_to/2` but always returns a boolean. `:maybe` returns `false`.

Link to this macro

# expr(body)

View Source (macro)

Creates an Ash expression for evaluation later.

Link to this function

# fetch_argument(query, argument)

View Source

    @spec fetch_argument(t(), atom()) :: {:ok, term()} | :error

fetches the value of an argument provided to the query or `:error`

Link to this macro

# filter(query, filter)

View Source (macro)

Attach a filter statement to the query.

The filter is applied as an "and" to any filters currently on the query. For more information on writing filters, see: `Ash.Filter`.

Link to this function

# filter_input(query, filter)

View Source

Attach a filter statement to the query labelled as user input.

Filters added as user input (or filters constructed with `Ash.Filter.parse_input`) will honor any field policies on resources by replacing any references to the field with `nil` in cases where the actor should not be able to see the given field.

This function does not expect the expression style filter (because an external source could never reasonably provide that). Instead, use the keyword/map style syntax. For example:

`expr(name == "fred")`

could be any of

- map syntax: `%{"name" => %{"eq" => "fred"}}`
- keyword syntax: `[name: [eq: "fred"]]`

See `Ash.Filter` for more.

Link to this function

# for_read(query, action_name, args \\ %{}, opts \\ [])

View Source

Creates a query for a given read action and prepares it.

Multitenancy is not validated until an action is called. This allows you to avoid specifying a tenant until just before calling the api action.

###

arguments

Arguments

Provide a map or keyword list of arguments for the read action

###

opts

Opts

- `:actor` (`term/0`) - set the actor, which can be used in any `Ash.Resource.Change`s configured on the action. (in the `context` argument)

- `:authorize?` (`boolean/0`) - set authorize?, which can be used in any `Ash.Resource.Change`s configured on the action. (in the `context` argument)

- `:tracer` (`atom/0`) - A tracer to use. Will be carried over to the action. For more information see `Ash.Tracer`.

- `:tenant` (`term/0`) - set the tenant on the query

Link to this function

# get_argument(query, argument)

View Source

    @spec get_argument(t(), atom()) :: term()

Gets the value of an argument provided to the query

Link to this function

# is_expr?(value)

View Source
This function is deprecated. use Ash.Filter.TemplateHelpers.expr?/1.

Returns true if the value is one of the expression structs.

Link to this function

# limit(query, limit)

View Source

    @spec limit(t() | Ash.Resource.t(), nil | integer()) :: t()

Limit the results returned from the query

Link to this function

# load(query, fields)

View Source

    @spec load(
      t() | Ash.Resource.t(),
      atom()
      | Ash.Query.Calculation.t()
      | [atom() | Ash.Query.Calculation.t()]
      | [{atom() | Ash.Query.Calculation.t(), term()}]
    ) :: t()

Loads relationships, calculations, or aggregates on the resource.

Currently, loading attributes has no effects, as all attributes are returned. Before long, we will have the default list to load as the attributes, but if you say `load(query, [:attribute1])`, that will be the only field filled in. This will let data layers make more intelligent "select" statements as well.

    # Loading nested relationships
    Ash.Query.load(query, [comments: [:author, :ratings]])

    # Loading relationships with a query
    Ash.Query.load(query, [comments: [author: author_query]])

Link to this function

# load_calculation_as(query, calc_name, as_name, opts_or_args \\ %{}, opts \\ [])

View Source

Adds a resource calculation to the query as a custom calculation with the provided name.

Example:

    Ash.Query.load_calculation_as(query, :calculation, :some_name, args: %{}, load_through: [:foo])

Link to this function

# load_through(query, type, name, load)

View Source

Adds a load statement to the result of an attribute or calculation.

Uses `Ash.Type.load/5` to request that the type load nested data.

Link to this function

# loading?(query, item)

View Source

Returns true if the field/relationship or path to field/relationship is being loaded.

It accepts an atom or a list of atoms, which is treated for as a "path", i.e:

    Resource |> Ash.Query.load(friends: [enemies: [:score]]) |> Ash.Query.loading?([:friends, :enemies, :score])
    iex> true

    Resource |> Ash.Query.load(friends: [enemies: [:score]]) |> Ash.Query.loading?([:friends, :score])
    iex> false

    Resource |> Ash.Query.load(friends: [enemies: [:score]]) |> Ash.Query.loading?(:friends)
    iex> true

Link to this function

# lock(query, lock_type)

View Source

    @spec lock(t() | Ash.Resource.t(), Ash.DataLayer.lock_type()) :: t()

Lock the query results.

This must be run while in a transaction, and is not supported by all data layers.

Link to this function

# new(resource, api \\ nil, opts \\ [])

View Source

Create a new query

Link to this function

# offset(query, offset)

View Source

    @spec offset(t() | Ash.Resource.t(), nil | integer()) :: t()

Skip the first n records

Link to this function

# put_context(query, key, value)

View Source

    @spec put_context(t() | Ash.Resource.t(), atom(), term()) :: t()

Sets a specific context key to a specific value

See `set_context/2` for more information.

Link to this function

# select(query, fields, opts \\ [])

View Source

Ensure that only the specified attributes are present in the results.

The first call to `select/2` will replace the default behavior of selecting all attributes. Subsequent calls to `select/2` will combine the provided fields unless the `replace?` option is provided with a value of `true`.

If a field has been deselected, selecting it again will override that (because a single list of fields is tracked for selection)

Primary key attributes are always selected and cannot be deselected.

When attempting to load a relationship (or manage it with `Ash.Changeset.manage_relationship/3`), if the source field is not selected on the query/provided data an error will be produced. If loading a relationship with a query, an error is produced if the query does not select the destination field of the relationship.

Use `ensure_selected/2` if you wish to make sure a field has been selected, without deselecting any other fields.

Link to this function

# selecting?(query, field)

View Source
Link to this function

# set_api(query, api)

View Source

Set the query's api, and any loaded query's api

Link to this function

# set_argument(query, argument, value)

View Source

Add an argument to the query, which can be used in filter templates on actions

Link to this function

# set_arguments(query, map)

View Source

Merge a map of arguments to the arguments list

Link to this function

# set_context(query, map)

View Source

    @spec set_context(t() | Ash.Resource.t(), map() | nil) :: t()

Merge a map of values into the query context

Link to this function

# set_result(changeset, result)

View Source

    @spec set_result(t(), term()) :: t()

Set the result of the action. This will prevent running the underlying datalayer behavior

Link to this function

# set_tenant(query, tenant)

View Source

    @spec set_tenant(t() | Ash.Resource.t(), String.t()) :: t()

Link to this function

# sort(query, sorts, opts \\ [])

View Source

    @spec sort(t() | Ash.Resource.t(), Ash.Sort.t(), opts :: Keyword.t()) :: t()

Sort the results based on attributes, aggregates or calculations.

Calculations are supported if they are defined with expressions, which can be done one of two ways.

1. with the shorthand `calculate :calc, :type, expr(a + b)`
2. By defining `expression/2` in a custom calculation module

See the guide on calculations for more.

Takes a list of fields to sort on, or a keyword list/mixed keyword list of fields and sort directions. The default sort direction is `:asc`.

Examples:

    Ash.Query.sort(query, [:foo, :bar])

    Ash.Query.sort(query, [:foo, bar: :desc])

    Ash.Query.sort(query, [foo: :desc, bar: :asc])

##

options

Options

- `prepend?` - set to `true` to put your sort at the front of the list of a sort is already specified

Link to this function

# struct?(arg1)

View Source
Link to this macro

# subset_of(query, expr)

View Source (macro)

Determines if the provided expression would return data that is a suprset of the data returned by the filter on the query.

This uses the satisfiability solver that is used when solving for policy authorizations. In complex scenarios, or when using custom database expressions, (like fragments in ash_postgres), this function may return `:maybe`. Use `subset_of?` to always return a boolean.

Link to this macro

# subset_of?(query, expr)

View Source (macro)

Same as `subset_of/2` but always returns a boolean. `:maybe` returns `false`.

Link to this macro

# superset_of(query, expr)

View Source (macro)

Determines if the provided expression would return data that is a subset of the data returned by the filter on the query.

This uses the satisfiability solver that is used when solving for policy authorizations. In complex scenarios, or when using custom database expressions, (like fragments in ash_postgres), this function may return `:maybe`. Use `supserset_of?` to always return a boolean.

Link to this macro

# superset_of?(query, expr)

View Source (macro)

Same as `superset_of/2` but always returns a boolean. `:maybe` returns `false`.

Link to this function

# timeout(query, timeout)

View Source
Link to this function

# to_query(query)

View Source

    @spec to_query(t() | Ash.Resource.t()) :: t()

Takes a resource or a query and returns a query.

Link to this function

# unload(query, fields)

View Source

    @spec unload(t(), [atom()]) :: t()

Removes a field from the list of fields to load

Link to this function

# unset(query, keys)

View Source

    @spec unset(Ash.Resource.t() | t(), atom() | [atom()]) :: t()