View Source Ash.Filter (ash v3.4.21)

The representation of a filter in Ash.

Security Concerns

If you are using a map with string keys, it is likely that you are parsing input. It is important to note that, instead of passing a filter supplied from an external source directly to Ash.Query.filter/2, you should call Ash.Filter.parse_input/2. This ensures that the filter only uses public attributes, relationships, aggregates and calculations, honors field policies and any policies on related resources.

Writing a filter

Built In Predicates

  • is_nil
  • ==
  • !=
  • in
  • <
  • >
  • <=
  • >=
  • &&
  • ||
  • <>
  • /
  • -
  • *
  • +
  • equals (alias for ==)
  • not_equals (alias for !=)
  • gt (alias for >)
  • lt (alias for <)
  • gte (alias for >=)
  • lte (alias for <=)
  • eq (alias for ==)
  • not_eq (alias for !=)
  • less_than (alias for <)
  • greater_than (alias for >)
  • less_than_or_equal (alias for <=)
  • greater_than_or_equal (alias for >=)
  • and (alias for &&)
  • or (alias for ||)
  • concat (alias for <>)
  • div (alias for /)
  • minus (alias for -)
  • times (alias for *)
  • plus (alias for +)

BooleanExpression syntax

The expression syntax ultimately just builds the keyword list style filter, but with lots of conveniences that would be very annoying to do manually.

Examples

Ash.Query.filter(resource, name == "Zardoz")
Ash.Query.filter(resource, first_name == "Zar" and last_name == "Doz")
Ash.Query.filter(resource, first_name == "Zar" and last_name in ["Doz", "Daz"] and high_score > 10)
Ash.Query.filter(resource, first_name == "Zar" or last_name == "Doz" or (high_score > 10 and high_score < -10))

Expressions

More complex filters can be built using Ash Expressions.

Examples

# Filter based on the contents of a string attribute
Ash.Query.filter(Helpdesk.Support.Ticket, contains(subject, "2"))
# Filter based on the attribute of a joined relationship:
Ash.Query.filter(Helpdesk.Support.Ticket, representative.name == ^name)

See the Expressions guide guide for more information.

Keyword list syntax

A filter is a nested keyword list (with some exceptions, like true for everything and false for nothing).

The key is the "predicate" (or "condition") and the value is the parameter. You can use and and or to create nested filters. Data layers can expose custom predicates. Eventually, you will be able to define your own custom predicates, which will be a mechanism for you to attach complex filters supported by the data layer to your queries.

Important In a given keyword list, all predicates are considered to be "ands". So [or: [first_name: "Tom", last_name: "Bombadil"]] doesn't mean 'First name == "tom" or last_name == "bombadil"'. To say that, you want to provide a list of filters, like so: [or: [[first_name: "Tom"], [last_name: "Bombadil"]]]

Some example filters:

Ash.Query.filter(resource, [name: "Zardoz"])
Ash.Query.filter(resource, [first_name: "Zar", last_name: "Doz"])
Ash.Query.filter(resource, [first_name: "Zar", last_name: [in: ["Doz", "Daz"]], high_score: [greater_than: 10]])
Ash.Query.filter(resource, [or: [
  [first_name: "Zar"],
  [last_name: "Doz"],
  [or: [
    [high_score: [greater_than: 10]]],
    [high_score: [less_than: -10]]
  ]
]])

Other formats

Maps are also accepted, as are maps with string keys. Technically, a list of [{"string_key", value}] would also work.

Summary

Functions

Can be used to find a simple equality predicate on an attribute

Find an expression inside of a filter that matches the provided predicate

Can be used to find a simple equality predicate on an attribute

Returns a filter statement that would find a single record based on the input.

Parses a filter statement

Parses a filter statement, accepting only public attributes/relationships, honoring field policies & related resource policies.

Parses a filter statement, accepting only public attributes/relationships, honoring field policies & related resource policies, raising on errors.

Returns true if the second argument is a strict subset (always returns the same or less data) of the first

Transform an expression based filter to a simple filter, which is just a list of predicates

Types

@type t() :: %Ash.Filter{expression: term(), resource: term()}

Functions

Link to this function

add_to_filter(base, addition, op \\ :and, aggregates \\ %{}, calculations \\ %{}, context \\ %{})

View Source
Link to this function

add_to_filter!(base, addition, op \\ :and, aggregates \\ %{}, calculations \\ %{}, context \\ %{})

View Source
Link to this function

builtin_predicate_operators()

View Source
Link to this function

custom_expression(name, args)

View Source
Link to this function

do_hydrate_refs(filter, context)

View Source
Link to this function

fetch_simple_equality_predicate(expression, attribute)

View Source
@spec fetch_simple_equality_predicate(Ash.Expr.t(), atom()) :: {:ok, term()} | :error

Can be used to find a simple equality predicate on an attribute

Use this when your attribute is configured with filterable? :simple_equality, and you want to to find the value that it is being filtered on with (if any).

Link to this function

find(expr, pred, ors? \\ true, ands? \\ true)

View Source

Find an expression inside of a filter that matches the provided predicate

Link to this function

find_simple_equality_predicate(expression, attribute)

View Source

Can be used to find a simple equality predicate on an attribute

Prefer fetch_simple_equality_predicate/2.

Link to this function

flat_map(expression, func)

View Source
Link to this function

get_filter(resource, id)

View Source

Returns a filter statement that would find a single record based on the input.

For example:

iex> get_filter(MyApp.Post, 1)
{:ok, %{id: 1}} #using primary key
iex> get_filter(MyApp.Post, id: 1)
{:ok, %{id: 1}} #using primary key
iex> get_filter(MyApp.Post, author_id: 1, publication_id: 2, first_name: "fred")
{:ok, %{author_id: 1, publication_id: 1}} # using a unique identity
iex> get_filter(MyApp.Post, first_name: "fred")
:error # not enough information
Link to this function

get_function(key, resource, public?)

View Source
Link to this function

get_predicate_function(key, resource, public?)

View Source
Link to this function

hydrate_refs(value, context)

View Source
Link to this function

list_predicates(expression)

View Source
Link to this function

list_refs(expression, no_longer_simple? \\ false, in_an_eq? \\ false, expand_calculations? \\ false, expand_get_path? \\ false)

View Source
Link to this function

move_exprs_to_relationship_path(refs, path)

View Source
Link to this function

move_to_relationship_path(expression, relationship_path)

View Source
Link to this function

parse(resource, statement, context \\ %{})

View Source

Parses a filter statement

See the module documentation for more information on the supported formats for filter statements.

Important

If you are trying to validate a filter supplied from an external/untrusted source, be sure to use parse_input/2 instead! The only difference is that it only accepts filters over public attributes/relationships.

Link to this function

parse!(resource, statement, context \\ %{})

View Source

Parses a filter statement

See parse/2 for more

Link to this function

parse_input(resource, statement)

View Source

Parses a filter statement, accepting only public attributes/relationships, honoring field policies & related resource policies.

See parse/2 for more

Link to this function

parse_input!(resource, statement)

View Source

Parses a filter statement, accepting only public attributes/relationships, honoring field policies & related resource policies, raising on errors.

See parse_input/2 for more

Link to this function

put_at_path(value, list)

View Source
Link to this function

relationship_paths(filter_or_expression, include_exists? \\ false, with_refs? \\ false, expand_aggregates? \\ false)

View Source
Link to this function

run_other_data_layer_filters(domain, resource, filter, tenant)

View Source
Link to this function

strict_subset_of(filter, candidate)

View Source

Returns true if the second argument is a strict subset (always returns the same or less data) of the first

Link to this function

strict_subset_of?(filter, candidate)

View Source
Link to this function

to_simple_filter(map, opts \\ [])

View Source

Transform an expression based filter to a simple filter, which is just a list of predicates

Options:

  • :skip_invalid? (boolean/0) - If an invalid filter expression is reached that can't be used with a simple filter (like an or statement, or a non-predicate expression), it will be ignored instead of raising an error. The default value is false.
Link to this function

update_aggregates(expression, mapper, nested_path \\ [], parent_paths \\ [])

View Source
Link to this function

used_aggregates(filter, relationship_path \\ [], return_refs? \\ false)

View Source
Link to this function

used_calculations(filter, resource, relationship_path \\ [], calculations \\ %{}, aggregates \\ %{}, return_refs? \\ false)

View Source