Packages
zoi
0.7.2
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/refinements.ex
defmodule Zoi.Refinements do
@moduledoc false
def refine(input, args, opts, ctx: ctx) do
do_refine(ctx.schema, input, args, opts)
end
# String
defp do_refine(%Zoi.Types.String{}, input, [gte: min], opts) do
if String.length(input) >= min do
:ok
else
{:error, message(opts, "too small: must have at least #{min} characters")}
end
end
defp do_refine(%Zoi.Types.String{}, input, [gt: gt], opts) do
if String.length(input) > gt do
:ok
else
{:error, message(opts, "too small: must have more than #{gt} characters")}
end
end
defp do_refine(%Zoi.Types.String{}, input, [lte: max], opts) do
if String.length(input) <= max do
:ok
else
{:error, message(opts, "too big: must have at most #{max} characters")}
end
end
defp do_refine(%Zoi.Types.String{}, input, [lt: lt], opts) do
if String.length(input) < lt do
:ok
else
{:error, message(opts, "too big: must have less than #{lt} characters")}
end
end
defp do_refine(%Zoi.Types.String{}, input, [length: length], opts) do
if String.length(input) == length do
:ok
else
{:error, message(opts, "invalid length: must have #{length} characters")}
end
end
defp do_refine(%Zoi.Types.String{}, input, [regex: regex], opts) do
# To allow both string and regex input for regex refinement
regex = Regex.compile!(regex)
if String.match?(input, regex) do
:ok
else
{:error, message(opts, "invalid string: must match a pattern #{inspect(regex)}")}
end
end
defp do_refine(%Zoi.Types.String{}, input, [starts_with: prefix], opts) do
if String.starts_with?(input, prefix) do
:ok
else
{:error, message(opts, "invalid string: must start with '#{prefix}'")}
end
end
defp do_refine(%Zoi.Types.String{}, input, [ends_with: suffix], opts) do
if String.ends_with?(input, suffix) do
:ok
else
{:error, message(opts, "invalid string: must end with '#{suffix}'")}
end
end
# Array
defp do_refine(%Zoi.Types.Array{}, input, [gte: min], opts) do
if length(input) >= min do
:ok
else
{:error, message(opts, "too small: must have at least #{min} items")}
end
end
defp do_refine(%Zoi.Types.Array{}, input, [gt: gt], opts) do
if length(input) > gt do
:ok
else
{:error, message(opts, "too small: must have more than #{gt} items")}
end
end
defp do_refine(%Zoi.Types.Array{}, input, [lt: lt], opts) do
if length(input) < lt do
:ok
else
{:error, message(opts, "too big: must have less than #{lt} items")}
end
end
defp do_refine(%Zoi.Types.Array{}, input, [lte: max], opts) do
if length(input) <= max do
:ok
else
{:error, message(opts, "too big: must have at most #{max} items")}
end
end
defp do_refine(%Zoi.Types.Array{}, input, [length: length], opts) do
if length(input) == length do
:ok
else
{:error, message(opts, "invalid length: must have #{length} items")}
end
end
# Numeric
for numeric_module <- [Integer, Float, Number] do
@module Module.concat(Zoi.Types, numeric_module)
defp do_refine(%@module{}, input, [gte: min], opts) do
if input >= min do
:ok
else
{:error, message(opts, "too small: must be at least #{min}")}
end
end
defp do_refine(%@module{}, input, [gt: gt], opts) do
if input > gt do
:ok
else
{:error, message(opts, "too small: must be greater than #{gt}")}
end
end
defp do_refine(%@module{}, input, [lte: max], opts) do
if input <= max do
:ok
else
{:error, message(opts, "too big: must be at most #{max}")}
end
end
defp do_refine(%@module{}, input, [lt: lt], opts) do
if input < lt do
:ok
else
{:error, message(opts, "too big: must be less than #{lt}")}
end
end
end
# Dates
for date_module <- [Date, NaiveDateTime, Time, DateTime] do
@module Module.concat(Zoi.Types, date_module)
@date_module date_module
defp do_refine(%@module{}, input, [gte: min], opts) do
case @date_module.compare(input, min) do
:gt -> :ok
:eq -> :ok
:lt -> {:error, message(opts, "too small: must be at least #{min}")}
end
end
defp do_refine(%@module{}, input, [gt: gt], opts) do
case @date_module.compare(input, gt) do
:gt -> :ok
_ -> {:error, message(opts, "too small: must be greater than #{gt}")}
end
end
defp do_refine(%@module{}, input, [lte: max], opts) do
case @date_module.compare(input, max) do
:lt -> :ok
:eq -> :ok
:gt -> {:error, message(opts, "too big: must be at most #{max}")}
end
end
defp do_refine(%@module{}, input, [lt: lt], opts) do
case @date_module.compare(input, lt) do
:lt -> :ok
_ -> {:error, message(opts, "too big: must be less than #{lt}")}
end
end
end
# Decimal
if Code.ensure_loaded?(Decimal) do
defp do_refine(%Zoi.Types.Decimal{}, input, [gte: min], opts) do
if Decimal.gte?(input, min) do
:ok
else
{:error, message(opts, "too small: must be at least #{min}")}
end
end
defp do_refine(%Zoi.Types.Decimal{}, input, [gt: gt], opts) do
if Decimal.gt?(input, gt) do
:ok
else
{:error, message(opts, "too small: must be greater than #{gt}")}
end
end
defp do_refine(%Zoi.Types.Decimal{}, input, [lt: lt], opts) do
if Decimal.lt?(input, lt) do
:ok
else
{:error, message(opts, "too big: must be less than #{lt}")}
end
end
defp do_refine(%Zoi.Types.Decimal{}, input, [lte: max], opts) do
if Decimal.lte?(input, max) do
:ok
else
{:error, message(opts, "too big: must be at most #{max}")}
end
end
end
defp do_refine(_schema, _input, _args, _opts) do
# Default to :ok if there is no type pattern match
:ok
end
defp message(opts, default_message) do
Keyword.get(opts, :message, default_message)
end
end