lib/validators/not_empty.ex

defmodule Dsv.NotEmpty do
  use Dsv.Validator, message_key_mapper: fn options -> [options] end

  @moduledoc """
  Ensure a value is not empty (default behavior) or empty if the option is set to `:false`
  Empty lists, maps, strings, and nil values are considered empty.

  Dsv.NotEmpty module provides a function to determine if a value is empty or non-empty.
  """

  message({true, "Value must not be empty"})
  message({false, "Value must be empty"})

  @doc """
  The `valid?/2` function checks if a provided value is non-empty.

  The `valid?/2` function provides a flexible approach to check the emptiness of various data types.
  It returns true for empty values and false for non-empty values.

  ## Parameters

    * `value` - The value to be checked for emptiness. This can be a list, map, string, or nil.

  ## Returns

  A boolean value:

  - `true` if `value` is empty according to the defined criteria.
  - `false` if `value` is non-empty according to the defined criteria.

  ## Emptiness Criteria

  The `valid?/2` function considers the following conditions to determine emptiness:
  - Lists with a length of 0 are considered empty.
  - Maps without any keys and values are considered empty.
  - Strings with a length of 0 are considered empty.
  - A nil value is considered empty.


  ## Example
      iex> Dsv.NotEmpty.valid?([])
      :false

      iex> Dsv.NotEmpty.valid?("")
      :false

      iex> Dsv.NotEmpty.valid?(nil)
      :false

      iex> Dsv.NotEmpty.valid?(%{})
      :false

      iex> Dsv.NotEmpty.valid?(["elem"])
      :true

      iex> Dsv.NotEmpty.valid?({})
      :false

      iex> Dsv.NotEmpty.valid?({:a})
      :true

      iex> Dsv.NotEmpty.valid?(:a)
      :true

      iex> Dsv.NotEmpty.valid?("text")
      :true

      iex> Dsv.NotEmpty.valid?(36)
      :true

      iex> Dsv.NotEmpty.valid?(%{a: :b})
      :true
  """
  def valid?(data), do: valid?(data, true)

  @doc """
  The `valid?/2` function checks if a provided value is empty or non-empty, with second parameter
  that can reverse the behavior.

  The `valid?/2` function provides a flexible approach to check the emptiness of various data types.
  It returns true for empty values and false for non-empty values when second parameter is set to :true. However, you can reverse
  this behavior by setting the second parameter to :false.

  ## Parameters

    * `value` - The value to be checked for emptiness. This can be a list, map, string, or nil.
    * `:is_empty` - A boolean value that, when set to :false, reverses the function's behavior,
      returning true for empty values and false for non-empty values.

  ## Returns

  A boolean value:

  - `true` if `value` is empty according to the defined criteria.
  - `false` if `value` is non-empty according to the defined criteria.

  ## Emptiness Criteria

  The `valid?/2` function considers the following conditions to determine emptiness:
  - Lists with a length of 0 are considered empty.
  - Maps without any keys and values are considered empty.
  - Strings with a length of 0 are considered empty.
  - A nil value is considered empty.


  ## Example
      iex> Dsv.NotEmpty.valid?(%{}, true)
      :false

      iex> Dsv.NotEmpty.valid?({}, :false)
      :true

      iex> Dsv.NotEmpty.valid?({:a}, :false)
      :false

      iex> Dsv.NotEmpty.valid?(:a, :false)
      :false

      iex> Dsv.NotEmpty.valid?(%{a: :b}, true)
      :true

      iex> Dsv.NotEmpty.valid?([], false)
      :true

      iex> Dsv.NotEmpty.valid?(nil, false)
      :true

      iex> Dsv.NotEmpty.valid?(36, false)
      :false

      iex> Dsv.NotEmpty.valid?("text", false)
      :false
  """
  def valid?(data, true), do: not Dsv.Empty.empty?(data)
  def valid?(data, false), do: Dsv.Empty.empty?(data)
  def valid?(data, _options), do: not Dsv.Empty.empty?(data)

  @doc """
  The `validate/2` function checks if a provided value is empty or non-empty, with an optional parameter
  to reverse the behavior.

  The `validate/2` function provides a flexible approach to check the emptiness of various data types.
  By default, it returns true for empty values and false for non-empty values. However, you can reverse
  this behavior by setting the second parameter to :false.

  ## Parameters

    * `value` - The value to be checked for emptiness. This can be a list, map, string, or nil.
    * `:is_empty` (optional, default: true) - A boolean value that, when set to :false, reverses the function's behavior,
      returning true for empty values and false for non-empty values.

  ## Returns

  - `:ok` if `value` is empty according to the defined criteria.
  - `{:error, message}` if `value` is non-empty according to the defined criteria.

  ## Emptiness Criteria

  The `valid?/2` function considers the following conditions to determine emptiness:
  - Lists with a length of 0 are considered empty.
  - Maps without any keys and values are considered empty.
  - Strings with a length of 0 are considered empty.
  - A nil value is considered empty.

  ## Example
      iex> Dsv.NotEmpty.validate([])
      {:error, "Value must not be empty"}

      iex> Dsv.NotEmpty.validate("")
      {:error, "Value must not be empty"}

      iex> Dsv.NotEmpty.validate(nil)
      {:error, "Value must not be empty"}

      iex> Dsv.NotEmpty.validate(%{})
      {:error, "Value must not be empty"}

      iex> Dsv.NotEmpty.validate(%{}, true)
      {:error, "Value must not be empty"}

      iex> Dsv.NotEmpty.validate(["elem"])
      :ok

      iex> Dsv.NotEmpty.validate({})
      {:error, "Value must not be empty"}

      iex> Dsv.NotEmpty.validate({:a})
      :ok

      iex> Dsv.NotEmpty.validate({}, :false)
      :ok

      iex> Dsv.NotEmpty.validate({:a}, :false)
      {:error, "Value must be empty"}

      iex> Dsv.NotEmpty.validate(:a)
      :ok

      iex> Dsv.NotEmpty.validate(:a, :false)
      {:error, "Value must be empty"}

      iex> Dsv.NotEmpty.validate("text")
      :ok

      iex> Dsv.NotEmpty.validate(36)
      :ok

      iex> Dsv.NotEmpty.validate(%{a: :b})
      :ok

      iex> Dsv.NotEmpty.validate(%{a: :b}, true)
      :ok

      iex> Dsv.NotEmpty.validate([], false)
      :ok

      iex> Dsv.NotEmpty.validate(nil, false)
      :ok

      iex> Dsv.NotEmpty.validate(36, false)
      {:error, "Value must be empty"}

      iex> Dsv.NotEmpty.validate("text", false)
      {:error, "Value must be empty"}


  """
  def validate(data, []), do: super(data, true)
  def validate(data, options), do: super(data, options)
end