lib/helper.ex

defmodule Request.Validator.Helper do
  alias Request.Validator.Rules

  @doc """
  A wrapper around the `{:in_list, options}` rule.

  ## Examples
      iex> Request.Validator.Helper.in_list(["male", "female"])
      {:in_list, ~w[male female]}
      iex> Request.Validator.Helper.in_list(~w[tech law finance])
      {:in_list, ["tech", "law", "finance"]}
      iex> Request.Validator.Helper.in_list(~w[doctor nurse nurse midwife specialist midwife doctor])
      {:in_list, ~w[doctor nurse midwife specialist]}
  """
  @spec in_list(list(any())) :: {:in_list, list(any())}
  def in_list(options) when is_list(options), do: {:in_list, Enum.uniq(options)}

  @doc """
  A wrapper around the `{:gt, field}` rule.

  ## Examples
      iex> Request.Validator.Helper.gt(:age)
      {:gt, :age}
      iex> Request.Validator.Helper.gt(:year)
      {:gt, :year}
  """
  @spec gt(atom()) :: {:gt, atom()}
  def gt(field), do: {:gt, field}

  @doc """
  A wrapper around the `{:lt, field}` rule.

  ## Examples
      iex> Request.Validator.Helper.lt(:age)
      {:lt, :age}
      iex> Request.Validator.Helper.lt(:year)
      {:lt, :year}
  """
  @spec lt(atom()) :: {:lt, atom()}
  def lt(field), do: {:lt, field}

  @doc """
  A wrapper around the `{:max, value}` rule.

  ## Examples
      iex> Request.Validator.Helper.max(30)
      {:max, 30}
      iex> Request.Validator.Helper.max(40)
      {:max, 40}
  """
  @spec max(number()) :: {:max, number()}
  def max(value) when is_number(value), do: {:max, value}

  @doc """
  A wrapper around the `{:min, value}` rule.

  ## Examples
      iex> Request.Validator.Helper.min(30)
      {:min, 30}
      iex> Request.Validator.Helper.min(40)
      {:min, 40}
  """
  @spec min(number()) :: {:min, number()}
  def min(value), do: {:min, value}

  @doc """
  A wrapper around the `required` rule.

  ## Examples
      iex> Request.Validator.Helper.required(:string)
      ~w[required string]a
      iex> Request.Validator.Helper.required([:string, :email, {:max, 100}])
      [:required, :string, :email, {:max, 100}]
      iex> Request.Validator.Helper.required({:max, 100})
      [:required, {:max, 100}]
  """
  def required(rule) when is_atom(rule), do: required([rule])
  def required(rule) when is_tuple(rule), do: required([rule])
  def required(rules) when is_list(rules), do: [:required] ++ rules

  @doc """
  A wrapper around the `{:size, value}` rule.

  ## Examples
      iex> Request.Validator.Helper.size(30)
      {:size, 30}
      iex> Request.Validator.Helper.size(40)
      {:size, 40}
  """
  @spec size(number()) :: {:size, number()}
  def size(value), do: {:size, value}

  @doc """
  Makes a nested map input validation nullable.

  ## Examples
      iex> alias Request.Validator.{Helper, Rules}
      [Request.Validator.Helper, Request.Validator.Rules]
      iex> Helper.nullable(Rules.map(name: ~w[required string]a))
      %Rules.Object{attrs: [name: ~w[required string]a], nullable: true}
      iex> Rules.map(name: ~w[required string]a)
      %Rules.Object{attrs: [name: ~w[required string]a], nullable: false}
  """
  def nullable(%Rules.Object{} = map), do: struct!(map, %{nullable: true})

  @doc """
  A wrapper around the `{:unique, callback}` rule.

  ## Examples
      iex> alias Request.Validator.Helper
      Request.Validator.Helper
      iex> {:unique, _} = Helper.unique(&(&1 == 10))
  """
  def unique(callback), do: {:unique, callback}

  @doc """
  A wrapper around the `{:exists, callback}` rule.

  ## Examples
      iex> alias Request.Validator.Helper
      Request.Validator.Helper
      iex> {:exists, _} = Helper.exists(&(&1 == 10))
  """
  def exists(callback), do: {:exists, callback}
end