Packages
zoi
0.9.0-rc.0
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.1
0.16.0
0.15.0
0.14.1
0.14.0
0.13.1
0.13.0
0.12.1
0.12.0
0.11.1
0.11.0
0.10.7
0.10.6
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.1
0.9.0
0.9.0-rc.1
0.9.0-rc.0
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.0
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.3
0.1.2
0.1.1
0.1.0
Zoi is a schema validation library for Elixir, designed to provide a simple and flexible way to define and validate data.
Current section
Files
Jump to
Current section
Files
lib/zoi/types/meta.ex
defmodule Zoi.Types.Meta do
@moduledoc false
@type t :: %__MODULE__{
refinements: [Zoi.refinement()],
transforms: [Zoi.transform()],
error: binary() | nil,
required: boolean(),
description: binary() | nil,
example: Zoi.input(),
metadata: [keyword()]
}
@struct_fields [
refinements: [],
transforms: [],
metadata: [],
required: nil,
error: nil,
description: nil,
example: nil
]
@struct_keys Keyword.keys(@struct_fields)
defstruct @struct_fields
@spec create_meta(keyword()) :: {t(), keyword()}
def create_meta(opts) do
{meta_opts, rest_opts} = split_keyword(opts)
{struct!(__MODULE__, meta_opts), rest_opts}
end
defp split_keyword(opts) when is_list(opts) do
Enum.reduce(opts, {[], []}, fn {k, v}, {meta_opts, rest_opts} ->
if k in @struct_keys do
{Keyword.put(meta_opts, k, v), rest_opts}
else
{meta_opts, Keyword.put(rest_opts, k, v)}
end
end)
end
@spec run_refinements(schema :: Zoi.Type.t(), ctx :: Zoi.Context.t()) ::
{:ok, Zoi.input()} | {:error, [Zoi.Errors.t()]}
def run_refinements(schema, %Zoi.Context{parsed: input} = ctx) do
schema.meta.refinements
|> Enum.reduce({{:ok, input}, []}, fn
{mod, func, args}, {{:ok, input}, errors} ->
case apply(mod, func, [input] ++ args ++ [[ctx: ctx]]) do
:ok ->
{{:ok, input}, errors}
{:error, err} ->
{{:ok, input}, Zoi.Errors.add_error(errors, err)}
%Zoi.Context{} = context ->
{{:ok, context.parsed}, context.errors}
end
refine_func, {{:ok, input}, errors} ->
cond do
is_function(refine_func, 1) ->
refine_func.(input)
is_function(refine_func, 2) ->
refine_func.(input, ctx)
end
|> case do
:ok ->
{{:ok, input}, errors}
{:error, err} ->
{{:ok, input}, Zoi.Errors.add_error(errors, err)}
%Zoi.Context{} = context ->
{{:ok, context.parsed}, context.errors}
end
end)
|> then(fn {{:ok, value}, errors} ->
if Enum.empty?(errors) do
{:ok, value}
else
{:error, errors}
end
end)
end
@spec run_transforms(schema :: Zoi.Type.t(), ctx :: Zoi.Context.t()) ::
{:ok, Zoi.input()} | {:error, [Zoi.Errors.t()]}
def run_transforms(schema, %Zoi.Context{parsed: input} = ctx) do
schema.meta.transforms
|> Enum.reduce({{:ok, input}, []}, fn
{mod, func, args}, {{:ok, input}, errors} ->
case apply(mod, func, [input] ++ args ++ [[ctx: ctx]]) do
{:ok, value} ->
{{:ok, value}, errors}
{:error, err} ->
{{:ok, input}, Zoi.Errors.add_error(errors, err)}
%Zoi.Context{} = context ->
{{:ok, context.parsed}, context.errors}
value ->
{{:ok, value}, errors}
end
refine_func, {{:ok, input}, errors} ->
cond do
is_function(refine_func, 1) ->
refine_func.(input)
is_function(refine_func, 2) ->
refine_func.(input, ctx)
end
|> case do
{:ok, value} ->
{{:ok, value}, errors}
{:error, err} ->
{{:ok, input}, Zoi.Errors.add_error(errors, err)}
%Zoi.Context{} = context ->
{{:ok, context.parsed}, context.errors}
value ->
{{:ok, value}, errors}
end
end)
|> then(fn {{:ok, value}, errors} ->
if Enum.empty?(errors) do
{:ok, value}
else
{:error, errors}
end
end)
end
@spec required?(t()) :: boolean()
def required?(%__MODULE__{required: required}) do
case required do
nil -> false
val -> val
end
end
end