lib/ash/query/function/if.ex

defmodule Ash.Query.Function.If do
  @moduledoc """
  If predicate is truthy, then the second argument is returned, otherwise the third.
  """
  use Ash.Query.Function, name: :if
  import Ash.Filter.TemplateHelpers, only: [expr?: 1]

  def args, do: [[:boolean, :any], [:boolean, :any, :any]]

  def new([condition, block]) do
    args =
      if Keyword.keyword?(block) && Keyword.has_key?(block, :do) do
        if Keyword.has_key?(block, :else) do
          [condition, block[:do], block[:else]]
        else
          [condition, block[:do], nil]
        end
      else
        [condition, block, nil]
      end

    new(args)
  end

  def new([true, block, _else_block]), do: {:ok, block}
  def new([false, _block, else_block]), do: {:ok, else_block}

  def new([condition, block, else_block]) do
    super([condition, block, else_block])
  end

  def evaluate(%{arguments: [true, when_true, _]}),
    do: {:known, when_true}

  def evaluate(%{arguments: [false, _, when_false]}),
    do: {:known, when_false}

  def evaluate(%{arguments: [nil, _, when_false]}),
    do: {:known, when_false}

  def evaluate(%{arguments: [_, when_true, _]}), do: {:known, when_true}

  def partial_evaluate(%{arguments: [false, _, when_false]}),
    do: when_false

  def partial_evaluate(%{arguments: [nil, _, when_false]}),
    do: when_false

  def partial_evaluate(%{arguments: [condition, when_true, _]} = fun) do
    if expr?(condition) do
      fun
    else
      when_true
    end
  end

  def partial_evaluate(other) do
    raise inspect(other)
  end
end