defmodule Ash.Query.Operator.Eq do
@moduledoc """
left == right
The simplest operator, matches if the left and right are equal.
For comparison, this compares as mutually exclusive with other equality
and `is_nil` checks that have the same reference on the left side
"""
use Ash.Query.Operator,
operator: :==,
name: :eq,
predicate?: true,
types: [:any, :same]
def new(left, right) do
{:ok, struct(__MODULE__, left: left, right: right)}
end
def evaluate(%{left: nil}), do: {:known, nil}
def evaluate(%{right: nil}), do: {:known, nil}
def evaluate(%{left: left, right: right}) do
{:known, Comp.equal?(left, right)}
end
def can_return_nil?(%{left: left, right: right}),
do: Ash.Expr.can_return_nil?(left) or Ash.Expr.can_return_nil?(right)
@impl Ash.Filter.Predicate
def bulk_compare(predicates) do
predicates
|> Enum.filter(&match?(%struct{} when struct == __MODULE__, &1))
|> Enum.uniq()
|> Enum.reject(fn
%{right: %struct{}} when struct in [Ash.Query.Ref, Ash.Query.Call] ->
true
_ ->
false
end)
|> Enum.group_by(& &1.left)
|> Enum.flat_map(fn {_, predicates} ->
Ash.SatSolver.mutually_exclusive(predicates)
end)
end
@impl Ash.Filter.Predicate
def compare(
%__MODULE__{left: left, right: left_right},
%__MODULE__{left: left, right: right_right}
) do
if Comp.equal?(left_right, right_right) do
:mutually_inclusive
else
:mutually_exclusive
end
end
def compare(%__MODULE__{} = left, %Ash.Query.Operator.In{} = right) do
case Ash.Query.Operator.In.compare(right, left) do
:left_includes_right -> :right_includes_left
other -> other
end
end
def compare(_, _), do: :unknown
end