Normandy.Validate (normandy v0.2.0)

View Source

Provides changeset-style validation for schemas.

This module implements validation logic similar to Ecto changesets, allowing you to validate data before creating or updating structs.

Features

  • Required field validation
  • Type casting and validation
  • Custom validation functions
  • Error accumulation
  • Change tracking

Example

changeset = Validate.validate(data, params, types, required: [:name, :email])

if changeset.valid? do
  apply_changes(changeset)
else
  handle_errors(changeset.errors)
end

Summary

Types

action()

@type action() :: nil | :insert | :update | :delete | :replace | :ignore | atom()

constraint()

@type constraint() :: %{
  type: :check | :exclusion | :foreign_key | :unique,
  constraint: String.t() | Regex.t(),
  match: :exact | :suffix | :prefix,
  field: atom(),
  error_message: String.t(),
  error_type: atom()
}

data()

@type data() :: map()

empty_value()

@type empty_value() :: (term() -> boolean()) | binary() | list() | map() | tuple()

error()

@type error() :: {String.t(), Keyword.t()}

t()

@type t() :: t(Normandy.Schema.t() | map() | nil)

t(data_type)

@type t(data_type) :: %Normandy.Validate{
  action: action(),
  changes: term(),
  constraints: [constraint()],
  data: data_type,
  errors: [{atom(), error()}],
  filters: %{optional(atom()) => term()},
  params: %{optional(String.t()) => term()} | nil,
  prepare: [(t() -> t())],
  required: [atom()],
  types: types(),
  valid?: boolean(),
  validations: [validation()]
}

traverse_result()

@type traverse_result() :: %{required(atom()) => [term()] | traverse_result()}

types()

@type types() :: %{
  required(atom()) => Normandy.Type.t() | {:assoc, term()} | {:embed, term()}
}

validation()

@type validation() :: {atom(), term()}

Functions

apply_action(changeset, action)

@spec apply_action(t(), action()) ::
  {:ok, Normandy.Schema.t() | data()} | {:error, t()}

apply_action!(changeset, action)

@spec apply_action!(t(), action()) :: Normandy.Schema.t() | data()

apply_changes(validate)

@spec apply_changes(t()) :: Normandy.Schema.t() | data()

cast(data, params, permitted, opts \\ [])

@spec cast(
  Normandy.Schema.t() | t() | {data(), types()},
  %{required(binary()) => term()} | %{required(atom()) => term()} | :invalid,
  [atom()],
  Keyword.t()
) :: t()

empty_values()

@spec empty_values() :: [empty_value()]

field_missing?(changeset, field)

@spec field_missing?(t(), atom()) :: boolean()

get_field(validate, key, default \\ nil)

@spec get_field(t(), atom(), term()) :: term()

traverse_errors(changeset, msg_func)

@spec traverse_errors(
  t(),
  (error() -> String.t()) | (t(), atom(), error() -> String.t())
) ::
  traverse_result()

validate(data, params)

validate_acceptance(changeset, field, opts \\ [])

@spec validate_acceptance(t(), atom(), Keyword.t()) :: t()

Validates the given parameter is true.

Note this validation only checks the parameter itself is true, never the field in the schema. That's because acceptance parameters do not need to be persisted, as by definition they would always be stored as true.

Options

  • :message - the message on failure, defaults to "must be accepted". Can also be a {msg, opts} tuple, to provide additional options when using traverse_errors/2.

Examples

validate_acceptance(changeset, :terms_of_service)
validate_acceptance(changeset, :rules, message: "please accept rules")

validate_change(changeset, field, validator)

@spec validate_change(
  t(),
  atom(),
  (atom(), term() -> [{atom(), String.t()} | {atom(), error()}])
) :: t()

validate_change(changeset, field, metadata, validator)

@spec validate_change(
  t(),
  atom(),
  term(),
  (atom(), term() -> [{atom(), String.t()} | {atom(), error()}])
) :: t()

validate_confirmation(changeset, field, opts \\ [])

@spec validate_confirmation(t(), atom(), Keyword.t()) :: t()

validate_exclusion(changeset, field, data, opts \\ [])

@spec validate_exclusion(t(), atom(), Enum.t(), Keyword.t()) :: t()

validate_format(changeset, field, format, opts \\ [])

@spec validate_format(t(), atom(), Regex.t(), Keyword.t()) :: t()

validate_inclusion(changeset, field, data, opts \\ [])

@spec validate_inclusion(t(), atom(), Enum.t(), Keyword.t()) :: t()

validate_length(changeset, field, opts)

@spec validate_length(t(), atom(), Keyword.t()) :: t()

validate_number(changeset, field, opts)

@spec validate_number(t(), atom(), Keyword.t()) :: t()

validate_required(changeset, fields, opts \\ [])

@spec validate_required(t(), list() | atom(), Keyword.t()) :: t()

validate_subset(changeset, field, data, opts \\ [])

@spec validate_subset(t(), atom(), Enum.t(), Keyword.t()) :: t()

validations(validate)

@spec validations(t()) :: [{atom(), term()}]