Ash.Query (ash v1.51.2) View Source

Utilties 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, 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

Functions

Builds a query from a keyword list.

Return the underlying data layer query for an ash query

Remove an argument from the query

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

Get results distinct on the provided fields.

Ensures that the given attributes are selected.

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

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

Creates an Ash expression for evaluation later.

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

Attach a filter statement to the query.

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

Gets the value of an argument provided to the query

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

Limit the results returned from the query

Loads relationships, calculations, or aggregates on the resource.

Skip the first n records

Sets a specific context key to a specific value

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

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

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

Merge a map of arguments to the arguments list

Merge a map of values into the query context

Sort the results based on attributes, aggregates or calculations.

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

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

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

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

Removes a field from the list of fields to load

Link to this section Types

Specs

t() :: %Ash.Query{
  __validated_for_action__: term(),
  action: term(),
  action_failed?: term(),
  after_action: term(),
  aggregates: term(),
  api: term(),
  arguments: term(),
  before_action: term(),
  calculations: term(),
  context: term(),
  distinct: term(),
  errors: term(),
  filter: term(),
  limit: term(),
  load: term(),
  offset: term(),
  params: term(),
  resource: term(),
  select: term(),
  sort: term(),
  tenant: term(),
  valid?: term()
}

Link to this section Functions

Link to this function

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

View Source
Link to this function

after_action(query, func)

View Source

Specs

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, type, relationship, agg_query \\ nil, default \\ nil, filterable? \\ 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

Specs

before_action(
  t(),
  (t() -> t() | {t(), [Ash.Notifier.Notification.t()]})
) :: t()
Link to this function

build(resource, api \\ nil, keyword)

View Source

Specs

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. Be sure to require Ash.Query first, or import it. Consider importing only the expr/1 macro if you do that

For example:

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

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

Supported keys:

  • filter - filter keyword/expr or %Ash.Filter{}
  • sort - sort keyword
  • limit - integer limit
  • offset - integer offset
  • load - keyword/list of atoms to load
  • aggregate - {name, type, relationship}
  • aggregate - {name, type, relationship, query_in_build_format}
  • calculate - {name, module_and_opts}
  • calculate - {name, module_and_opts, context}
  • distinct - list of atoms
  • context: %{key: value}
Link to this function

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

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.

More features for calculations, like passing anonymous functions, will be supported in the future.

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

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

Link to this function

distinct(query, distincts)

View Source

Specs

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

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.

Creates an Ash expression for evaluation later.

Link to this function

fetch_argument(query, argument)

View Source

Specs

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

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

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

Opts

  • :actor - set the actor, which can be used in any Ash.Resource.Changes configured on the action. (in the context argument)

  • :tenant - set the tenant on the query

Link to this function

get_argument(query, argument)

View Source

Specs

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

Gets the value of an argument provided to the query

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

Specs

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

Limit the results returned from the query

Specs

load(t() | Ash.Resource.t(), atom() | [atom()] | Keyword.t()) :: 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

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

View Source

Create a new query

Specs

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

Skip the first n records

Link to this function

put_context(query, key, value)

View Source

Specs

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 simply wish to make sure a field has been selected, without deselecting any other fields.

Link to this function

selecting?(query, field)

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

Specs

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

Merge a map of values into the query context

Link to this function

set_tenant(query, tenant)

View Source

Specs

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

Specs

sort(t() | Ash.Resource.t(), Ash.Sort.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])
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.

Specs

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

Removes a field from the list of fields to load

Specs

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