Packages
zoi
0.10.1
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, [:url], opts) do
uri = URI.parse(input)
if uri.scheme in ["http", "https"] and uri.host != nil do
:ok
else
{:error, Zoi.Error.invalid_url(input, opts)}
end
end
defp do_refine(%Zoi.Types.String{}, input, [gte: min], opts) do
if String.length(input) >= min do
:ok
else
{:error, Zoi.Error.greater_than_or_equal_to(:string, min, opts)}
end
end
defp do_refine(%Zoi.Types.String{}, input, [lte: max], opts) do
if String.length(input) <= max do
:ok
else
{:error, Zoi.Error.less_than_or_equal_to(:string, max, opts)}
end
end
defp do_refine(%Zoi.Types.String{}, input, [length: length], opts) do
if String.length(input) == length do
:ok
else
{:error, Zoi.Error.invalid_length(:string, length, opts)}
end
end
defp do_refine(%Zoi.Types.String{}, input, [regex: regex, opts: regex_opts], opts) do
# To allow both string and regex input for regex refinement
regex = Regex.compile!(regex, regex_opts)
if String.match?(input, regex) do
:ok
else
{:error, Zoi.Error.invalid_format(regex, opts)}
end
end
defp do_refine(%Zoi.Types.String{}, input, [starts_with: prefix], opts) do
if String.starts_with?(input, prefix) do
:ok
else
{:error, Zoi.Error.invalid_starting_string(prefix, opts)}
end
end
defp do_refine(%Zoi.Types.String{}, input, [ends_with: suffix], opts) do
if String.ends_with?(input, suffix) do
:ok
else
{:error, Zoi.Error.invalid_ending_string(suffix, opts)}
end
end
# Array
defp do_refine(%Zoi.Types.Array{}, input, [gte: min], opts) do
if length(input) >= min do
:ok
else
{:error, Zoi.Error.greater_than_or_equal_to(:array, min, opts)}
end
end
defp do_refine(%Zoi.Types.Array{}, input, [gt: gt], opts) do
if length(input) > gt do
:ok
else
{:error, Zoi.Error.greater_than(:array, gt, opts)}
end
end
defp do_refine(%Zoi.Types.Array{}, input, [lt: lt], opts) do
if length(input) < lt do
:ok
else
{:error, Zoi.Error.less_than(:array, lt, opts)}
end
end
defp do_refine(%Zoi.Types.Array{}, input, [lte: max], opts) do
if length(input) <= max do
:ok
else
{:error, Zoi.Error.less_than_or_equal_to(:array, max, opts)}
end
end
defp do_refine(%Zoi.Types.Array{}, input, [length: length], opts) do
if length(input) == length do
:ok
else
{:error, Zoi.Error.invalid_length(:array, length, opts)}
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, Zoi.Error.greater_than_or_equal_to(:number, min, opts)}
end
end
defp do_refine(%@module{}, input, [gt: gt], opts) do
if input > gt do
:ok
else
{:error, Zoi.Error.greater_than(:number, gt, opts)}
end
end
defp do_refine(%@module{}, input, [lte: max], opts) do
if input <= max do
:ok
else
{:error, Zoi.Error.less_than_or_equal_to(:number, max, opts)}
end
end
defp do_refine(%@module{}, input, [lt: lt], opts) do
if input < lt do
:ok
else
{:error, Zoi.Error.less_than(:number, lt, opts)}
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, Zoi.Error.greater_than_or_equal_to(:date, min, opts)}
end
end
defp do_refine(%@module{}, input, [gt: gt], opts) do
case @date_module.compare(input, gt) do
:gt -> :ok
_ -> {:error, Zoi.Error.greater_than(:date, gt, opts)}
end
end
defp do_refine(%@module{}, input, [lte: max], opts) do
case @date_module.compare(input, max) do
:lt -> :ok
:eq -> :ok
:gt -> {:error, Zoi.Error.less_than_or_equal_to(:date, max, opts)}
end
end
defp do_refine(%@module{}, input, [lt: lt], opts) do
case @date_module.compare(input, lt) do
:lt -> :ok
_ -> {:error, Zoi.Error.less_than(:date, lt, opts)}
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, Zoi.Error.greater_than_or_equal_to(:number, min, opts)}
end
end
defp do_refine(%Zoi.Types.Decimal{}, input, [gt: gt], opts) do
if Decimal.gt?(input, gt) do
:ok
else
{:error, Zoi.Error.greater_than(:number, gt, opts)}
end
end
defp do_refine(%Zoi.Types.Decimal{}, input, [lt: lt], opts) do
if Decimal.lt?(input, lt) do
:ok
else
{:error, Zoi.Error.less_than(:number, lt, opts)}
end
end
defp do_refine(%Zoi.Types.Decimal{}, input, [lte: max], opts) do
if Decimal.lte?(input, max) do
:ok
else
{:error, Zoi.Error.less_than_or_equal_to(:number, max, opts)}
end
end
end
defp do_refine(_schema, _input, _args, _opts) do
# Default to :ok if there is no type pattern match
:ok
end
end