mirror of
https://github.com/ash-project/ash.git
synced 2024-09-20 05:23:03 +12:00
fix: use Comp.equal?/2
when finding loaded data matches
This commit is contained in:
parent
865d028667
commit
2c2c207e68
3 changed files with 124 additions and 19 deletions
|
@ -147,30 +147,57 @@ defmodule Ash.Actions.Load do
|
|||
|
||||
defp attach_to_many_loads(value, last_relationship, data, lead_path) when is_map(value) do
|
||||
primary_key = Ash.Resource.Info.primary_key(last_relationship.source)
|
||||
value = Map.to_list(value)
|
||||
|
||||
map_or_update(data, lead_path, fn record ->
|
||||
case primary_key do
|
||||
[field] ->
|
||||
related =
|
||||
Enum.find(value, fn {key, _value} ->
|
||||
Comp.equal?(key, Map.get(record, field)) ||
|
||||
Comp.equal?(key, Map.take(record, [field]))
|
||||
end)
|
||||
|> case do
|
||||
nil ->
|
||||
nil
|
||||
|
||||
{_, value} ->
|
||||
value
|
||||
end
|
||||
|
||||
Map.put(
|
||||
record,
|
||||
last_relationship.name,
|
||||
Map.get(value, Map.take(record, primary_key)) ||
|
||||
Map.get(value, Map.get(record, field)) || []
|
||||
related
|
||||
)
|
||||
|
||||
_ ->
|
||||
Map.put(record, last_relationship.name, Map.get(value, Map.take(record, primary_key))) ||
|
||||
[]
|
||||
primary_key ->
|
||||
related =
|
||||
Enum.find(value, fn {key, _value} ->
|
||||
Comp.equal?(key, Map.take(record, primary_key))
|
||||
end)
|
||||
|> case do
|
||||
nil ->
|
||||
nil
|
||||
|
||||
{_, value} ->
|
||||
value
|
||||
end
|
||||
|
||||
Map.put(record, last_relationship.name, related)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp attach_to_many_loads(value, last_relationship, data, lead_path) do
|
||||
values = Enum.group_by(value, &Map.get(&1, last_relationship.destination_attribute))
|
||||
|
||||
map_or_update(data, lead_path, fn record ->
|
||||
source_key = Map.get(record, last_relationship.source_attribute)
|
||||
related_records = Map.get(values, source_key, [])
|
||||
|
||||
related_records =
|
||||
Enum.filter(value, fn maybe_related ->
|
||||
Comp.equal?(Map.get(maybe_related, last_relationship.destination_attribute), source_key)
|
||||
end)
|
||||
|
||||
Map.put(record, last_relationship.name, related_records)
|
||||
end)
|
||||
end
|
||||
|
@ -185,21 +212,54 @@ defmodule Ash.Actions.Load do
|
|||
primary_key = Ash.Resource.Info.primary_key(last_relationship.source)
|
||||
|
||||
map_or_update(data, lead_path, fn record ->
|
||||
Map.put(record, last_relationship.name, Map.get(value, Map.take(record, primary_key)))
|
||||
case primary_key do
|
||||
[field] ->
|
||||
related =
|
||||
Enum.find(value, fn {key, _value} ->
|
||||
Comp.equal?(key, Map.get(record, field)) ||
|
||||
Comp.equal?(key, Map.take(record, [field]))
|
||||
end)
|
||||
|> case do
|
||||
nil ->
|
||||
nil
|
||||
|
||||
{_, value} ->
|
||||
value
|
||||
end
|
||||
|
||||
Map.put(
|
||||
record,
|
||||
last_relationship.name,
|
||||
related
|
||||
)
|
||||
|
||||
primary_key ->
|
||||
related =
|
||||
Enum.find(value, fn {key, _value} ->
|
||||
Comp.equal?(key, Map.take(record, primary_key))
|
||||
end)
|
||||
|> case do
|
||||
nil ->
|
||||
nil
|
||||
|
||||
{_, value} ->
|
||||
value
|
||||
end
|
||||
|
||||
Map.put(record, last_relationship.name, related)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp attach_to_one_loads(value, last_relationship, data, lead_path) do
|
||||
values =
|
||||
value
|
||||
|> Enum.reverse()
|
||||
|> Enum.into(%{}, fn item ->
|
||||
{Map.get(item, last_relationship.destination_attribute), item}
|
||||
end)
|
||||
|
||||
map_or_update(data, lead_path, fn record ->
|
||||
source_key = Map.get(record, last_relationship.source_attribute)
|
||||
related_record = Map.get(values, source_key)
|
||||
|
||||
related_record =
|
||||
Enum.find(value, fn maybe_related ->
|
||||
Comp.equal?(Map.get(maybe_related, last_relationship.destination_attribute), source_key)
|
||||
end)
|
||||
|
||||
Map.put(record, last_relationship.name, related_record)
|
||||
end)
|
||||
end
|
||||
|
@ -218,8 +278,10 @@ defmodule Ash.Actions.Load do
|
|||
join_values =
|
||||
join_data
|
||||
|> Enum.filter(fn join_row ->
|
||||
Map.get(join_row, last_relationship.source_attribute_on_join_resource) ==
|
||||
Comp.equal?(
|
||||
Map.get(join_row, last_relationship.source_attribute_on_join_resource),
|
||||
source_value
|
||||
)
|
||||
end)
|
||||
|> Enum.map(&Map.get(&1, last_relationship.destination_attribute_on_join_resource))
|
||||
|
||||
|
|
|
@ -1394,7 +1394,7 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
defp do_matches?(current_value, input, field) do
|
||||
with {:ok, current_val} when not is_nil(current_val) <- Map.fetch(current_value, field),
|
||||
{:ok, input_val} when not is_nil(input_val) <- fetch_field(input, field) do
|
||||
current_val == input_val
|
||||
Comp.equal?(current_val, input_val)
|
||||
else
|
||||
_ ->
|
||||
false
|
||||
|
|
|
@ -5,6 +5,25 @@ defmodule Ash.Test.Actions.LoadTest do
|
|||
import Ash.Changeset
|
||||
require Ash.Query
|
||||
|
||||
defmodule Campaign do
|
||||
@moduledoc false
|
||||
use Ash.Resource,
|
||||
data_layer: Ash.DataLayer.Ets
|
||||
|
||||
ets do
|
||||
private?(true)
|
||||
end
|
||||
|
||||
actions do
|
||||
defaults [:create, :read, :update, :destroy]
|
||||
end
|
||||
|
||||
attributes do
|
||||
uuid_primary_key :id
|
||||
attribute :name, :ci_string
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Author do
|
||||
@moduledoc false
|
||||
use Ash.Resource,
|
||||
|
@ -32,6 +51,13 @@ defmodule Ash.Test.Actions.LoadTest do
|
|||
has_one :latest_post, Ash.Test.Actions.LoadTest.Post,
|
||||
destination_attribute: :author_id,
|
||||
sort: [inserted_at: :desc]
|
||||
|
||||
belongs_to :campaign, Ash.Test.Actions.LoadTest.Campaign do
|
||||
attribute_type :ci_string
|
||||
source_attribute :campaign_name
|
||||
destination_attribute :name
|
||||
attribute_writable? true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -176,6 +202,7 @@ defmodule Ash.Test.Actions.LoadTest do
|
|||
entry(Post)
|
||||
entry(Category)
|
||||
entry(PostCategory)
|
||||
entry(Campaign)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -241,6 +268,22 @@ defmodule Ash.Test.Actions.LoadTest do
|
|||
|> Map.get(:posts_in_same_category)
|
||||
end
|
||||
|
||||
test "it uses `Comp.equal?/2` to support things like ci_string foreign keys" do
|
||||
author =
|
||||
Author
|
||||
|> new(%{name: "zerg", campaign_name: "FrEd"})
|
||||
|> Api.create!()
|
||||
|
||||
Campaign
|
||||
|> new(%{name: "fReD"})
|
||||
|> Api.create!()
|
||||
|
||||
assert %{
|
||||
campaign: %{name: %Ash.CiString{string: "fReD"}},
|
||||
campaign_name: %Ash.CiString{string: "FrEd"}
|
||||
} = Api.load!(author, :campaign)
|
||||
end
|
||||
|
||||
test "it allows loading related data" do
|
||||
author =
|
||||
Author
|
||||
|
|
Loading…
Reference in a new issue