diff --git a/lib/ash/filter/filter.ex b/lib/ash/filter/filter.ex index 47d8c600..6a7b8a82 100644 --- a/lib/ash/filter/filter.ex +++ b/lib/ash/filter/filter.ex @@ -22,6 +22,7 @@ defmodule Ash.Filter do Eq, GreaterThan, GreaterThanOrEqual, + Has, In, LessThan, LessThanOrEqual, @@ -45,7 +46,8 @@ defmodule Ash.Filter do LessThan, GreaterThan, LessThanOrEqual, - GreaterThanOrEqual + GreaterThanOrEqual, + Has ] ++ Ash.Query.Operator.Basic.operator_modules() @builtins @functions ++ @operators diff --git a/lib/ash/query/operator/has.ex b/lib/ash/query/operator/has.ex new file mode 100644 index 00000000..b94da6ad --- /dev/null +++ b/lib/ash/query/operator/has.ex @@ -0,0 +1,17 @@ +defmodule Ash.Query.Operator.Has do + @moduledoc """ + left has 1 + + this predicate matches if the right is in the list on the left + + This actually just reverses the inputs and uses `in`. + """ + use Ash.Query.Operator, + operator: :has, + predicate?: true, + types: [[{:array, :any}, :same]] + + def new(left, right) do + Ash.Query.Operator.In.new(right, left) + end +end diff --git a/lib/ash/query/operator/operator.ex b/lib/ash/query/operator/operator.ex index 6b0fb5db..6c07f98d 100644 --- a/lib/ash/query/operator/operator.ex +++ b/lib/ash/query/operator/operator.ex @@ -211,7 +211,8 @@ defmodule Ash.Query.Operator do Ash.Query.Operator.IsNil, Ash.Query.Operator.LessThanOrEqual, Ash.Query.Operator.LessThan, - Ash.Query.Operator.NotEq + Ash.Query.Operator.NotEq, + Ash.Query.Operator.Has ] ++ Ash.Query.Operator.Basic.operator_modules() end diff --git a/lib/ash/query/query.ex b/lib/ash/query/query.ex index 5087e541..d3ed3056 100644 --- a/lib/ash/query/query.ex +++ b/lib/ash/query/query.ex @@ -481,6 +481,13 @@ defmodule Ash.Query do soft_escape(%Ash.Query.Call{name: op, args: args, operator?: true}, escape?) end + defp do_expr({left, _, [{op, _, [right]}]}, escape?) + when is_atom(op) and op in @operator_symbols and is_atom(left) do + args = Enum.map([{left, [], nil}, right], &do_expr(&1, false)) + + soft_escape(%Ash.Query.Call{name: op, args: args, operator?: true}, escape?) + end + defp do_expr({op, _, args}, escape?) when is_atom(op) and is_list(args) do args = Enum.map(args, &do_expr(&1, false))