mirror of
https://github.com/ash-project/ash.git
synced 2024-09-20 13:33:20 +12:00
fix: load relationships for management properly
fix: `fetch_key` bug in embedded types fix: handle_indexed_maps for embedded types
This commit is contained in:
parent
f97caad908
commit
5425660752
3 changed files with 39 additions and 20 deletions
|
@ -5,18 +5,35 @@ defmodule Ash.Actions.ManagedRelationships do
|
||||||
alias Ash.Error.Changes.InvalidRelationship
|
alias Ash.Error.Changes.InvalidRelationship
|
||||||
alias Ash.Error.Query.NotFound
|
alias Ash.Error.Query.NotFound
|
||||||
|
|
||||||
def load(_api, created, %{relationships: rels}, _) when rels == %{}, do: {:ok, created}
|
def load(_api, created, %{relationships: rels}, _) when rels == %{},
|
||||||
|
do: {:ok, created}
|
||||||
|
|
||||||
def load(_api, created, %{relationships: nil}, _), do: {:ok, created}
|
def load(_api, created, %{relationships: nil}, _), do: {:ok, created}
|
||||||
|
|
||||||
def load(api, created, changeset, opts) do
|
def load(api, created, changeset, engine_opts) do
|
||||||
if Ash.Changeset.ManagedRelationshipHelpers.must_load?(opts) do
|
Enum.reduce_while(changeset.relationships, {:ok, created}, fn {key, value}, {:ok, acc} ->
|
||||||
api.load(created, Map.keys(changeset.relationships),
|
relationship = Ash.Resource.Info.relationship(changeset.resource, key)
|
||||||
authorize?: opts[:authorize?],
|
|
||||||
actor: opts[:actor]
|
case Enum.filter(value, fn {_, opts} ->
|
||||||
)
|
opts = Ash.Changeset.ManagedRelationshipHelpers.sanitize_opts(relationship, opts)
|
||||||
else
|
Ash.Changeset.ManagedRelationshipHelpers.must_load?(opts)
|
||||||
{:ok, created}
|
end) do
|
||||||
end
|
[] ->
|
||||||
|
{:cont, {:ok, acc}}
|
||||||
|
|
||||||
|
relationships ->
|
||||||
|
authorize? =
|
||||||
|
engine_opts[:authorize?] &&
|
||||||
|
Enum.any?(relationships, fn {_, opts} -> opts[:authorize?] end)
|
||||||
|
|
||||||
|
actor = engine_opts[:actor]
|
||||||
|
|
||||||
|
case api.load(acc, key, authorize?: authorize?, actor: actor) do
|
||||||
|
{:ok, loaded} -> {:cont, {:ok, loaded}}
|
||||||
|
{:error, error} -> {:halt, {:error, error}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
def setup_managed_belongs_to_relationships(changeset, actor, engine_opts) do
|
def setup_managed_belongs_to_relationships(changeset, actor, engine_opts) do
|
||||||
|
|
|
@ -1718,7 +1718,8 @@ defmodule Ash.Changeset do
|
||||||
add_invalid_errors(:attribute, changeset, attribute, "Attribute is not writable")
|
add_invalid_errors(:attribute, changeset, attribute, "Attribute is not writable")
|
||||||
|
|
||||||
attribute ->
|
attribute ->
|
||||||
with {:ok, prepared} <-
|
with value <- handle_indexed_maps(attribute.type, value),
|
||||||
|
{:ok, prepared} <-
|
||||||
prepare_change(changeset, attribute, value, attribute.constraints),
|
prepare_change(changeset, attribute, value, attribute.constraints),
|
||||||
{:ok, casted} <-
|
{:ok, casted} <-
|
||||||
cast_input(attribute.type, prepared, attribute.constraints, true),
|
cast_input(attribute.type, prepared, attribute.constraints, true),
|
||||||
|
@ -1844,7 +1845,8 @@ defmodule Ash.Changeset do
|
||||||
%{changeset | attributes: Map.put(changeset.attributes, attribute.name, nil)}
|
%{changeset | attributes: Map.put(changeset.attributes, attribute.name, nil)}
|
||||||
|
|
||||||
attribute ->
|
attribute ->
|
||||||
with {:ok, prepared} <-
|
with value <- handle_indexed_maps(attribute.type, value),
|
||||||
|
{:ok, prepared} <-
|
||||||
prepare_change(changeset, attribute, value, attribute.constraints),
|
prepare_change(changeset, attribute, value, attribute.constraints),
|
||||||
{:ok, casted} <-
|
{:ok, casted} <-
|
||||||
cast_input(attribute.type, prepared, attribute.constraints),
|
cast_input(attribute.type, prepared, attribute.constraints),
|
||||||
|
|
|
@ -128,7 +128,7 @@ defmodule Ash.EmbeddableType do
|
||||||
|
|
||||||
defmacro single_embed_implementation do
|
defmacro single_embed_implementation do
|
||||||
# credo:disable-for-next-line Credo.Check.Refactor.LongQuoteBlocks
|
# credo:disable-for-next-line Credo.Check.Refactor.LongQuoteBlocks
|
||||||
quote do
|
quote location: :keep do
|
||||||
alias __MODULE__.ShadowApi
|
alias __MODULE__.ShadowApi
|
||||||
def storage_type, do: :map
|
def storage_type, do: :map
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ defmodule Ash.EmbeddableType do
|
||||||
def fetch_key(map, atom) do
|
def fetch_key(map, atom) do
|
||||||
case Map.fetch(map, atom) do
|
case Map.fetch(map, atom) do
|
||||||
{:ok, value} ->
|
{:ok, value} ->
|
||||||
value
|
{:ok, value}
|
||||||
|
|
||||||
:error ->
|
:error ->
|
||||||
Map.fetch(map, to_string(atom))
|
Map.fetch(map, to_string(atom))
|
||||||
|
@ -321,7 +321,7 @@ defmodule Ash.EmbeddableType do
|
||||||
:error ->
|
:error ->
|
||||||
{pkey_field, :error}
|
{pkey_field, :error}
|
||||||
|
|
||||||
value ->
|
{:ok, value} ->
|
||||||
attribute = Ash.Resource.Info.attribute(__MODULE__, pkey_field)
|
attribute = Ash.Resource.Info.attribute(__MODULE__, pkey_field)
|
||||||
|
|
||||||
case Ash.Type.cast_input(attribute.type, value, attribute.constraints) do
|
case Ash.Type.cast_input(attribute.type, value, attribute.constraints) do
|
||||||
|
@ -362,7 +362,7 @@ defmodule Ash.EmbeddableType do
|
||||||
|
|
||||||
defmacro array_embed_implementation do
|
defmacro array_embed_implementation do
|
||||||
# credo:disable-for-next-line Credo.Check.Refactor.LongQuoteBlocks
|
# credo:disable-for-next-line Credo.Check.Refactor.LongQuoteBlocks
|
||||||
quote do
|
quote location: :keep do
|
||||||
alias __MODULE__.ShadowApi
|
alias __MODULE__.ShadowApi
|
||||||
def array_constraints, do: Ash.EmbeddableType.embedded_resource_array_constraints()
|
def array_constraints, do: Ash.EmbeddableType.embedded_resource_array_constraints()
|
||||||
|
|
||||||
|
@ -482,9 +482,9 @@ defmodule Ash.EmbeddableType do
|
||||||
Enum.into(pkey_fields, %{}, fn pkey_field ->
|
Enum.into(pkey_fields, %{}, fn pkey_field ->
|
||||||
case fetch_key(new, pkey_field) do
|
case fetch_key(new, pkey_field) do
|
||||||
:error ->
|
:error ->
|
||||||
:error
|
{pkey_field, :error}
|
||||||
|
|
||||||
value ->
|
{:ok, value} ->
|
||||||
attr = Map.get(pkey_attributes, pkey_field)
|
attr = Map.get(pkey_attributes, pkey_field)
|
||||||
|
|
||||||
case Ash.Type.cast_input(attr.type, value, attr.constraints) do
|
case Ash.Type.cast_input(attr.type, value, attr.constraints) do
|
||||||
|
@ -492,7 +492,7 @@ defmodule Ash.EmbeddableType do
|
||||||
{pkey_field, casted}
|
{pkey_field, casted}
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
:error
|
{pkey_field, :error}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
@ -538,7 +538,7 @@ defmodule Ash.EmbeddableType do
|
||||||
end
|
end
|
||||||
|
|
||||||
defmacro define_embeddable_type do
|
defmacro define_embeddable_type do
|
||||||
quote do
|
quote location: :keep do
|
||||||
use Ash.Type
|
use Ash.Type
|
||||||
|
|
||||||
parent = __MODULE__
|
parent = __MODULE__
|
||||||
|
|
Loading…
Reference in a new issue