Skip to content

Commit 938dbbe

Browse files
committed
Merge remote-tracking branch 'GitHub/main' into includes-duplicates
2 parents 2a442e2 + de83ff4 commit 938dbbe

File tree

7 files changed

+375
-19
lines changed

7 files changed

+375
-19
lines changed

lib/ash_json_api/includes/includer.ex

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ defmodule AshJsonApi.Includes.Includer do
3838
includes_keyword
3939
|> Enum.reduce({preloaded, includes_map}, fn
4040
{relationship, further}, {preloaded_without_linkage, includes_map} ->
41+
linkage_only? =
42+
case further do
43+
%{__linkage_only__: true} -> true
44+
_ -> false
45+
end
4146
{related, includes_map} =
4247
preloaded
4348
|> Enum.flat_map(fn record ->
@@ -62,22 +67,32 @@ defmodule AshJsonApi.Includes.Includer do
6267
)
6368

6469
includes_map =
65-
related
66-
|> List.wrap()
67-
|> Enum.reduce(includes_map, fn related_item, includes_map ->
68-
type = AshJsonApi.Resource.Info.type(related_item)
69-
id = AshJsonApi.Resource.encode_primary_key(related_item)
70-
71-
case Map.fetch(includes_map, {type, id}) do
72-
{:ok, _} ->
73-
Map.update!(includes_map, {type, id}, fn existing ->
74-
merge_linkages(existing, related_item)
75-
end)
76-
77-
:error ->
78-
Map.put(includes_map, {type, id}, Map.put_new(related_item, :__linkage__, %{}))
79-
end
80-
end)
70+
if linkage_only? do
71+
includes_map
72+
else
73+
related
74+
|> List.wrap()
75+
|> Enum.reduce(includes_map, fn related_item, includes_map ->
76+
# On construit la clé {type, id}
77+
type = AshJsonApi.Resource.Info.type(related_item)
78+
id = AshJsonApi.Resource.encode_primary_key(related_item)
79+
80+
# On ajoute le record dans includes_map
81+
case Map.fetch(includes_map, {type, id}) do
82+
{:ok, _} ->
83+
# La clé existe déjà, on merge les linkages
84+
Map.update!(includes_map, {type, id}, fn existing ->
85+
# On merge les linkages en une liste
86+
merge_linkages(existing, related_item)
87+
end)
88+
89+
:error ->
90+
# La clé n'existe pas, on l'ajoute avec le linkage, et un linkage vide
91+
# si il n'existe pas déjà,
92+
Map.put(includes_map, {type, id}, Map.put_new(related_item, :__linkage__, %{}))
93+
end
94+
end)
95+
end
8196

8297
{preloaded_with_linkage, includes_map}
8398
end)

lib/ash_json_api/request.ex

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -680,11 +680,28 @@ defmodule AshJsonApi.Request do
680680
)
681681
end
682682

683-
defp set_include_queries(includes, fields, field_inputs, filters, sorts, resource, path \\ []) do
683+
defp set_include_queries(includes, fields, field_inputs, filters, sorts, resource, path \\ [])
684+
685+
defp set_include_queries(:linkage_only, _, _, _, _, _, _), do: []
686+
687+
defp set_include_queries(includes, fields, field_inputs, filters, sorts, resource, path) do
688+
includes =
689+
Enum.reduce(
690+
AshJsonApi.Resource.Info.always_include_linkage(resource),
691+
includes,
692+
fn key, includes ->
693+
if Keyword.has_key?(includes, key) do
694+
includes
695+
else
696+
Keyword.put(includes, key, :linkage_only)
697+
end
698+
end
699+
)
700+
684701
Enum.map(includes, fn {key, nested} ->
685702
related = public_related(resource, key)
686703

687-
nested =
704+
nested_queries =
688705
set_include_queries(nested, fields, field_inputs, filters, sorts, related, path ++ [key])
689706

690707
related_field_inputs = Map.get(field_inputs, related, %{})
@@ -704,12 +721,13 @@ defmodule AshJsonApi.Request do
704721
value -> {field, value}
705722
end
706723
end)
707-
|> Kernel.++(nested)
724+
|> Kernel.++(nested_queries)
708725

709726
new_query =
710727
related
711728
|> Ash.Query.new()
712729
|> Ash.Query.load(load)
730+
|> Map.put(:__linkage_only__, nested == :linkage_only)
713731

714732
filtered_query =
715733
case Map.fetch(filters, path ++ [key]) do

lib/ash_json_api/resource/info.ex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ defmodule AshJsonApi.Resource.Info do
1515
Extension.get_opt(resource, [:json_api], :derive_sort, true, false)
1616
end
1717

18+
def always_include_linkage(resource) do
19+
Extension.get_opt(resource, [:json_api], :always_include_linkage, [], false)
20+
end
21+
1822
def includes(resource) do
1923
Extension.get_opt(resource, [:json_api], :includes, [], false)
2024
end

lib/ash_json_api/resource/resource.ex

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,12 @@ defmodule AshJsonApi.Resource do
494494
type: :string,
495495
doc: "The resource identifier type of this resource in JSON:API"
496496
],
497+
always_include_linkage: [
498+
type: {:list, :atom},
499+
doc:
500+
"A list of relationships that should always have their linkage included in the resource",
501+
default: []
502+
],
497503
includes: [
498504
type: {:wrap_list, :any},
499505
default: [],

lib/ash_json_api/serializer.ex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,9 +577,16 @@ defmodule AshJsonApi.Serializer do
577577
type: AshJsonApi.Resource.Info.type(destination)
578578
})
579579

580+
%{__linkage__: %{^name => []}} ->
581+
Map.put(payload, :data, nil)
582+
580583
# There could be another case here if a bug in the system gave us a list
581584
# of more than one shouldn't happen though
582585

586+
%{__linkage__: %{^name => other}} ->
587+
IO.inspect(other, label: "Unexpected record for relationship #{name}")
588+
payload
589+
583590
_ ->
584591
payload
585592
end

0 commit comments

Comments
 (0)