Packages
zoi
0.17.1
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/decimal.ex
if Code.ensure_loaded?(Decimal) do
defmodule Zoi.Types.Decimal do
@moduledoc false
use Zoi.Type.Def, fields: [:gte, :lte, :gt, :lt, :multiple_of, coerce: false]
alias Zoi.Validations
def opts() do
error = "invalid type: expected decimal"
Zoi.Opts.meta_opts()
|> Zoi.Opts.with_coerce()
|> Zoi.Types.Extend.new(
gte:
Zoi.Opts.constraint_schema(Zoi.Types.Decimal.new([]),
description: "decimal greater than or equal to",
error: error
),
lte:
Zoi.Opts.constraint_schema(Zoi.Types.Decimal.new([]),
description: "decimal less than or equal to",
error: error
),
gt:
Zoi.Opts.constraint_schema(Zoi.Types.Decimal.new([]),
description: "decimal greater than",
error: error
),
lt:
Zoi.Opts.constraint_schema(Zoi.Types.Decimal.new([]),
description: "decimal less than",
error: error
),
multiple_of:
Zoi.Opts.constraint_schema(Zoi.Types.Decimal.new([]),
description: "decimal must be multiple of",
error: error
)
)
end
def new(opts \\ []) do
{validation_opts, opts} = Keyword.split(opts, [:gte, :lte, :gt, :lt, :multiple_of])
opts
|> apply_type()
|> Validations.maybe_set_validation(Validations.Gte, validation_opts[:gte])
|> Validations.maybe_set_validation(Validations.Lte, validation_opts[:lte])
|> Validations.maybe_set_validation(Validations.Gt, validation_opts[:gt])
|> Validations.maybe_set_validation(Validations.Lt, validation_opts[:lt])
|> Validations.maybe_set_validation(Validations.MultipleOf, validation_opts[:multiple_of])
end
defimpl Zoi.Type do
import Decimal, only: [is_decimal: 1]
def parse(schema, input, opts) do
coerce = Keyword.get(opts, :coerce, schema.coerce)
with {:ok, parsed} <- parse_type(schema, input, coerce),
:ok <- validate_constraints(schema, parsed) do
{:ok, parsed}
end
end
defp parse_type(_schema, input, _coerce) when is_decimal(input), do: {:ok, input}
defp parse_type(schema, input, true) do
case Decimal.cast(input) do
{:ok, decimal} -> {:ok, decimal}
:error -> error(schema)
end
end
defp parse_type(schema, _input, _coerce), do: error(schema)
defp validate_constraints(schema, input) do
[
{Validations.Gte, schema.gte},
{Validations.Lte, schema.lte},
{Validations.Gt, schema.gt},
{Validations.Lt, schema.lt},
{Validations.MultipleOf, schema.multiple_of}
]
|> Validations.run_validations(schema, input)
end
defp error(schema) do
{:error, Zoi.Error.invalid_type(:decimal, error: schema.meta.error)}
end
end
defimpl Zoi.TypeSpec do
def spec(_schema, _opts) do
quote(do: Decimal.t())
end
end
defimpl Zoi.Validations.Gte do
def set(schema, value, opts \\ []) do
%{schema | gte: {value, opts}}
end
def validate(_schema, input, value, opts) do
if Decimal.gte?(input, value) do
:ok
else
{:error, Zoi.Error.greater_than_or_equal_to(:number, value, opts)}
end
end
end
defimpl Zoi.Validations.Lte do
def set(schema, value, opts \\ []) do
%{schema | lte: {value, opts}}
end
def validate(_schema, input, value, opts) do
if Decimal.lte?(input, value) do
:ok
else
{:error, Zoi.Error.less_than_or_equal_to(:number, value, opts)}
end
end
end
defimpl Zoi.Validations.Gt do
def set(schema, value, opts \\ []) do
%{schema | gt: {value, opts}}
end
def validate(_schema, input, value, opts) do
if Decimal.gt?(input, value) do
:ok
else
{:error, Zoi.Error.greater_than(:number, value, opts)}
end
end
end
defimpl Zoi.Validations.Lt do
def set(schema, value, opts \\ []) do
%{schema | lt: {value, opts}}
end
def validate(_schema, input, value, opts) do
if Decimal.lt?(input, value) do
:ok
else
{:error, Zoi.Error.less_than(:number, value, opts)}
end
end
end
defimpl Zoi.Validations.MultipleOf do
def set(schema, value, opts \\ []) do
%{schema | multiple_of: {value, opts}}
end
def validate(_schema, input, value, opts) do
remainder = Decimal.rem(input, value)
if Decimal.eq?(remainder, Decimal.new(0)) do
:ok
else
{:error, Zoi.Error.multiple_of(value, opts)}
end
end
end
defimpl Inspect do
alias Zoi.Validations
def inspect(type, opts) do
extra_fields = [
gte: Validations.unwrap_validation(type.gte),
lte: Validations.unwrap_validation(type.lte),
gt: Validations.unwrap_validation(type.gt),
lt: Validations.unwrap_validation(type.lt),
multiple_of: Validations.unwrap_validation(type.multiple_of)
]
Zoi.Inspect.build(type, opts, extra_fields)
end
end
defimpl Zoi.JSONSchema.Encoder do
def encode(schema) do
%{type: :number}
|> maybe_add(:minimum, schema.gte)
|> maybe_add(:maximum, schema.lte)
|> maybe_add(:exclusiveMinimum, schema.gt)
|> maybe_add(:exclusiveMaximum, schema.lt)
|> maybe_add(:multipleOf, schema.multiple_of)
end
defp maybe_add(map, _key, nil), do: map
defp maybe_add(map, key, {value, _opts}), do: Map.put(map, key, value)
end
defimpl Zoi.Describe.Encoder do
def encode(_schema), do: "`t:Decimal.t/0`"
end
end
end