Skip to content

Commit

Permalink
Re-use implementation of diff-association for has_many_through
Browse files Browse the repository at this point in the history
  • Loading branch information
dimakula committed Sep 29, 2023
1 parent a59c906 commit 6a16422
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 24 deletions.
41 changes: 17 additions & 24 deletions lib/ecto_diff.ex
Original file line number Diff line number Diff line change
Expand Up @@ -367,33 +367,26 @@ defmodule EctoDiff do
end
end

defp diff_association(previous, current, %{cardinality: :many, through: [through, field]}, acc, opts) do
assoc_diff =
acc
|> Keyword.get_values(through)
|> List.flatten()
|> Enum.map(& &1[:changes][field])

diff =
case assoc_diff do
[_ | _] = diff ->
List.flatten(diff)

_ ->
{previous, current} =
case length(previous) - length(current) do
0 -> {previous, current}
n when n > 0 -> {previous, current ++ List.duplicate(nil, n)}
n when n < 0 -> {previous ++ List.duplicate(nil, -n), current}
end

Enum.zip_with([previous, current], fn [p, c] -> do_diff(p, c, opts) end)
end

if no_changes?(diff), do: acc, else: [{field, diff} | acc]
defp diff_association(
previous,
current,
%{cardinality: :many, through: [through, assoc_field]} = has_through,
acc,
opts
) do
%{field: field, owner: owner} = has_through

association = owner.__schema__(:association, through).related
struct = association.__schema__(:association, assoc_field).related

do_diff_association(previous, current, field, struct, acc, opts)
end

defp diff_association(previous, current, %{cardinality: :many, field: field, related: struct}, acc, opts) do
do_diff_association(previous, current, field, struct, acc, opts)
end

defp do_diff_association(previous, current, field, struct, acc, opts) do
primary_key_fields = get_primary_key_fields(struct, opts)

if primary_key_fields == [],
Expand Down
3 changes: 3 additions & 0 deletions test/ecto_diff_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,8 @@ defmodule EctoDiffTest do
})
|> Repo.update()

updated_pet = Repo.preload(updated_pet, [:toys], force: true)

{:ok, diff} = EctoDiff.diff(pet, updated_pet)

assert %EctoDiff{
Expand Down Expand Up @@ -861,6 +863,7 @@ defmodule EctoDiffTest do
[ball_id] = Enum.map(pet.toys, & &1.id)

{:ok, updated_pet} = pet |> Pet.update(%{resources: [%{id: resource_id, toys: []}]}) |> Repo.update()
updated_pet = Repo.preload(updated_pet, [:toys], force: true)

{:ok, diff} = EctoDiff.diff(pet, updated_pet)

Expand Down

0 comments on commit 6a16422

Please sign in to comment.