Skip to content

Commit

Permalink
feat: add MFA support for transform, default and dependent directives
Browse files Browse the repository at this point in the history
  • Loading branch information
zoedsoupe committed Sep 17, 2024
1 parent b212bc1 commit 8928e59
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 1 deletion.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

All notable changes to this project will be documented in this file.

## [0.2.11] - 204-09-16

## Added

- ability to pass partial MFA (aka `{mod, fun}`) or complete MFA (aka `{mof, fun, args}`) to `:transform`, `:dependent` and `:default` directives

## [0.2.10] - 2024-09-16

### Added
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,18 @@ end
- `{:list, type}` - Validates that the field is a list of elements of the specified type.
- `{:tuple, types}` - Validates that the field is a tuple with elements of the specified types.
- `{type, {:default, default}}` - Provides a default value if the field is missing or `nil`.
- `{type, {:default, &some_fun/0}}` - The default values is retrieved from callinf `some_fun/0` if the field is missing.
- `{type, {:default, {mod, fun}}}` - The default values is retrieved from callinf `mod.fun/0` if the field is missing.
- `{type, {:transform, mapper}}` - Transforms the field value using the specified mapper function.
- `{type, {:transform, {mod, fun}}}` - Transforms the field value using the specified `mod.fun/1` function.
- `{:either, {type1, type2}}` - Validates that the field is either of the two specified types.
- `{:oneof, types}` - Validates that the field is one of the specified types.
- `{:custom, callback}` - Validates that the field passes the custom validation function.
- `{:custom, {mod, fun}}` - Validates that the field passes the custom validation function.
- `{:custom, {mod, fun, args}}` - Validates that the field passes the custom validation function.
- `{:dependent, field, condition, type}` - Validates the field based on the value of another field. Check the [dependent schema examples](#dependent-schemas) section for more info.
- `{:dependent, condition}` - Validates the field based on the value of multiple data values. Check the [dependent schema examples](#dependent-schemas) section for more info.
- `{:dependent, {mod, fun}}` - Validates the field based on the value of multiple data values but executes `mod.fun/1` in runtime.
- `{:cond, condition, type, else_type}` - Conditional validation based on a condition function. Check the [conditional schema examples](#conditional-schemas) section for more info.

## Defining Schemas
Expand Down
44 changes: 44 additions & 0 deletions lib/peri.ex
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,16 @@ defmodule Peri do
end
end

defp validate_field(val, {type, {:default, {mod, fun}}}, data)
when is_atom(mod) and is_atom(fun) do
validate_field(val, {type, {:default, apply(mod, fun, [])}}, data)
end

defp validate_field(val, {type, {:default, {mod, fun, args}}}, data)
when is_atom(mod) and is_atom(fun) and is_list(args) do
validate_field(val, {type, {:default, apply(mod, fun, args)}}, data)
end

defp validate_field(val, {type, {:default, default}}, data)
when is_function(default, 0) do
validate_field(val, {type, {:default, default.()}}, data)
Expand Down Expand Up @@ -614,6 +624,26 @@ defmodule Peri do
end
end

defp validate_field(val, {:dependent, {mod, fun}}, parser)
when is_atom(mod) and is_atom(fun) do
root = maybe_get_root_data(parser)

with {:ok, type} <- apply(mod, fun, [root]),
{:ok, schema} <- validate_schema(type) do
validate_field(val, schema, parser)
end
end

defp validate_field(val, {:dependent, {mod, fun, args}}, parser)
when is_atom(mod) and is_atom(fun) and is_list(args) do
root = maybe_get_root_data(parser)

with {:ok, type} <- apply(mod, fun, [root | args]),
{:ok, schema} <- validate_schema(type) do
validate_field(val, schema, parser)
end
end

defp validate_field(val, {:dependent, field, condition, type}, data) do
dependent_val = get_enumerable_value(data, field)

Expand All @@ -635,6 +665,20 @@ defmodule Peri do
end
end

defp validate_field(val, {type, {:transform, {mod, fun}}}, data)
when is_atom(mod) and is_atom(fun) do
with :ok <- validate_field(val, type, data) do
{:ok, apply(mod, fun, [val])}
end
end

defp validate_field(val, {type, {:transform, {mod, fun, args}}}, data)
when is_atom(mod) and is_atom(fun) and is_list(args) do
with :ok <- validate_field(val, type, data) do
{:ok, apply(mod, fun, [val | args])}
end
end

defp validate_field(val, {:custom, callback}, _data) when is_function(callback, 1) do
callback.(val)
end
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Peri.MixProject do
use Mix.Project

@version "0.2.10"
@version "0.2.11"
@source_url "https://github.com/zoedsoupe/peri"

def project do
Expand Down

0 comments on commit 8928e59

Please sign in to comment.