improvement: improve the behavior of defaults

functional defaults are added at action time, others are added directly
into the changeset
This commit is contained in:
Zach Daniel 2021-03-17 22:34:49 -04:00
parent d4b27d5d4e
commit f3c85da268
5 changed files with 28 additions and 33 deletions

View file

@ -76,7 +76,7 @@ defmodule Ash.Actions.Create do
else
Ash.Changeset.for_create(changeset, action.name, %{}, actor: actor)
end
|> Ash.Changeset.set_defaults(:create)
|> Ash.Changeset.set_defaults(:create, true)
|> Ash.Changeset.cast_arguments(action)
end

View file

@ -74,7 +74,7 @@ defmodule Ash.Actions.Update do
else
Ash.Changeset.for_update(changeset, action.name, %{}, actor: actor)
end
|> Ash.Changeset.set_defaults(:update)
|> Ash.Changeset.set_defaults(:update, true)
|> Ash.Changeset.cast_arguments(action)
end

View file

@ -280,11 +280,6 @@ defmodule Ash.Changeset do
tenant: [
type: :any,
doc: "set the tenant on the changeset"
],
defaults: [
type: :any,
doc:
"A list of attributes and arguments to apply defaults for. Defaults to: []. Any unset defaults are set when the action is called."
]
]
@ -450,7 +445,7 @@ defmodule Ash.Changeset do
|> validate_relationships_accepted(action)
|> cast_arguments(action, opts[:defaults], true)
|> run_action_changes(action, opts[:actor])
|> set_defaults(changeset.action_type, opts[:defaults] || [])
|> set_defaults(changeset.action_type, false)
|> add_validations()
|> require_values(changeset.action_type)
|> mark_validated(action.name)
@ -585,13 +580,16 @@ defmodule Ash.Changeset do
end
@doc false
def set_defaults(changeset, action_type, keys \\ :all)
def set_defaults(changeset, action_type, lazy? \\ false)
def set_defaults(changeset, :create, keys) do
def set_defaults(changeset, :create, lazy?) do
changeset.resource
|> Ash.Resource.Info.attributes()
|> Enum.filter(&(not is_nil(&1.default)))
|> Enum.filter(&(keys == :all || &1.name in keys))
|> Enum.filter(fn attribute ->
lazy? or
not (is_function(attribute.default) or match?({_, _, _}, attribute.default))
end)
|> Enum.reduce(changeset, fn attribute, changeset ->
force_change_new_attribute_lazy(changeset, attribute.name, fn ->
default(:create, attribute)
@ -599,11 +597,14 @@ defmodule Ash.Changeset do
end)
end
def set_defaults(changeset, :update, keys) do
def set_defaults(changeset, :update, lazy?) do
changeset.resource
|> Ash.Resource.Info.attributes()
|> Enum.filter(&(not is_nil(&1.update_default)))
|> Enum.filter(&(keys == :all || &1.name in keys))
|> Enum.filter(fn attribute ->
lazy? or
not (is_function(attribute.update_default) or match?({_, _, _}, attribute.update_default))
end)
|> Enum.reduce(changeset, fn attribute, changeset ->
force_change_new_attribute_lazy(changeset, attribute.name, fn ->
default(:update, attribute)

View file

@ -217,11 +217,6 @@ defmodule Ash.Query do
tenant: [
type: :any,
doc: "set the tenant on the query"
],
defaults: [
type: :any,
doc:
"A list of arguments to apply defaults for. Defaults to: []. Any unset defaults are set when the action is called."
]
]
@ -257,7 +252,7 @@ defmodule Ash.Query do
|> cast_params(action, args)
|> run_preparations(action, opts[:actor])
|> add_action_filters(action, opts[:actor])
|> cast_arguments(action, opts[:defaults], true)
|> cast_arguments(action, true)
else
add_error(query, :action, "No such action #{action_name}")
end
@ -801,22 +796,18 @@ defmodule Ash.Query do
end
@doc false
def cast_arguments(query, action, defaults \\ :all, only_supplied? \\ false) do
def cast_arguments(query, action, only_supplied? \\ false) do
action.arguments
|> Enum.reject(& &1.private?)
|> Enum.reject(&(only_supplied? && match?({:ok, _}, fetch_argument(query, &1.name))))
|> Enum.reduce(query, fn argument, new_query ->
{ignore_nil_check, value} =
if defaults == :all || argument.name in (defaults || []) do
{false, get_argument(query, argument.name) || argument_default(argument.default)}
else
value = get_argument(query, argument.name)
value = get_argument(query, argument.name)
if argument_default(argument.default) do
{true, value}
else
{false, value}
end
{ignore_nil_check, value} =
if argument_default(argument.default) do
{true, value}
else
{false, value}
end
cond do

View file

@ -82,12 +82,12 @@ defmodule Ash.Resource.Attribute do
update_default: [
type: {:custom, Ash.OptionsHelpers, :default, []},
doc:
"A zero argument function, an {mod, fun, args} triple or a value. If no value is provided for the attribute on update, this value is used."
"A zero argument function, an {mod, fun, args} triple or a value. `Ash.Changeset.for_update/4` sets the default in the changeset if a value is not provided."
],
default: [
type: {:custom, Ash.OptionsHelpers, :default, []},
doc:
"A zero argument function, an {mod, fun, args} triple or a value. If no value is provided for the attribute on create, this value is used."
"A zero argument function, an {mod, fun, args} triple or a value. `Ash.Changeset.for_create/4` sets the default in the changeset if a value is not provided."
],
description: [
type: :string,
@ -106,7 +106,10 @@ defmodule Ash.Resource.Attribute do
|> OptionsHelpers.set_default!(:writable?, false)
|> OptionsHelpers.set_default!(:private?, true)
|> OptionsHelpers.set_default!(:default, &DateTime.utc_now/0)
|> OptionsHelpers.set_default!(:update_default, &DateTime.utc_now/0)
|> OptionsHelpers.set_default!(
:update_default,
&DateTime.utc_now/0
)
|> OptionsHelpers.set_default!(:type, Ash.Type.UtcDatetimeUsec)
|> OptionsHelpers.set_default!(:allow_nil?, false)