From 358a1b5cae112610ebb8da08e6373be9cff6be13 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 24 Oct 2021 14:19:38 -0400 Subject: [PATCH] fix: breaking change! disambiguating functions in keyword filter syntax it was possible to call functions in the form of `[function_name: [...args]]`, but if you had relationships that overlapped w/ the function name that would cause problems. To disambiguate, function arguments must now be provided as a tuple, e.g `[function_name: {...args}]`. --- lib/ash/filter/filter.ex | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/lib/ash/filter/filter.ex b/lib/ash/filter/filter.ex index 0ddbf6b7..e43b80cc 100644 --- a/lib/ash/filter/filter.ex +++ b/lib/ash/filter/filter.ex @@ -1602,20 +1602,19 @@ defmodule Ash.Filter do add_expression_part({attribute, [is_nil: true]}, context, expression) end - defp add_expression_part({field, nested_statement}, context, expression) - when is_atom(field) or is_binary(field) do - aggregates = - Enum.flat_map(context.aggregates, fn {key, _} -> - [key, to_string(key)] - end) + defp add_expression_part({function, args}, context, expression) + when is_tuple(args) and is_atom(function) do + case get_function(function, Ash.DataLayer.data_layer_functions(context.resource)) do + nil -> + {:error, + NoSuchAttributeOrRelationship.exception( + attribute_or_relationship: function, + resource: context.resource + )} - calculations = - Enum.flat_map(context.calculations, fn {key, _} -> - [key, to_string(key)] - end) + function_module -> + nested_statement = Tuple.to_list(args) - cond do - function_module = get_function(field, Ash.DataLayer.data_layer_functions(context.resource)) -> with {:ok, args} <- hydrate_refs(List.wrap(nested_statement), context), refs <- list_refs(args), @@ -1623,7 +1622,7 @@ defmodule Ash.Filter do validate_not_crossing_datalayer_boundaries( refs, context.resource, - {field, nested_statement} + {function, nested_statement} ), {:ok, function} <- Function.new( @@ -1640,7 +1639,22 @@ defmodule Ash.Filter do end end end + end + end + defp add_expression_part({field, nested_statement}, context, expression) + when is_atom(field) or is_binary(field) do + aggregates = + Enum.flat_map(context.aggregates, fn {key, _} -> + [key, to_string(key)] + end) + + calculations = + Enum.flat_map(context.calculations, fn {key, _} -> + [key, to_string(key)] + end) + + cond do rel = relationship(context, field) -> context = context