Packages

Erlang input validation and normalization utilities

Current section

Files

Jump to
validerl src normalizerl.erl
Raw

src/normalizerl.erl

-module(normalizerl).
-author('hernanrivasacosta@gmail.com').
-export([normalize_proplist/2]).
-include("normalizerl.hrl").
%%==============================================================================
%% API
%%==============================================================================
-spec normalize_proplist(proplist_schema(), [{any(), any()}]) ->
{ok, [{any(), any()}]} | {errors, {atom(), any()}}.
normalize_proplist(Schema, Proplist) ->
GetValue = fun(ItemSchema) -> get_proplist_value(ItemSchema, Proplist) end,
IsError = fun({error, _}) -> true;
(_Other) -> false end,
case lists:partition(IsError, lists:map(GetValue, Schema)) of
{[], Values} -> {ok, Values};
{Errors, _} -> {errors, [Reason || {error, Reason} <- Errors]}
end.
%%==============================================================================
%% Utils
%%==============================================================================
get_proplist_value({Key, Type, Required}, Proplist) ->
get_proplist_value({Key, Type, Required, undefined}, Proplist);
get_proplist_value({Key, Type, Required, Constraints}, Proplist) ->
case {get_value_from_proplist(Key, Proplist), Required} of
{undefined, required} ->
{error, {missing_property, Key}};
{undefined, optional} ->
undefined;
{undefined, {default, Value}} ->
Value;
{{ok, {Key, Value}}, _} ->
case {validerl:get_value(Value, Type), Constraints} of
{{ok, Validated}, undefined} ->
Validated;
{{ok, Validated}, Constraints} ->
case value_satisfies(Validated, Constraints) of
true -> Validated;
false -> {error, {value_mismatch, Value}}
end;
Error ->
Error
end;
{Any, Required} ->
error_logger:info_msg("received ~p for ~p on ~p", [Any, Key, Proplist]),
{error, unknown}
end.
get_value_from_proplist(Key, Proplist) ->
GetValue = fun(K) -> lists:keyfind(K, 1, Proplist) end,
case {GetValue(Key), is_list(Key)} of
{false, true} ->
first_satisfying(GetValue, Key);
{false, false} ->
undefined;
{Tuple, _} ->
{ok, Tuple}
end.
value_satisfies(Value, {matches, Value}) ->
true;
value_satisfies(Value, {matches, Constraints}) ->
value_satisfies(Value, Constraints);
value_satisfies(Value, [Value | _T]) ->
true;
value_satisfies(Value, [_H | T]) ->
value_satisfies(Value, T);
value_satisfies(_Value, _Any) ->
false.
first_satisfying(_F, []) ->
undefined;
first_satisfying(F, [H | T]) ->
case F(H) of
false -> first_satisfying(F, T);
Tuple -> {ok, Tuple}
end.