Ash.Query.Function behaviour (ash v3.33.9)

Copy Markdown View Source

A function is a predicate with an arguments list.

For more information on being a predicate, see Ash.Filter.Predicate. Most of the complexities are there. A function must meet both behaviours.

Summary

Callbacks

The number and types of arguments supported.

Whether or not the function return nil.

Whether or not the function can be evaluated eagerly. For example, now() cannot be.

Evaluate a function when all arguments are known valid values

If true, will be allowed to evaluate nil inputs.

The name of the function

Instantiate a new function with the provided arguments

Evaluate a function when some or no arguments are known valid values

Whether or not the function is a predicate (takes a reference as the first argument, a value as the second, and returns a boolean)

Whether or not the function should be usable when parsing input.

The return type for each corresponding set of args.

Functions

Whether an expression's type is compatible with a declared argument type.

Evaluate the operator with provided inputs

Attaches the appropriate suffix to refer to an ordinal number, e.g 1 -> "1st"

Casts args to a single declared signature, returning the cast list or nil.

Types

arg()

@type arg() :: any()

Callbacks

args()

@callback args() :: [arg()] | :var_args

The number and types of arguments supported.

can_return_nil?(func)

@callback can_return_nil?(func :: map()) :: boolean()

Whether or not the function return nil.

eager_evaluate?()

@callback eager_evaluate?() :: boolean()

Whether or not the function can be evaluated eagerly. For example, now() cannot be.

evaluate(func)

@callback evaluate(func :: map()) :: :unknown | {:known, term()} | {:error, term()}

Evaluate a function when all arguments are known valid values

evaluate_nil_inputs?()

@callback evaluate_nil_inputs?() :: boolean()

If true, will be allowed to evaluate nil inputs.

If false (the default), any nil inputs will cause a nil return.

name()

@callback name() :: atom()

The name of the function

new(list)

@callback new([term()]) :: {:ok, term()} | {:error, String.t() | Exception.t()}

Instantiate a new function with the provided arguments

partial_evaluate(func)

(optional)
@callback partial_evaluate(func) :: {:ok, func} | {:error, term()} when func: map()

Evaluate a function when some or no arguments are known valid values

predicate?()

@callback predicate?() :: boolean()

Whether or not the function is a predicate (takes a reference as the first argument, a value as the second, and returns a boolean)

private?()

@callback private?() :: boolean()

Whether or not the function should be usable when parsing input.

returns()

@callback returns() ::
  [Ash.Type.t() | {Ash.Type.t(), constraints :: Keyword.t()}]
  | Ash.Type.t()
  | {Ash.Type.t(), constraints :: Keyword.t()}
  | :unknown

The return type for each corresponding set of args.

Functions

compatible_expr_type?(expr, vague)

@spec compatible_expr_type?(term(), term()) :: boolean()

Whether an expression's type is compatible with a declared argument type.

Vague declarations (:any, :same and their array forms) accept anything. A concrete declaration matches when the expression's type, as resolved by Ash.Expr.determine_type/1, is that type or acts as it: a NewType acts as its subtype_of, and any type may name another via Ash.Type.acts_as/1 (an :atom acts as a :string, an embedded resource acts as a :map, and so on), recursively. Functions should therefore declare the most general type they accept: datetime_add/3 declares :datetime, so any datetime NewType such as :utc_datetime_usec is accepted. An expression whose type cannot be determined is considered compatible, as there is no evidence against it.

evaluate(func)

Evaluate the operator with provided inputs

new(mod, args)

ordinal(num)

Attaches the appropriate suffix to refer to an ordinal number, e.g 1 -> "1st"

try_cast_arguments(configured_args, args, opts \\ [])

Casts args to a single declared signature, returning the cast list or nil.

With exact?: true, a value only fits a declared type if casting leaves it unchanged, so signatures are matched on the type the value already has.