defmodule Ash.Query.Operator.IsNil do @moduledoc """ left is_nil true/false This predicate matches if the left is nil when the right is `true` or if the left is not nil when the right is `false` """ use Ash.Query.Operator, operator: :is_nil, predicate?: true, types: [[:any, :boolean]] def new(nil, true), do: {:ok, true} def new(nil, false), do: {:ok, false} def new(left, right) do super(left, right) end @impl Ash.Query.Operator def evaluate_nil_inputs?, do: true @impl Ash.Query.Operator def evaluate(%{right: nil}), do: {:known, nil} def evaluate(%{left: left, right: is_nil?}) do {:known, is_nil(left) == is_nil?} end def to_string(%{left: left, right: right}, opts) do import Inspect.Algebra cond do right == true -> concat([ to_doc(left, opts), " is nil" ]) right == false -> concat([ to_doc(left, opts), " is not nil" ]) true -> concat([ " is_nil(", to_doc(left, opts), ") == ", to_doc(right, opts) ]) end end @impl Ash.Filter.Predicate def compare(%__MODULE__{left: %Ref{} = same_ref, right: true}, %Ash.Query.Operator.Eq{ left: %Ref{} = same_ref, right: nil }) do :mutually_inclusive end def compare(%__MODULE__{left: %Ref{} = same_ref, right: false}, %Ash.Query.Operator.Eq{ left: %Ref{} = same_ref, right: nil }) do :mutually_exclusive_and_collectively_exhaustive end def compare(%__MODULE__{left: %Ref{} = same_ref, right: false}, %Ash.Query.Operator.Eq{ left: %Ref{} = same_ref, right: %Ref{} }) do :unknown end def compare(%__MODULE__{left: %Ref{} = same_ref, right: false}, %Ash.Query.Operator.Eq{ left: %Ref{} = same_ref }) do :right_includes_left end def compare(%__MODULE__{left: %Ref{} = same_ref, right: true}, %__MODULE__{ left: %Ref{} = same_ref, right: false }) do :mutually_exclusive_and_collectively_exhaustive end def compare(%__MODULE__{left: %Ref{} = same_ref, right: false}, %__MODULE__{ left: %Ref{} = same_ref, right: true }) do :mutually_exclusive_and_collectively_exhaustive end def compare(%__MODULE__{left: %Ref{} = same_ref, right: right}, %__MODULE__{ left: %Ref{} = same_ref, right: right }) when is_boolean(right) do :mutually_inclusive end def compare(_left, _right) do :unknown end end