-
-
Notifications
You must be signed in to change notification settings - Fork 181
/
change.ex
83 lines (69 loc) · 2.17 KB
/
change.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
defmodule Ash.Resource.Change do
@moduledoc """
The behaviour for an action-specific resource change.
To implement one, simply implement the behaviour. `c:init/1` is defined automatically
by `use Ash.Resource.Change`, but can be implemented if you want to validate/transform any
options passed to the module.
The main function is `c:change/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.
"""
defstruct [:change, :on]
@doc false
def schema do
[
on: [
type: {:custom, __MODULE__, :on, []},
default: [:create, :update],
doc: """
The action types the validation should run on.
Many validations don't make sense in the context of deletion, so by default it is left out of the list.
"""
],
change: [
type: {:ash_behaviour, Ash.Resource.Change, Ash.Resource.Change.Builtins},
doc: """
The module and options for a change.
""",
required: true
]
]
end
def action_schema do
Keyword.delete(schema(), :on)
end
@doc false
def change({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 change(module) when is_atom(module), do: {:ok, {module, []}}
def change(other) do
{:error, "Expected a module and opts, got: #{inspect(other)}"}
end
@doc false
def on(list) do
list
|> List.wrap()
|> Enum.all?(&(&1 in [:create, :update, :destroy]))
|> case do
true ->
{:ok, List.wrap(list)}
false ->
{:error, "Expected items of [:create, :update, :destroy], got: #{inspect(list)}"}
end
end
@type context :: %{actor: Ash.Resource.record()} | %{}
@callback init(Keyword.t()) :: {:ok, Keyword.t()} | {:error, term}
@callback change(Ash.Changeset.t(), Keyword.t(), context) :: Ash.Changeset.t()
defmacro __using__(_) do
quote do
@behaviour Ash.Resource.Change
def init(opts), do: {:ok, opts}
defoverridable init: 1
end
end
end