lib/formula/function/decimal_operation.ex

defmodule Formula.Function.DecimalOperation do
  @moduledoc """
  Process decimal operation
  """
  alias Formula.Errors.DivideByZeroError
  alias Formula.Errors.InvalidFormulaError

  @type success :: Decimal.t()
  @type failure :: {:error, DivideByZeroError.t()} | {:error, InvalidFormulaError.t()}

  @spec call(atom(), list(Decimal.t())) :: success | failure
  def call(:+, [a, b]), do: Decimal.add(a, b)

  def call(:-, [a, b]), do: Decimal.sub(a, b)

  def call(:*, [a, b]), do: Decimal.mult(a, b)

  def call(:/, [a, b]) do
    if Decimal.eq?(b, Decimal.new("0")) do
      {:error, DivideByZeroError.exception(message: "Cannot divide by zero")}
    else
      Decimal.div(a, b)
    end
  end

  def call(name, arguments) do
    {:error,
     InvalidFormulaError.exception(message: "Invalid formula", name: name, arguments: arguments)}
  end
end