fix: don't optimize across or boundaries

This commit is contained in:
Zach Daniel 2023-04-20 17:30:44 -06:00
parent 2e5f045f72
commit b67c2b7f34
2 changed files with 21 additions and 17 deletions

View file

@ -804,15 +804,15 @@ defmodule Ash.Filter do
defp simple_eq?(_, _), do: false defp simple_eq?(_, _), do: false
def find_value(expr, pred) do def find_value(expr, pred) do
do_find(expr, pred, true) do_find(expr, pred, true, true)
end end
@doc "Find an expression inside of a filter that matches the provided predicate" @doc "Find an expression inside of a filter that matches the provided predicate"
def find(expr, pred) do def find(expr, pred, ors? \\ true) do
do_find(expr, pred, false) do_find(expr, pred, false, ors?)
end end
defp do_find(expr, pred, value?) do defp do_find(expr, pred, value?, ors?) do
if value = pred.(expr) do if value = pred.(expr) do
if value? do if value? do
value value
@ -822,22 +822,26 @@ defmodule Ash.Filter do
else else
case expr do case expr do
%__MODULE__{expression: expression} -> %__MODULE__{expression: expression} ->
find(expression, pred) find(expression, pred, ors?)
%Not{expression: expression} -> %Not{expression: expression} ->
find(expression, pred) find(expression, pred, ors?)
%BooleanExpression{left: left, right: right} -> %BooleanExpression{op: op, left: left, right: right} ->
find(left, pred) || find(right, pred) if op == :or && !ors? do
nil
else
find(left, pred, ors?) || find(right, pred, ors?)
end
%Call{args: arguments} -> %Call{args: arguments} ->
Enum.find(arguments, &find(&1, pred)) Enum.find(arguments, &find(&1, pred, ors?))
%{__operator__?: true, left: left, right: right} -> %{__operator__?: true, left: left, right: right} ->
find(left, pred) || find(right, pred) find(left, pred, ors?) || find(right, pred, ors?)
%{__function__?: true, arguments: arguments} -> %{__function__?: true, arguments: arguments} ->
Enum.find(arguments, &find(&1, pred)) Enum.find(arguments, &find(&1, pred, ors?))
_ -> _ ->
nil nil

View file

@ -220,15 +220,15 @@ defmodule Ash.Query.BooleanExpression do
end end
def optimized_new( def optimized_new(
op, :and,
%__MODULE__{left: left, right: right} = left_expr, %__MODULE__{op: :and, left: left, right: right} = left_expr,
right_expr, right_expr,
op op
) do ) do
case right_expr do case right_expr do
%In{} = in_op -> %In{} = in_op ->
with {:left, nil} <- {:left, Ash.Filter.find(left, &simplify?(&1, in_op))}, with {:left, nil} <- {:left, Ash.Filter.find(left, &simplify?(&1, in_op), false)},
{:right, nil} <- {:right, Ash.Filter.find(right, &simplify?(&1, in_op))} do {:right, nil} <- {:right, Ash.Filter.find(right, &simplify?(&1, in_op), false)} do
do_new(op, left_expr, in_op) do_new(op, left_expr, in_op)
else else
{:left, _} -> {:left, _} ->
@ -240,9 +240,9 @@ defmodule Ash.Query.BooleanExpression do
%Eq{} = eq_op -> %Eq{} = eq_op ->
with {:left, nil} <- with {:left, nil} <-
{:left, Ash.Filter.find(left, &simplify?(&1, eq_op))}, {:left, Ash.Filter.find(left, &simplify?(&1, eq_op), false)},
{:right, nil} <- {:right, nil} <-
{:right, Ash.Filter.find(right, &simplify?(&1, eq_op))} do {:right, Ash.Filter.find(right, &simplify?(&1, eq_op), false)} do
do_new(op, left_expr, eq_op) do_new(op, left_expr, eq_op)
else else
{:left, _} -> {:left, _} ->