fix: don't eager evaluate exists erroneously

This commit is contained in:
Zach Daniel 2024-05-14 10:11:14 -04:00
parent ca61d56fcf
commit fa172b3be2
2 changed files with 153 additions and 39 deletions

View file

@ -116,6 +116,12 @@ defmodule Ash.Filter.Runtime do
[] -> [] ->
[record] [record]
%Ash.NotLoaded{} = not_loaded ->
[Ash.Resource.set_metadata(record, %{unflattened_rels: %{rel => not_loaded}})]
%Ash.ForbiddenField{} = forbidden ->
[Ash.Resource.set_metadata(record, %{unflattened_rels: %{rel => forbidden}})]
value when is_list(value) -> value when is_list(value) ->
flatten_many_to_many(record, rel, value, rest) flatten_many_to_many(record, rel, value, rest)
@ -740,6 +746,9 @@ defmodule Ash.Filter.Runtime do
%Ash.NotLoaded{} -> %Ash.NotLoaded{} ->
:unknown :unknown
%Ash.ForbiddenField{} ->
:unknown
other -> other ->
{:ok, other} {:ok, other}
end end
@ -827,6 +836,13 @@ defmodule Ash.Filter.Runtime do
) do ) do
if load do if load do
case Map.get(record, load) do case Map.get(record, load) do
%Ash.ForbiddenField{} ->
if unknown_on_unknown_refs? do
:unknown
else
{:ok, nil}
end
%Ash.NotLoaded{} -> %Ash.NotLoaded{} ->
if unknown_on_unknown_refs? do if unknown_on_unknown_refs? do
:unknown :unknown
@ -974,9 +990,24 @@ defmodule Ash.Filter.Runtime do
end end
end end
def get_related(
%Ash.ForbiddenField{},
_,
unknown_on_unknown_refs?,
_join_filters,
_parent_stack,
_domain
) do
if unknown_on_unknown_refs? do
:unknown
else
[]
end
end
def get_related( def get_related(
%Ash.NotLoaded{}, %Ash.NotLoaded{},
[], _,
unknown_on_unknown_refs?, unknown_on_unknown_refs?,
_join_filters, _join_filters,
_parent_stack, _parent_stack,
@ -1004,6 +1035,125 @@ defmodule Ash.Filter.Runtime do
when is_list(records) do when is_list(records) do
{join_filter, rest_join_filters} = Map.pop(join_filters, []) {join_filter, rest_join_filters} = Map.pop(join_filters, [])
rest_join_filters =
Enum.reduce(rest_join_filters, %{}, fn {path, filter}, acc ->
if List.starts_with?(path, [key]) do
Map.put(acc, Enum.drop(path, 1), filter)
else
acc
end
end)
filtered =
if Map.has_key?(join_filters, []) do
filter_matches(domain, records, join_filter,
parent: parent_stack,
unknown_on_unknown_refs?: unknown_on_unknown_refs?
)
else
{:ok, records}
end
case filtered do
{:ok, matches} ->
matches
|> Enum.reduce_while([], fn match, acc ->
case Map.get(match, key) do
%Ash.NotLoaded{} when unknown_on_unknown_refs? ->
{:halt, :unknown}
%Ash.ForbiddenField{} when unknown_on_unknown_refs? ->
{:halt, :unknown}
nil when unknown_on_unknown_refs? ->
{:halt, :unknown}
nil ->
{:cont, acc}
match_keys ->
match_keys
|> List.wrap()
|> Enum.reduce_while([], fn this_match, inner_acc ->
case get_related(
this_match,
rest,
unknown_on_unknown_refs?,
rest_join_filters,
[match | parent_stack],
domain
) do
:unknown -> {:halt, :unknown}
value -> {:cont, inner_acc ++ List.wrap(value)}
end
end)
|> case do
:unknown -> {:halt, :unknown}
list -> {:cont, acc ++ list}
end
end
end)
_ ->
if unknown_on_unknown_refs? do
:unknown
else
[]
end
end
end
def get_related(
record,
[key | _] = path,
unknown_on_unknown_refs?,
join_filters,
parent_stack,
domain
) do
case Map.get(record, key) do
%Ash.NotLoaded{} when unknown_on_unknown_refs? ->
:unknown
%Ash.ForbiddenField{} when unknown_on_unknown_refs? ->
:unknown
nil when unknown_on_unknown_refs? ->
:unknown
_value ->
case get_related(
[record],
path,
unknown_on_unknown_refs?,
join_filters,
parent_stack,
domain
) do
:unknown ->
if unknown_on_unknown_refs? do
:unknown
else
[]
end
related ->
List.wrap(related)
end
end
end
def old_get_related(
records,
[key | rest],
unknown_on_unknown_refs?,
join_filters,
parent_stack,
domain
)
when is_list(records) do
{join_filter, rest_join_filters} = Map.pop(join_filters, [])
rest_join_filters = rest_join_filters =
Enum.reduce(rest_join_filters, %{}, fn {path, filter}, acc -> Enum.reduce(rest_join_filters, %{}, fn {path, filter}, acc ->
if List.starts_with?(path, [key]) do if List.starts_with?(path, [key]) do
@ -1065,43 +1215,6 @@ defmodule Ash.Filter.Runtime do
end end
end end
def get_related(
record,
[key | _] = path,
unknown_on_unknown_refs?,
join_filters,
parent_stack,
domain
) do
case Map.get(record, key) do
%Ash.NotLoaded{} when unknown_on_unknown_refs? ->
:unknown
nil when unknown_on_unknown_refs? ->
:unknown
_value ->
case get_related(
[record],
path,
unknown_on_unknown_refs?,
join_filters,
parent_stack,
domain
) do
:unknown ->
if unknown_on_unknown_refs? do
:unknown
else
[]
end
related ->
List.wrap(related)
end
end
end
defp parent_stack(nil), do: [] defp parent_stack(nil), do: []
defp parent_stack(%resource{}), do: [resource] defp parent_stack(%resource{}), do: [resource]
defp parent_stack(value) when is_list(value), do: value defp parent_stack(value) when is_list(value), do: value

View file

@ -328,7 +328,8 @@ defmodule Ash.MixProject do
defp deps do defp deps do
[ [
# DSLs # DSLs
{:spark, "~> 2.1 and >= 2.1.18"}, # {:spark, "~> 2.1 and >= 2.1.18"},
{:spark, path: "../spark", override: true},
# Ash resources are backed by ecto scheams # Ash resources are backed by ecto scheams
{:ecto, "~> 3.7"}, {:ecto, "~> 3.7"},
# Used by the ETS data layer # Used by the ETS data layer