View Source Ash.Policy.FilterCheck behaviour (ash v3.4.46)

A type of check that is represented by a filter statement

That filter statement can be templated, currently only supporting {:_actor, field} which will replace that portion of the filter with the appropriate field value from the actor and {:_actor, :_primary_key} which will replace the value with a keyword list of the primary key fields of an actor to their values, like [id: 1]. If the actor is not present {:_actor, field} becomes nil, and {:_actor, :_primary_key} becomes false.

You can customize what the "negative" filter looks like by defining reject/3. This is important for filters over related data. For example, given an owner relationship and a data layer like ash_postgres where column != NULL does not evaluate to true (see postgres docs on NULL for more):

# The opposite of
`owner.id == 1`
# in most cases is not
`not(owner.id == 1)`
# because in postgres that would be `NOT (owner.id = NULL)` in cases where there was no owner
# A better opposite would be
`owner.id != 1 or is_nil(owner.id)`
# alternatively
`not(owner.id == 1) or is_nil(owner.id)`

By being able to customize the reject filter, you can use related filters in your policies. Without it, they will likely have undesired effects.

Summary

Types

context()

@type context() :: %{
  :action => Ash.Resource.Actions.action(),
  :resource => Ash.Resource.t(),
  :domain => Ash.Domain.t(),
  optional(:query) => Ash.Query.t(),
  optional(:changeset) => Ash.Changeset.t(),
  optional(:action_input) => Ash.ActionInput.t(),
  optional(any()) => any()
}

options()

@type options() :: Keyword.t()

Callbacks

filter(actor, context, options)

@callback filter(actor :: term(), context(), options()) :: Keyword.t() | Ash.Expr.t()

reject(actor, context, options)

(optional)
@callback reject(actor :: term(), context(), options()) :: Keyword.t() | Ash.Expr.t()

Functions

is_filter_check?(module)