defmodule Ash.Resource.Preparation do
@moduledoc """
The behaviour for an action-specific query preparation.
`c:init/1` is defined automatically by `use Ash.Resource.Preparation`, but can be implemented if you want to validate/transform any
options passed to the module.
The main function is `c:prepare/3`. It takes the changeset, any options that were provided
when this change was configured on a resource, and the context, which currently only has
the actor.
To access any query arguments from within a preparation, make sure you are using `Ash.Query.get_argument/2`
as the argument keys may be strings or atoms.
"""
defstruct [:preparation]
@type t :: %__MODULE__{}
@type ref :: {module(), Keyword.t()} | module()
@doc false
def schema do
[
preparation: [
type:
{:spark_function_behaviour, Ash.Resource.Preparation, Ash.Resource.Preparation.Builtins,
{Ash.Resource.Preparation.Function, 2}},
doc: """
The module and options for a preparation.
Also accepts functions take the query and the context.
""",
required: true
]
]
end
@doc false
def preparation({module, opts}) when is_atom(module) do
if Keyword.keyword?(opts) do
{:ok, {module, opts}}
else
{:error, "Expected opts to be a keyword, got: #{inspect(opts)}"}
end
end
def preparation(module) when is_atom(module), do: {:ok, {module, []}}
def preparation(other) do
{:error, "Expected a module and opts, got: #{inspect(other)}"}
end
@type context :: %{
optional(:actor) => Ash.Resource.record(),
optional(any) => any
}
@callback init(Keyword.t()) :: {:ok, Keyword.t()} | {:error, term}
@callback prepare(query, Keyword.t(), context) :: query when query: struct
defmacro __using__(_) do
quote do
@behaviour Ash.Resource.Preparation
def init(opts), do: {:ok, opts}
defoverridable init: 1
end
end
end