defmodule Ash.Query.Operator.Basic do @operators [ plus: [ symbol: :+, no_nils: true ], times: [ symbol: :*, no_nils: true ], minus: [ symbol: :-, no_nils: true ], div: [ symbol: :/, no_nils: true ], concat: [ symbol: :<>, no_nils: true ], or: [ symbol: :|| ], and: [ symbol: :&& ] ] Module.register_attribute(__MODULE__, :operator_modules, accumulate: true) for {name, opts} <- @operators do mod = Module.concat([__MODULE__, String.capitalize(to_string(name))]) @operator_modules mod Module.create( mod, quote generated: true do @moduledoc """ left #{unquote(opts[:symbol])} right """ use Ash.Query.Operator, operator: unquote(opts[:symbol]), name: unquote(name), predicate?: false, types: [:same, :any] if unquote(opts[:no_nils]) do def evaluate(%{left: left, right: right}) do if is_nil(left) || is_nil(right) do {:known, nil} else # delegate to function to avoid dialyzer warning # that this can only ever be one value (for each module we define) do_evaluate(unquote(opts[:symbol]), left, right) end end else def evaluate(%{left: left, right: right}) do # delegate to function to avoid dialyzer warning # that this can only ever be one value (for each module we define) do_evaluate(unquote(opts[:symbol]), left, right) end end defp do_evaluate(:<>, left, right) do {:known, to_string(left) <> to_string(right)} end defp do_evaluate(:||, left, right) do {:known, left || right} end defp do_evaluate(:&&, left, right) do {:known, left && right} end defp do_evaluate(op, left, right) do {:known, apply(Kernel, unquote(opts[:symbol]), [left, right])} end end, Macro.Env.location(__ENV__) ) end def operator_modules do @operator_modules end end