lib/validators/or.ex

defmodule Dsv.Or do
  use Dsv.Validator

  @moduledoc """
  Dsv.Or module provides functions to validate a value against multiple validators.
  The validation success as soon as at least one of the validators passes.
  """

  message("At least one validator must be valid.")

  @doc """
  The `valid?/2` function checks if a provided value passes any of the specified validators.

  ## Parameters

    * `value` - The value to be validated.
    * `validators` - A list of validators.

  ## Returns

  A boolean value:

  - `true` if the `value` passes at least one of the specified validators.
  - `false` if the `value` fails all of the specified validators.

  ## Example

      iex> Dsv.Or.valid?("testowy", equal: "tes", length: [min: 1, max: 20], format: ~r/t.*wyc/)
      :true

      iex> Dsv.Or.valid?("testowy", equal: "tes", length: [min: 1, max: 2], format: ~r/t.*wyc/)
      :false


  This code will check if value is equal to "tes" and has min length of 2 or it has min length of 1, max length of 2 or match regular expression /t.*wyc/.

      iex> Dsv.Or.valid?("testowy", [[equal: "tes", length: [min: 2]], length: [min: 1, max: 2], format: ~r/t.*wyc/])
      :false

  """
  def valid?(data, options),
    do: options |> Enum.any?(fn validators -> Dsv.valid?(data, validators) end)

  @doc """
  The `validate/2` function checks if a provided value passes any of the specified validators.

  ## Parameters

    * `value` - The value to be validated.
    * `validators` - A list of validators.
    * `message` - An optional custom message that will be returned in case of error.

  ## Returns

  - `:ok` if the `value` passes at least one of the specified validators.
  - `{:error, message}` if the `value` fails all of the specified validators.

  ## Example

      iex> Dsv.Or.validate("testowy", equal: "tes", length: [min: 1, max: 20], format: ~r/t.*wyc/)
      :ok

      iex> Dsv.Or.validate("testowy", equal: "tes", length: [min: 1, max: 2], format: ~r/t.*wyc/)
      {:error, "At least one validator must be valid."}

      iex> Dsv.Or.validate("testowy", [[equal: "tes", length: [min: 2]], length: [min: 1, max: 2], format: ~r/t.*wyc/])
      {:error, "At least one validator must be valid."}

      iex> Dsv.Or.validate("testowy", equal: "tes", length: [min: 1, max: 2], format: ~r/t.*wyc/, message: "You will never provide valid value.")
      {:error, "You will never provide valid value."}


      iex> Dsv.Or.validate("testowy", [[equal: "testowy", length: [min: 2]], length: [min: 1, max: 2], format: ~r/t.*wyc/])
      :ok

      iex> Dsv.Or.validate("testowy", [[equal: "testowy", length: [max: 2]], length: [min: 1, max: 20], format: ~r/t.*wyc/])
      :ok
  """
  def validate(data, options), do: super(data, options)
end