Skip to main content

lib/kameleoon/data/validation.ex

defmodule Kameleoon.Data.Validation do
  @moduledoc false

  @max_u32 4_294_967_295

  def keyword!(opts, defaults) when is_list(opts), do: Keyword.validate!(opts, defaults)

  def keyword!(value, _defaults) do
    raise ArgumentError, "expected options to be a keyword list, got: #{inspect(value)}"
  end

  def one_of!(value, allowed, key) do
    if value in allowed do
      value
    else
      raise ArgumentError,
            "expected #{inspect(key)} to be one of #{inspect(allowed)}, got: #{inspect(value)}"
    end
  end

  def u32!(value, _key) when is_integer(value) and value >= 0 and value <= @max_u32, do: value

  def u32!(value, key) do
    raise ArgumentError,
          "expected #{inspect(key)} to be an unsigned 32-bit integer, got: #{inspect(value)}"
  end

  def non_empty_string!(value, _key) when is_binary(value) and byte_size(value) > 0, do: value

  def non_empty_string!(value, key) do
    raise ArgumentError,
          "expected #{inspect(key)} to be a non-empty string, got: #{inspect(value)}"
  end

  def string_or_nil!(nil, _key), do: nil
  def string_or_nil!(value, _key) when is_binary(value), do: value

  def string_or_nil!(value, key) do
    raise ArgumentError, "expected #{inspect(key)} to be a string or nil, got: #{inspect(value)}"
  end

  def number_or_nil!(nil, _key), do: nil
  def number_or_nil!(value, _key) when is_number(value), do: value

  def number_or_nil!(value, key) do
    raise ArgumentError, "expected #{inspect(key)} to be a number or nil, got: #{inspect(value)}"
  end

  def boolean!(value, _key) when is_boolean(value), do: value

  def boolean!(value, key) do
    raise ArgumentError, "expected #{inspect(key)} to be a boolean, got: #{inspect(value)}"
  end

  def string_list!(values, _key) when is_list(values) do
    if Enum.all?(values, &is_binary/1) do
      values
    else
      raise ArgumentError, "expected :values to contain only strings"
    end
  end

  def string_list!(value, key) do
    raise ArgumentError, "expected #{inspect(key)} to be a list, got: #{inspect(value)}"
  end

  def integer_list!(values, _key) when is_list(values) do
    if Enum.all?(values, &is_integer/1) do
      values
    else
      raise ArgumentError, "expected :referrers to contain only integers"
    end
  end

  def integer_list!(value, key) do
    raise ArgumentError, "expected #{inspect(key)} to be a list, got: #{inspect(value)}"
  end

  def cookie_map!(cookies, _key) when is_map(cookies) do
    if Enum.all?(cookies, fn {key, value} -> is_binary(key) and is_binary(value) end) do
      cookies
    else
      raise ArgumentError, "expected cookies to be a map of string keys and string values"
    end
  end

  def cookie_map!(value, key) do
    raise ArgumentError, "expected #{inspect(key)} to be a map, got: #{inspect(value)}"
  end

  def custom_data_list!(values, _key) when is_list(values) do
    if Enum.all?(values, &custom_data?/1) do
      values
    else
      raise ArgumentError, "expected :metadata to contain only Kameleoon.Data.CustomData structs"
    end
  end

  def custom_data_list!(value, key) do
    raise ArgumentError, "expected #{inspect(key)} to be a list, got: #{inspect(value)}"
  end

  defp custom_data?(value) when is_map(value) do
    Map.get(value, :__struct__) == Kameleoon.Data.CustomData
  end

  defp custom_data?(_value), do: false
end