Skip to content

Commit

Permalink
Add support for datetime built in type
Browse files Browse the repository at this point in the history
  • Loading branch information
bluzky committed Feb 26, 2024
1 parent e513510 commit 1fad002
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 11 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ iex(56)> Valdi.validate_map(%{name: "dzung", password: "123456", emal: "ddd@exam
- `:atom`
- `:function`
- `:map`
- `:date`
- `:time`
- `:datetime`
- `:naive_datetime`
- `:utc_datetime`
- `{:array, type}` array of item similar to Ecto.Schema
- `:keyword`
- `struct` for example: `User`. it's the struct module name
Expand Down
45 changes: 36 additions & 9 deletions lib/valdi.ex
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ defmodule Valdi do
"""
require Decimal

@supported_validations [
:type,
:required,
:format,
:number,
:length,
:in,
:not_in,
:func,
:each,
:decimal
]
@type error :: {:error, String.t()}

@doc """
Expand All @@ -53,7 +65,8 @@ defmodule Valdi do
"""
@spec validate(any(), keyword()) :: :ok | error
def validate(value, validators) do
validators = sort_validator(validators)
validators = prepare_validator(validators)

do_validate(value, validators, :ok)
end

Expand All @@ -69,7 +82,7 @@ defmodule Valdi do

@spec validate_list(list(), keyword()) :: :ok | {:error, list()}
def validate_list(items, validators) do
validators = sort_validator(validators)
validators = prepare_validator(validators)

items
|> Enum.with_index()
Expand Down Expand Up @@ -107,7 +120,7 @@ defmodule Valdi do
def validate_map(data, validations_spec) do
validations_spec
|> Enum.reduce({:ok, []}, fn {key, validators}, {status, acc} ->
validators = sort_validator(validators)
validators = prepare_validator(validators)

case do_validate(Map.get(data, key), validators, :ok) do
:ok -> {status, acc}
Expand All @@ -121,8 +134,12 @@ defmodule Valdi do
end

# prioritize checking
# remove unknown validator
# `required` -> `type` -> others
defp sort_validator(validators) do
defp prepare_validator(validators) do
validators =
Enum.filter(validators, fn {key, _} -> Enum.member?(@supported_validations, key) end)

{required, validators} = Keyword.pop(validators, :required, false)
{type, validators} = Keyword.pop(validators, :type, :any)
validators = [{:type, type} | validators]
Expand Down Expand Up @@ -204,6 +221,10 @@ defmodule Valdi do
- `atom`
- `function`
- `keyword`
- `date`
- `datetime`
- `naive_datetime`
- `time`
It can also check extend types
- `struct` Ex: `User`
Expand All @@ -223,6 +244,11 @@ defmodule Valdi do
def validate_type(value, :function) when is_function(value), do: :ok
def validate_type(value, :map) when is_map(value), do: :ok
def validate_type(%Decimal{} = _value, :decimal), do: :ok
def validate_type(value, :date), do: validate_type(value, Date)
def validate_type(value, :time), do: validate_type(value, Time)
def validate_type(value, :datetime), do: validate_type(value, DateTime)
def validate_type(value, :utc_datetime), do: validate_type(value, DateTime)
def validate_type(value, :naive_datetime), do: validate_type(value, NaiveDateTime)
def validate_type(_value, :any), do: :ok

def validate_type(value, {:array, type}) when is_list(value) do
Expand All @@ -232,6 +258,8 @@ defmodule Valdi do
end
end

def validate_type(value, %{} = map), do: validate_map(value, map)

def validate_type([] = _check_item, :keyword), do: :ok
def validate_type([{atom, _} | _] = _check_item, :keyword) when is_atom(atom), do: :ok
# def validate_type(value, struct_name) when is_struct(value, struct_name), do: :ok
Expand Down Expand Up @@ -486,17 +514,17 @@ defmodule Valdi do
def validate_decimal(value, checks) when is_list(checks) do
if Decimal.is_decimal(value) do
Enum.reduce(checks, :ok, fn
check, :ok ->
check, :ok ->
validate_decimal(value, check)
_, error ->
error

_, error ->
error
end)
else
{:error, "must be a Decimal.t() type"}
end
end


def validate_decimal(decimal, {:equal_to, %Decimal{} = check_value}) do
if Decimal.eq?(decimal, check_value) do
:ok
Expand Down Expand Up @@ -552,5 +580,4 @@ defmodule Valdi do
def validate_decimal(_decimal, {_check, check_value}) do
{:error, "#{check_value} must be a Decimal.t() type"}
end

end
12 changes: 10 additions & 2 deletions test/valdi_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,15 @@ defmodule ValdiTest do
[{:array, User}, %{}, :error],
[:decimal, Decimal.new("1.0"), :ok],
[:decimal, "1.0", :error],
[:decimal, 1.0, :error]
[:decimal, 1.0, :error],
[:date, ~D[2023-10-11], :ok],
[:date, "1.0", :error],
[:datetime, ~U[2023-10-11 09:00:00Z], :ok],
[:datetime, "1.0", :error],
[:naive_datetime, ~N[2023-10-11 09:10:00], :ok],
[:naive_datetime, "1.0", :error],
[:time, ~T[09:10:00], :ok],
[:time, "1.0", :error]
]

test "validate type" do
Expand Down Expand Up @@ -278,7 +286,7 @@ defmodule ValdiTest do
[:max, Decimal.new("10.0"), Decimal.new("10.0"), :ok],
[:max, Decimal.new("10.0"), Decimal.new("11.0"), :error],
[:unknown_check, Decimal.new("10.0"), Decimal.new("11.0"), :error],
[:min, 11, Decimal.new("11.0"), :error],
[:min, 11, Decimal.new("11.0"), :error]
]
test "validate decimal" do
for [condition, value, actual_value, expect] <- @decimal_tests do
Expand Down

0 comments on commit 1fad002

Please sign in to comment.