Packages
zoi
0.10.0
0.18.7
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(ctx :: Zoi.Context.t()) :: {:ok, Zoi.input()} | {:error, [Zoi.Errors.t()]}
def run_refinements(%Zoi.Context{schema: schema, 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(ctx :: Zoi.Context.t()) :: {:ok, Zoi.input()} | {:error, [Zoi.Errors.t()]}
def run_transforms(%Zoi.Context{schema: schema, 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
transform_func, {{:ok, input}, errors} ->
cond do
is_function(transform_func, 1) ->
transform_func.(input)
is_function(transform_func, 2) ->
transform_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
@spec optional?(t()) :: boolean()
def optional?(%__MODULE__{} = meta) do
not required?(meta)
end
end