View Source CozyKV (cozy_kv v0.1.0)
Validates data containing key-value pairs.
Features
- Supports any type of key, not limited to atoms.
- Provides errors with detailed metadata, which is useful to build custom error messages.
Terminologies
- spec - a list which describes the structure of key-value pairs.
- data - the key-value pairs to be validated using a spec.
Usage
# 1. create a raw spec
spec = [
name: [type: :string, required: true]
]
# 2. validate the spec
spec = CozyKV.validate_spec!(spec)
# 3. validate a piece of data using above spec
# 3.1 validate key-value pairs in list form.
kv_list = [name: "zeke"]
{:ok, [name: "zeke"]} = CozyKV.validate(spec, kv_list)
# 3.2 validate key-value pairs in map form.
kv_map = %{name: "zeke"}
{:ok, %{name: "zeke"}} = CozyKV.validate(spec, kv_map)
# 3.3 when validation fails, an error is returned
kv_bad = []
{:error, %CozyKV.ValidationError{path: _, type: _}} = CozyKV.validate(spec, kv_bad)
Specs
A valid spec is a list of two-element tuples.
In each tuple, the first element is the key, the second element is the spec options of the value correspoding to the key.
atom key
[
name: [
type: :string,
required: true
],
# ...
]
string key
[
{"name", [
type: :string,
required: true
]},
# ...
]
arbitrary key
# allows to use arbitrary key in any type.
[
{%{}, [
type: :string,
required: true
]},
# ...
]
Spec options
These options are supported:
:type
:required
:default
:deprecated
:doc
Types and Values
The left side of
-
is the type name, and the right side is the description of the value corresponding to the type.
:any
- Any value.nil
-nil
itself.:atom
- An atom.:boolean
- A boolean.:string
- A string.:integer
- An integer.:pos_integer
- A positive integer.:non_neg_integer
- A non-negative integer.:float
- A float.:tuple
- A tuple.{:tuple, subtypes}
- A tuple as described bysubtypes
. The length of the expected tuple must match the length ofsubtypes
. The type of each element in tuple must match the type at the same position ofsubtypes
. For example, a valid value of{:tuple, [:atom, :string, {:list, :integer}]}
can be{:name, "zeke", [3, 2, 2]}
.:list
- A list.{:list, subtype}
- A list with elements of typesubtype
.:keyword_list
- A keyword list.{:keyword_list, spec}
- A keyword list with key-value pairs structured byspec
.:non_empty_keyword_list
- A non-empty keyword list.{:non_empty_keyword_list, spec}
- A non-empty keyword list with key-value pairs structured byspec
.:map
- A map with atom keys. It is a shortcut of{:map, :atom, :any}
.{:map, key_type, value_type}
- A map withkey_type
keys andvalue_type
values.{:map, spec}
- A map with key-value pairs structured byspec
.{:struct, struct_name}
- A struct.:timeout
- A non-negative integer or the atom:infinity
.:pid
- A PID.:reference
- A reference (seereference/0
).:mfa
- A tuple in the format{mod, fun, args}
.{:fun, arity}
- A function with a specificarity
.:mod_args
- A tuple in the format{mod, args}
. It is usually used for process initialization usingstart_link
and similar.{:value_in, values}
- A value which is one of the values invalues
.values
can be any enumerable value, such as a list or a%Range{}
.{:type_in, subtypes}
- A value which matches one of the types insubtypes
.subtypes
is a list of types.{:custom, mod, fun}
- A custom type. The related value will be validated byapply(mod, fun, [type, value, metadata])
.type
is the{:custom, mod, fun}
itself.mod.fun(type, value, metadata)
must return{:ok, value}
or{:error, exception}
.
Data
A valid piece of data is a list of two-element tuples or a map.
list (atom key)
[
name: "zeke",
# ...
]
list (string key)
[
{"name", "zeke"},
# ...
]
list (arbitrary key)
# In general, you don't do this.
# I just want to demonstrate what this package can do.
[
{%{}, "zeke"},
# ...
]
map (atom key)
%{
name: "zeke",
# ...
}
map (string key)
%{
"name" => "zeke",
# ...
}
map (arbitrary key)
# In general, you don't do this.
# I just want to demonstrate what this package can do.
%{
%{} => "zeke",
# ...
}
Use cases
- validate options (like what nimble_options does).
- validate maps parsed from a JSON or YAML files.
Limitations
validate_spec!/1
doesn't validate the inner spec of a nested spec.
Todo
- doc generation
Summary
Types
Functions
@spec validate(spec(), data()) :: {:ok, data()} | {:error, CozyKV.ValidationError.t()}
Validates a key-value data.
Bang version of validate/2
.
Validates a spec.