defmodule Ash.Resource.Transformers.DefaultAccept do
@moduledoc "Sets the default `accept` for each action"
use Spark.Dsl.Transformer
alias Spark.Dsl.Transformer
def transform(dsl_state) do
public_attribute_names =
dsl_state
|> Transformer.get_entities([:attributes])
|> Enum.reject(& &1.private?)
|> Enum.map(& &1.name)
default_accept =
Transformer.get_option(
dsl_state,
[:actions],
:default_accept
) || public_attribute_names
dsl_state
|> Transformer.get_entities([:actions])
|> Enum.reduce({:ok, dsl_state}, fn
%{type: :read}, {:ok, _dsl_state} = acc ->
acc
action, {:ok, dsl_state} ->
if is_list(action.accept) && is_list(action.reject) &&
!MapSet.disjoint?(MapSet.new(action.accept), MapSet.new(action.reject)) do
raise Spark.Error.DslError,
path: [:actions, action.name],
message: "accept and reject keys cannot overlap"
end
{accept, reject} =
case {action.accept, action.reject} do
{_, :all} ->
{[], public_attribute_names}
{nil, reject} ->
{reject(if(action.type != :destroy, do: default_accept, else: []), reject), reject}
{:all, reject} ->
{reject(public_attribute_names, reject), reject}
{accept, reject} ->
{reject(accept, reject), reject}
end
new_dsl_state =
Transformer.replace_entity(
dsl_state,
[:actions],
%{action | accept: accept, reject: reject},
&(&1.name == action.name && &1.type == action.type)
)
{:ok, new_dsl_state}
end)
end
defp reject(list, reject) do
Enum.reject(list, &(&1 in reject))
end
def after?(Ash.Resource.Transformers.BelongsToSourceField), do: true
def after?(Ash.Resource.Transformers.BelongsToAttribute), do: true
def after?(Ash.Resource.Transformers.CreateJoinRelationship), do: true
def after?(Ash.Resource.Transformers.ValidatePrimaryActions), do: true
def after?(_), do: false
end