From 4b88300e007a67bee72ed030954d10ce4097b868 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 14 Sep 2022 20:05:51 -0400 Subject: [PATCH] fix: properly surface errors all the way from runtime filters --- lib/ash/data_layer/simple/simple.ex | 33 ++++++++++++++++++---------- lib/ash/filter/runtime.ex | 34 ++++++++++++++++++++++++----- logos/ascii-art.ans | 27 +++++++++++++++++++++++ 3 files changed, 77 insertions(+), 17 deletions(-) create mode 100644 logos/ascii-art.ans diff --git a/lib/ash/data_layer/simple/simple.ex b/lib/ash/data_layer/simple/simple.ex index 4b94811f..3def23bb 100644 --- a/lib/ash/data_layer/simple/simple.ex +++ b/lib/ash/data_layer/simple/simple.ex @@ -55,17 +55,28 @@ defmodule Ash.DataLayer.Simple do end def run_query(%{data: data, sort: sort, api: api, filter: filter, limit: limit}, _resource) do - {:ok, - data - |> Enum.filter(&Ash.Filter.Runtime.matches?(api, &1, filter)) - |> Ash.Actions.Sort.runtime_sort(sort) - |> then(fn data -> - if limit do - Enum.take(data, limit) - else - data - end - end)} + data + |> do_filter_matches(filter, api) + |> case do + {:ok, results} -> + {:ok, + results + |> Ash.Actions.Sort.runtime_sort(sort) + |> then(fn data -> + if limit do + Enum.take(data, limit) + else + data + end + end)} + + {:error, error} -> + {:error, error} + end + end + + defp do_filter_matches(data, filter, api) do + Ash.Filter.Runtime.filter_matches(api, data, filter) end @doc false diff --git a/lib/ash/filter/runtime.ex b/lib/ash/filter/runtime.ex index e80af68b..c071cc86 100644 --- a/lib/ash/filter/runtime.ex +++ b/lib/ash/filter/runtime.ex @@ -37,10 +37,25 @@ defmodule Ash.Filter.Runtime do |> Enum.map(&path_to_load/1) |> case do [] -> - {:ok, - Enum.filter(records, fn record -> - matches?(nil, record, filter) - end)} + Enum.reduce_while(records, {:ok, []}, fn record, {:ok, records} -> + case matches(record, filter) do + {:ok, falsey} when falsey in [false, nil] -> + {:cont, {:ok, records}} + + {:ok, _} -> + {:cont, {:ok, [record | records]}} + + {:error, error} -> + {:halt, {:error, error}} + end + end) + |> case do + {:ok, records} -> + {:ok, Enum.reverse(records)} + + other -> + other + end need_to_load when not loaded? -> case api.load(records, need_to_load) do @@ -85,12 +100,15 @@ defmodule Ash.Filter.Runtime do {:load, loads} when not is_nil(api) -> matches?(api, api.load!(record, loads), filter) + {:error, _} -> + false + {:load, _} -> false end end - def matches(record, expression) do + def matches(record, expression, load_with \\ nil) do relationship_paths = expression |> Ash.Filter.relationship_paths(true) @@ -116,7 +134,11 @@ defmodule Ash.Filter.Runtime do end) need_to_load -> - {:load, Enum.map(need_to_load, &path_to_load/1)} + if load_with do + matches(load_with.load!(record, need_to_load), expression, load_with) + else + {:load, Enum.map(need_to_load, &path_to_load/1)} + end end end diff --git a/logos/ascii-art.ans b/logos/ascii-art.ans new file mode 100644 index 00000000..61ac8528 --- /dev/null +++ b/logos/ascii-art.ans @@ -0,0 +1,27 @@ +                                        (                                       +                                      *(((                                      +                                     (((((((                                    +                                   ((((((((((                                   +                                  (((((((((((((                                 +                                ((((((((((((((((/                               +                               (((((((((((((((((((                              +                              ((((((((((((((((((((((                            +                            (##((((((((((((((((((((((                           +                          #(###### ((((((((((((((((((((                         +                        (# ##########(((((((((((((((((((.                       +                       ## ############# ((((((((((((((((((                      +                     ###*#################,((((((((((((((((,                    +                    ######################## ((((((((((((((((                   +                  ######################### ##  (((((((((((((((                 +                ,#####(##################.#####/##((((((((((((((                +               ######.################# #########(## (((((((((((((              +             ####### ################ ############ ####*(((((((((((             +            #######.############### ##################### (((((((((((           +          #######################,#*((/,#############.######*(((((((((*         +        .###################### ###((((((( ###########.####### (((((((((        +       ######################.####/((((((((((( ################## (((((((*      +     /##########.##########/###### ((((((((((((((/####### #########/(((((((     +    ########### #########,######## (((((((((((((((((( ################ ((((((   +  ############ ########,##########.(((((((((((((((((((((*%##,############/((((, + ############ #######(############((((((((((((((((((((((((((  ############# (((( + \ No newline at end of file