Skip to content

Commit

Permalink
fix: properly handle union changes for lists of embeds
Browse files Browse the repository at this point in the history
at the moment, this only works properly for tagged maps
  • Loading branch information
zachdaniel committed Dec 6, 2023
1 parent c7e6133 commit 618b706
Show file tree
Hide file tree
Showing 3 changed files with 315 additions and 82 deletions.
3 changes: 2 additions & 1 deletion lib/ash/embeddable_type.ex
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,8 @@ defmodule Ash.EmbeddableType do
else
value_updating_from =
Enum.find(old_values, fn old_value ->
Map.take(old_value, pkey_fields) == pkey
Map.take(old_value, pkey_fields) ==
pkey
end)

if value_updating_from do
Expand Down
63 changes: 49 additions & 14 deletions lib/ash/type/type.ex
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ defmodule Ash.Type do
context :: load_context()
) ::
{:ok, list(term)} | {:error, Ash.Error.t()}
@callback prepare_change_array?() :: boolean()
@callback handle_change_array?() :: boolean()

@optional_callbacks [
init: 1,
Expand Down Expand Up @@ -377,7 +379,7 @@ defmodule Ash.Type do

def handle_change({:array, type}, old_value, new_value, constraints) do
type = get_type(type)
type.handle_change_array(old_value, new_value, constraints)
type.handle_change_array(old_value, new_value, constraints[:items] || [])
end

def handle_change(type, old_value, new_value, constraints) do
Expand All @@ -398,7 +400,7 @@ defmodule Ash.Type do

def prepare_change({:array, type}, old_value, new_value, constraints) do
type = get_type(type)
type.prepare_change_array(old_value, new_value, constraints)
type.prepare_change_array(old_value, new_value, constraints[:items] || [])
end

def prepare_change(type, old_value, new_value, constraints) do
Expand Down Expand Up @@ -897,6 +899,25 @@ defmodule Ash.Type do
type.can_load?(constraints)
end

@spec prepare_change_array?(t()) :: boolean

def prepare_change_array?({:array, type}),
do: prepare_change_array?(type)

def prepare_change_array?(type) do
type = get_type(type)
type.prepare_change_array?()
end

@spec handle_change_array?(t()) :: boolean
def handle_change_array?({:array, type}),
do: handle_change_array?(type)

def handle_change_array?(type) do
type = get_type(type)
type.handle_change_array?()
end

@doc """
Determines if a type can be compared using ==
"""
Expand Down Expand Up @@ -1036,16 +1057,6 @@ defmodule Ash.Type do
dump_to_native(value, constraints)
end

@impl true
def handle_change_array(_old_value, new_value, _constraints) do
{:ok, new_value}
end

@impl true
def prepare_change_array(_old_value, new_value, _constraints) do
{:ok, new_value}
end

@impl true
def cast_input_array(term, single_constraints) do
term
Expand Down Expand Up @@ -1167,8 +1178,6 @@ defmodule Ash.Type do
include_source: 2,
describe: 1,
generator: 1,
handle_change_array: 3,
prepare_change_array: 3,
cast_input_array: 2,
dump_to_native_array: 2,
dump_to_embedded: 2,
Expand Down Expand Up @@ -1314,6 +1323,32 @@ defmodule Ash.Type do
def equal?(left, right), do: left == right
end

if Module.defines?(__MODULE__, {:handle_change_array, 3}, :def) do
@impl true
def handle_change_array?, do: true
else
@impl true
def handle_change_array(_old_value, new_value, _constraints) do
{:ok, new_value}
end

@impl true
def handle_change_array?, do: false
end

if Module.defines?(__MODULE__, {:prepare_change_array, 3}, :def) do
@impl true
def prepare_change_array?, do: true
else
@impl true
def prepare_change_array(_old_value, new_value, _constraints) do
{:ok, new_value}
end

@impl true
def prepare_change_array?, do: false
end

cond do
Module.defines?(__MODULE__, {:storage_type, 0}) &&
Module.defines?(__MODULE__, {:storage_type, 1}) ->
Expand Down
Loading

0 comments on commit 618b706

Please sign in to comment.