diff --git a/lib/ash/changeset/changeset.ex b/lib/ash/changeset/changeset.ex index 672a4908b..296df8eb8 100644 --- a/lib/ash/changeset/changeset.ex +++ b/lib/ash/changeset/changeset.ex @@ -1311,18 +1311,14 @@ defmodule Ash.Changeset do end defp set_lazy_defaults(changeset, type) do - attributes = Ash.Resource.Info.attributes(changeset.resource) - changeset - |> set_lazy_non_matching_defaults(attributes, type) - |> set_lazy_matching_defaults(attributes, type) + |> set_lazy_non_matching_defaults(type) + |> set_lazy_matching_defaults(type) end - defp set_lazy_non_matching_defaults(changeset, attributes, type) do - attributes - |> Enum.filter(fn attribute -> - !attribute.match_other_defaults? && get_default_fun(attribute, type) - end) + defp set_lazy_non_matching_defaults(changeset, type) do + changeset.resource + |> Ash.Resource.Info.lazy_non_matching_default_attributes(type) |> Enum.reduce(changeset, fn attribute, changeset -> if changing_attribute?(changeset, attribute.name) do changeset @@ -1336,23 +1332,9 @@ defmodule Ash.Changeset do end) end - defp get_default_fun(attribute, :create) do - if is_function(attribute.default) or match?({_, _, _}, attribute.default) do - attribute.default - end - end - - defp get_default_fun(attribute, :update) do - if is_function(attribute.update_default) or match?({_, _, _}, attribute.update_default) do - attribute.update_default - end - end - - defp set_lazy_matching_defaults(changeset, attributes, type) do - attributes - |> Enum.filter(fn attribute -> - attribute.match_other_defaults? && get_default_fun(attribute, type) - end) + defp set_lazy_matching_defaults(changeset, type) do + changeset.resource + |> Ash.Resource.Info.lazy_matching_default_attributes(type) |> Enum.group_by(fn attribute -> case type do :create -> @@ -1386,64 +1368,6 @@ defmodule Ash.Changeset do end) end - # defp set_lazy_defaults(changeset, type) do - # changeset - # |> set_lazy_non_matching_defaults(type) - # |> set_lazy_matching_defaults(type) - # end - - # defp set_lazy_non_matching_defaults(changeset, type) do - # changeset.resource - # |> Ash.Resource.Info.lazy_matching_default_attributes(type) - # |> Enum.reduce(changeset, fn attribute, changeset -> - # if changing_attribute?(changeset, attribute.name) do - # changeset - # else - # changeset - # |> force_change_attribute(attribute.name, default(type, attribute)) - # |> Map.update!(:defaults, fn defaults -> - # [attribute.name | defaults] - # end) - # end - # end) - # end - - # defp set_lazy_matching_defaults(changeset, type) do - # changeset.resource - # |> Ash.Resource.Info.lazy_matching_default_attributes(type) - # |> Enum.group_by(fn attribute -> - # case type do - # :create -> - # attribute.default - - # :update -> - # attribute.update_default - # end - # end) - # |> Enum.reduce(changeset, fn {default_fun, attributes}, changeset -> - # default_value = - # case default_fun do - # function when is_function(function) -> - # function.() - - # {m, f, a} when is_atom(m) and is_atom(f) and is_list(a) -> - # apply(m, f, a) - # end - - # Enum.reduce(attributes, changeset, fn attribute, changeset -> - # if changing_attribute?(changeset, attribute.name) do - # changeset - # else - # changeset - # |> force_change_attribute(attribute.name, default_value) - # |> Map.update!(:defaults, fn defaults -> - # [attribute.name | defaults] - # end) - # end - # end) - # end) - # end - defp default(:create, %{default: {mod, func, args}}), do: apply(mod, func, args) defp default(:create, %{default: function}) when is_function(function, 0), do: function.() defp default(:create, %{default: value}), do: value diff --git a/lib/ash/embeddable_type.ex b/lib/ash/embeddable_type.ex index 781e875b8..f71f23d80 100644 --- a/lib/ash/embeddable_type.ex +++ b/lib/ash/embeddable_type.ex @@ -525,6 +525,10 @@ defmodule Ash.EmbeddableType do end end + def include_source(changeset, constraints) do + Keyword.put(constraints, :__source__, changeset) + end + def prepare_change_array(_old_values, nil, _constraints) do {:ok, nil} end diff --git a/lib/ash/type/helpers.ex b/lib/ash/type/helpers.ex index 0e535b7a4..5053481e7 100644 --- a/lib/ash/type/helpers.ex +++ b/lib/ash/type/helpers.ex @@ -5,7 +5,7 @@ defmodule Ash.Type.Helpers do def cast_input(type, value, constraints, changeset, return_value?) do value = handle_indexed_maps(type, value) - constraints = constraints ++ [{:__source__, changeset}] + constraints = Ash.Type.include_source(type, changeset, constraints) case Ash.Type.cast_input(type, value, constraints) do {:ok, value} -> diff --git a/lib/ash/type/type.ex b/lib/ash/type/type.ex index 56cf0e760..351d2620d 100644 --- a/lib/ash/type/type.ex +++ b/lib/ash/type/type.ex @@ -151,6 +151,7 @@ defmodule Ash.Type do @callback storage_type() :: Ecto.Type.t() @callback storage_type(constraints) :: Ecto.Type.t() + @callback include_source(constraints, Ash.Changeset.t()) :: constraints @doc """ Useful for typed data layers (like ash_postgres) to instruct them not to attempt to cast input values. @@ -219,6 +220,7 @@ defmodule Ash.Type do array_constraints: 0, dump_to_embedded: 2, dump_to_embedded_array: 2, + include_source: 2, load: 4 ] @@ -823,6 +825,15 @@ defmodule Ash.Type do type.equal?(left, right) end + @spec include_source(t(), Ash.Changeset.t(), constraints()) :: constraints() + def include_source({:array, type}, changeset, constraints) do + include_source(type, changeset, constraints) + end + + def include_source(type, changeset, constraints) do + type.include_source(changeset, constraints) + end + @spec load( type :: Ash.Type.t(), values :: list(term), @@ -1007,6 +1018,9 @@ defmodule Ash.Type do @impl true def prepare_change(_old_value, new_value, _constraints), do: {:ok, new_value} + @impl true + def include_source(_, constraints), do: constraints + @impl true def array_constraints do unquote(@array_constraints) @@ -1022,6 +1036,7 @@ defmodule Ash.Type do defoverridable constraints: 0, init: 1, + include_source: 2, describe: 1, embedded?: 0, ecto_type: 0,