Normandy.Validate
(normandy v2.2.0)
View Source
Provides changeset-style validation for schemas.
This module implements validation logic for Normandy schemas, 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 =
%User{}
|> Validate.cast(params, [:name, :email, :age])
|> Validate.validate_required([:name, :email])
if changeset.valid? do
apply_changes(changeset)
else
handle_errors(changeset.errors)
end
Summary
Functions
Applies the changes of a valid changeset and returns {:ok, data}.
Returns the data apply_action/2 returns in {:ok, data}.
Returns data with the changes put in, whether or not the changeset is valid.
Casts params into a changeset on data, a schema struct.
Returns the default :empty_values of cast/4.
Returns whether field has no value in changeset: the value from get_field/2 is nil
or a string that is empty or only whitespace.
Returns the value of key: the change if there is one, else the value in data, else
default (nil) when data has no such key.
Returns the errors of changeset as a map of field to a list of msg_func results.
Casts params into every field of the schema struct data and requires the
fields declared required: true.
Validates the given parameter is true.
Runs validator on the change of field and adds the errors it returns.
Runs validator as validate_change/3 does, and first records {field, metadata} in
validations/1.
Checks that the param field_confirmation equals the param field.
Adds an "is reserved" error when the change of field is in data, an enumerable.
Adds a "has invalid format" error when the change of field does not match format.
Adds an "is invalid" error when the change of field is not in data, an enumerable.
Adds an error when the length of the change of field is not as opts asks.
Adds an error when the change of field fails a comparison in opts.
Adds a "can't be blank" error for each of fields that field_missing?/2 finds
missing, and marks fields as required.
Adds a "has an invalid entry" error when the change of field, a list, has an element
that is not in data, an enumerable.
Returns the validations recorded on changeset as {field, metadata} pairs, newest
first.
Types
@type action() :: nil | :insert | :update | :delete | :replace | :ignore | atom()
@type data() :: map()
@type t() :: t(Normandy.Schema.t() | map() | nil)
@type traverse_result() :: %{required(atom()) => [term()] | traverse_result()}
@type types() :: %{required(atom()) => Normandy.Type.t()}
Functions
@spec apply_action(t(), action()) :: {:ok, Normandy.Schema.t() | data()} | {:error, t()}
Applies the changes of a valid changeset and returns {:ok, data}.
For an invalid changeset it returns {:error, changeset} with action set. For a schema
struct the compute: fields are filled; a compute function that raises gives
{:error, changeset} with a "could not be computed (Exception)" error on that field.
Raises ArgumentError when action is not an atom.
@spec apply_action!(t(), action()) :: Normandy.Schema.t() | data()
Returns the data apply_action/2 returns in {:ok, data}.
Raises Normandy.InvalidChangesetError when apply_action/2 returns
{:error, changeset}.
@spec apply_changes(t()) :: Normandy.Schema.t() | data()
Returns data with the changes put in, whether or not the changeset is valid.
Only fields in the changeset's types are put. For a schema struct, the compute:
fields are filled. Use apply_action/2 to refuse an invalid changeset.
@spec cast( Normandy.Schema.t(), %{required(binary()) => term()} | %{required(atom()) => term()} | :invalid, [atom()], Keyword.t() ) :: t()
Casts params into a changeset on data, a schema struct.
Each key of permitted (a list of atoms) is read from params (atom or string keys)
and cast to its field's type. The result goes in changes unless it equals the current
value. A value that is empty (see :empty_values) becomes the field's default. A value
that does not cast adds an "is invalid" error and makes the changeset invalid. A
permitted key absent from params is skipped. params of :invalid gives an invalid
changeset with no changes.
Options
:empty_values- values treated as empty (defaultempty_values/0):force_changes- put a value inchangeseven when it equals the current one (defaultfalse):message-fn field, metadata -> message | nil end; a string replaces the error message of a failed cast,nilkeeps"is invalid"
Raises Normandy.CastError when params is a struct, is not a map or mixes atom and
string keys. Raises ArgumentError for a permitted key that is not an atom or not a
field of data, or a :message that is not a 2-arity function.
Example
With User, a schema with :name and :email fields:
changeset = Validate.cast(%User{}, %{"name" => "Ana"}, [:name, :email])
changeset.changes
#=> %{name: "Ana"}
@spec empty_values() :: [empty_value()]
Returns the default :empty_values of cast/4.
It is a list of functions and values. A param is empty when a function returns true
for it or when it equals a value. The default holds one function, which is true for a
string that is empty or only whitespace.
Returns whether field has no value in changeset: the value from get_field/2 is nil
or a string that is empty or only whitespace.
Raises ArgumentError when field is not an atom or not a field of the changeset.
Returns the value of key: the change if there is one, else the value in data, else
default (nil) when data has no such key.
@spec traverse_errors( t(), (error() -> String.t()) | (t(), atom(), error() -> String.t()) ) :: traverse_result()
Returns the errors of changeset as a map of field to a list of msg_func results.
msg_func is called for each {message, metadata} error with that tuple, or, as a
3-arity function, with the changeset, the field and that tuple. A changeset with no
errors gives %{}.
Example
For a changeset whose :name is required and blank:
Validate.traverse_errors(changeset, fn {message, _metadata} -> message end)
#=> %{name: ["can't be blank"]}
@spec validate( Normandy.Schema.t(), %{required(binary()) => term()} | %{required(atom()) => term()} ) :: t()
Casts params into every field of the schema struct data and requires the
fields declared required: true.
Example
changeset = Validate.validate(%Profile{}, %{"name" => "Ana"})
changeset.valid?
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 usingtraverse_errors/2.
Examples
validate_acceptance(changeset, :terms_of_service)
validate_acceptance(changeset, :rules, message: "please accept rules")
@spec validate_change( t(), atom(), (atom(), term() -> [{atom(), String.t()} | {atom(), error()}]) ) :: t()
Runs validator on the change of field and adds the errors it returns.
validator is called with the field and its new value, only when the changeset has a
change for it that is not nil, and returns a list of {field, message} or
{field, {message, metadata}}. Any error makes the changeset invalid. The data's current
value is not checked. Raises ArgumentError when field is not a field of the changeset.
Example
For a changeset with an :age field:
Validate.validate_change(changeset, :age, fn :age, age ->
if age < 0, do: [age: "must not be negative"], else: []
end)
@spec validate_change( t(), atom(), term(), (atom(), term() -> [{atom(), String.t()} | {atom(), error()}]) ) :: t()
Runs validator as validate_change/3 does, and first records {field, metadata} in
validations/1.
Checks that the param field_confirmation equals the param field.
It reads changeset.params, so it needs a changeset made by cast/4 from a map. A
mismatch adds a "does not match confirmation" error on :field_confirmation. A
changeset with no params (nil) is returned unchanged.
Options
:required- also add a"can't be blank"error when the confirmation param is absent (defaultfalse):message- the message on failure; a{message, opts}tuple adds metadata
Adds an "is reserved" error when the change of field is in data, an enumerable.
Options
:message- the message on failure; a{message, opts}tuple adds metadata
Adds a "has invalid format" error when the change of field does not match format.
Raises ArgumentError when the change is not a string.
Options
:message- the message on failure; a{message, opts}tuple adds metadata
Adds an "is invalid" error when the change of field is not in data, an enumerable.
Options
:message- the message on failure; a{message, opts}tuple adds metadata
Adds an error when the length of the change of field is not as opts asks.
The change is a string (counted in graphemes by default), a list or a map.
Options
:is- the length must be exactly this:min- the length must be at least this:max- the length must be at most this:count- for a string,:graphemes(default),:codepointsor:bytes:message- the message on failure; a{message, opts}tuple adds metadata
Adds an error when the change of field fails a comparison in opts.
Options
:less_than,:greater_than,:less_than_or_equal_to,:greater_than_or_equal_to,:equal_to,:not_equal_to- the number to compare the change with:message- the message on failure; a{message, opts}tuple adds metadata
Raises ArgumentError when the change or a compared number is not a number, or when
opts has any other key.
Adds a "can't be blank" error for each of fields that field_missing?/2 finds
missing, and marks fields as required.
A field that already has an error is skipped, and each field with a new error is removed
from changes. fields is an atom or a list of atoms.
Options
:message- the message on failure (default"can't be blank"); a{message, opts}tuple adds metadata fortraverse_errors/2
Raises ArgumentError for a field that is not an atom or not a field of the changeset.
Adds a "has an invalid entry" error when the change of field, a list, has an element
that is not in data, an enumerable.
Options
:message- the message on failure; a{message, opts}tuple adds metadata
Returns the validations recorded on changeset as {field, metadata} pairs, newest
first.
metadata is what the validation stored, such as {:format, regex}, {:length, opts} or
{:number, opts}.