mirror of
https://github.com/ash-project/ash.git
synced 2024-09-20 05:23:03 +12:00
improvement: ignore unknown string-keyed inputs beginning with _
improvement: support requesting to ignore additional keys
This commit is contained in:
parent
f8384e44b5
commit
48d8181967
5 changed files with 122 additions and 83 deletions
|
@ -1926,6 +1926,8 @@ defmodule Ash do
|
|||
{:ok, resource} <- Ash.Domain.Info.resource(domain, changeset.resource),
|
||||
{:ok, action} <- Ash.Helpers.get_action(resource, opts, :create, changeset.action) do
|
||||
Ash.Actions.Create.run(domain, changeset, action, opts)
|
||||
else
|
||||
{:error, error} -> {:error, Ash.Error.to_error_class(error)}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -184,9 +184,14 @@ defmodule Ash.ActionInput do
|
|||
}
|
||||
|
||||
Enum.reduce(params, input, fn {name, value}, input ->
|
||||
if has_argument?(input.action, name) do
|
||||
cond do
|
||||
has_argument?(input.action, name) ->
|
||||
set_argument(input, name, value)
|
||||
else
|
||||
|
||||
match?("_" <> _, name) ->
|
||||
input
|
||||
|
||||
true ->
|
||||
error =
|
||||
Ash.Error.Invalid.NoSuchInput.exception(
|
||||
resource: input.resource,
|
||||
|
|
|
@ -28,7 +28,7 @@ defmodule Ash.Actions.Read do
|
|||
def run(query, action, opts) do
|
||||
query = Ash.Query.new(query)
|
||||
|
||||
domain = query.domain || opts[:domain]
|
||||
domain = query.domain || opts[:domain] || Ash.Resource.Info.domain(query.resource)
|
||||
|
||||
if !domain do
|
||||
raise Ash.Error.Framework.AssumptionFailed, message: "got a query without a domain"
|
||||
|
|
|
@ -332,18 +332,15 @@ defmodule Ash.Changeset do
|
|||
|
||||
context = Ash.Resource.Info.default_context(resource) || %{}
|
||||
|
||||
domain = Ash.Resource.Info.domain(resource)
|
||||
|
||||
if Ash.Resource.Info.resource?(resource) do
|
||||
%__MODULE__{resource: resource, data: record, action_type: action_type, domain: domain}
|
||||
%__MODULE__{resource: resource, data: record, action_type: action_type}
|
||||
|> set_context(context)
|
||||
|> set_tenant(tenant)
|
||||
else
|
||||
%__MODULE__{
|
||||
resource: resource,
|
||||
action_type: action_type,
|
||||
data: struct(resource),
|
||||
domain: domain
|
||||
data: struct(resource)
|
||||
}
|
||||
|> add_error(NoSuchResource.exception(resource: resource))
|
||||
|> set_tenant(tenant)
|
||||
|
@ -858,6 +855,9 @@ defmodule Ash.Changeset do
|
|||
{:halt, {:not_atomic, reason}}
|
||||
end
|
||||
|
||||
match?("_" <> _, key) ->
|
||||
{:cont, changeset}
|
||||
|
||||
key in List.wrap(opts[:skip_unknown_inputs]) ->
|
||||
{:cont, changeset}
|
||||
|
||||
|
@ -881,7 +881,8 @@ defmodule Ash.Changeset do
|
|||
{:cont, set_argument(changeset, key, value)}
|
||||
|
||||
attribute = Ash.Resource.Info.attribute(changeset.resource, key) ->
|
||||
if attribute.name in action.accept do
|
||||
cond do
|
||||
attribute.name in action.accept ->
|
||||
case Ash.Type.cast_atomic(attribute.type, value, attribute.constraints) do
|
||||
{:atomic, atomic} ->
|
||||
{:cont, atomic_update(changeset, attribute.name, {:atomic, atomic})}
|
||||
|
@ -892,10 +893,14 @@ defmodule Ash.Changeset do
|
|||
{:not_atomic, reason} ->
|
||||
{:halt, {:not_atomic, reason}}
|
||||
end
|
||||
else
|
||||
if key in List.wrap(opts[:skip_unknown_inputs]) do
|
||||
|
||||
key in List.wrap(opts[:skip_unknown_inputs]) ->
|
||||
{:cont, changeset}
|
||||
else
|
||||
|
||||
match?("_" <> _, key) ->
|
||||
{:cont, changeset}
|
||||
|
||||
true ->
|
||||
{:cont,
|
||||
add_error(
|
||||
changeset,
|
||||
|
@ -907,7 +912,9 @@ defmodule Ash.Changeset do
|
|||
)
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
match?("_" <> _, key) ->
|
||||
{:cont, changeset}
|
||||
|
||||
key in List.wrap(opts[:skip_unknown_inputs]) ->
|
||||
{:cont, changeset}
|
||||
|
@ -1793,9 +1800,14 @@ defmodule Ash.Changeset do
|
|||
Enum.reduce(params, changeset, fn {name, value}, changeset ->
|
||||
cond do
|
||||
!Ash.Resource.Info.action_input?(changeset.resource, action.name, name) ->
|
||||
if name in skip_unknown_inputs do
|
||||
cond do
|
||||
name in skip_unknown_inputs ->
|
||||
changeset
|
||||
else
|
||||
|
||||
match?("_" <> _, name) ->
|
||||
changeset
|
||||
|
||||
true ->
|
||||
add_error(
|
||||
changeset,
|
||||
NoSuchInput.exception(
|
||||
|
@ -1814,9 +1826,14 @@ defmodule Ash.Changeset do
|
|||
if attr.writable? do
|
||||
do_change_attribute(changeset, attr.name, value, true)
|
||||
else
|
||||
if name in skip_unknown_inputs do
|
||||
cond do
|
||||
name in skip_unknown_inputs ->
|
||||
changeset
|
||||
else
|
||||
|
||||
match?("_" <> _, name) ->
|
||||
changeset
|
||||
|
||||
true ->
|
||||
add_error(
|
||||
changeset,
|
||||
NoSuchInput.exception(
|
||||
|
@ -4321,21 +4338,21 @@ defmodule Ash.Changeset do
|
|||
Ash.Type.include_source(attribute.type, changeset, attribute.constraints),
|
||||
{{:ok, prepared}, _} <-
|
||||
{prepare_change(changeset, attribute, value, constraints), value},
|
||||
{:ok, casted} <-
|
||||
Ash.Type.cast_input(
|
||||
{{:ok, casted}, _} <-
|
||||
{Ash.Type.cast_input(
|
||||
attribute.type,
|
||||
prepared,
|
||||
constraints
|
||||
),
|
||||
{:ok, casted} <-
|
||||
handle_change(
|
||||
), prepared},
|
||||
{{:ok, casted}, _} <-
|
||||
{handle_change(
|
||||
changeset,
|
||||
attribute,
|
||||
casted,
|
||||
constraints
|
||||
),
|
||||
{:ok, casted} <-
|
||||
Ash.Type.apply_constraints(attribute.type, casted, constraints) do
|
||||
), casted},
|
||||
{{:ok, casted}, _} <-
|
||||
{Ash.Type.apply_constraints(attribute.type, casted, constraints), casted} do
|
||||
data_value = Map.get(changeset.data, attribute.name)
|
||||
changeset = remove_default(changeset, attribute.name)
|
||||
|
||||
|
|
|
@ -381,7 +381,7 @@ defmodule Ash.Query do
|
|||
|
||||
def new(resource, opts) when is_atom(resource) do
|
||||
query = %__MODULE__{
|
||||
domain: opts[:domain] || Ash.Resource.Info.domain(resource),
|
||||
domain: opts[:domain],
|
||||
filter: nil,
|
||||
resource: resource
|
||||
}
|
||||
|
@ -438,6 +438,11 @@ defmodule Ash.Query do
|
|||
tenant: [
|
||||
type: {:protocol, Ash.ToTenant},
|
||||
doc: "set the tenant on the query"
|
||||
],
|
||||
skip_unknown_inputs: [
|
||||
type: {:list, {:or, [:atom, :string]}},
|
||||
doc:
|
||||
"A list of inputs that, if provided, will be ignored if they are not recognized by the action."
|
||||
]
|
||||
]
|
||||
|
||||
|
@ -508,7 +513,7 @@ defmodule Ash.Query do
|
|||
|> set_authorize?(opts)
|
||||
|> set_tracer(opts)
|
||||
|> set_tenant(opts[:tenant] || query.tenant)
|
||||
|> cast_params(action, args)
|
||||
|> cast_params(action, args, opts)
|
||||
|> set_argument_defaults(action)
|
||||
|> require_arguments(action)
|
||||
|> run_preparations(action, opts[:actor], opts[:authorize?], opts[:tracer], metadata)
|
||||
|
@ -603,11 +608,21 @@ defmodule Ash.Query do
|
|||
end)
|
||||
end
|
||||
|
||||
defp cast_params(query, action, args) do
|
||||
defp cast_params(query, action, args, opts) do
|
||||
skip_unknown_inputs = opts[:skip_unknown_inputs] || []
|
||||
|
||||
Enum.reduce(args, query, fn {name, value}, query ->
|
||||
if has_argument?(action, name) do
|
||||
cond do
|
||||
has_argument?(action, name) ->
|
||||
set_argument(query, name, value)
|
||||
else
|
||||
|
||||
name in skip_unknown_inputs ->
|
||||
query
|
||||
|
||||
match?("_" <> _, name) ->
|
||||
query
|
||||
|
||||
true ->
|
||||
error =
|
||||
Ash.Error.Invalid.NoSuchInput.exception(
|
||||
resource: query.resource,
|
||||
|
|
Loading…
Reference in a new issue