version: 1.0.0

+ map_validate/2: a simple way to validate maps
+ gitversion.mk removed
This commit is contained in:
Umgeher Torgersen 2024-10-13 19:36:09 +00:00
parent 7b5b494cbb
commit b5e2fecca5
4 changed files with 82 additions and 8 deletions

12
.gitignore vendored
View file

@ -1,4 +1,10 @@
ebin/*
deps
ebin
_rel
.erlang.mk/
utools.d
deps
config
*.d
*.plt
*.beam
*.pem
*.dump

View file

@ -1,12 +1,8 @@
PROJECT = utools
PROJECT_DESCRIPTION = Umgeher Erlang Tools
PROJECT_VERSION = 0.2.0
PROJECT_VERSION = 1.0.0
# Whitespace to be used when creating files from templates.
SP = 2
BUILD_DEPS = gitversion.mk
DEP_PLUGINS = gitversion.mk
dep_gitversion.mk = git https://git.sr.ht/~umgeher/gitversion.mk master
include erlang.mk

View file

@ -4,6 +4,7 @@
-export([b32_encode/1]).
-export([hex_encode/1]).
-export([hotp/2]).
-export([map_validate/2]).
-export([rand_bytes/0, rand_bytes/1]).
-export([rand_chars/1]).
-export([rand_hash/0]).
@ -85,6 +86,45 @@ hotp(Token, Time) ->
P = << <<48:8>> || _ <- lists:seq(1, 6 - byte_size(T)) >>,
{ok, <<P/binary, T/binary>>}.
map_validate({_, _, {error, _} = Error}) ->
Error;
map_validate({Map, #{with := W} = Doc, R}) when is_list(W) ->
map_validate({maps:with(W, Map), maps:remove(with, Doc), R});
map_validate({Map, #{rules := []} = Doc, R}) ->
map_validate({Map, maps:remove(rules, Doc), R});
map_validate({Map, #{rules := [#{key := K, required := true} = Rule | T]} = Doc, R}) ->
map_validate({Map, Doc#{rules => T}, map_validate_rule(maps:get(K, Map, required), maps:remove(required, Rule), R)});
map_validate({Map, #{rules := [#{key := K, default := nil} = Rule | T]} = Doc, R}) ->
map_validate({Map, Doc#{rules => T}, map_validate_rule(maps:get(K, Map, nil), maps:remove(required, Rule), R)});
map_validate({Map, #{rules := [#{key := K, default := V} = Rule | T]} = Doc, R}) ->
map_validate({Map, Doc#{rules => T}, map_validate_rule(maps:get(K, Map, V), maps:remove(required, Rule), R)});
map_validate({Map, #{rules := [_ | T]} = Doc, R}) ->
map_validate({Map, Doc#{rules => T}, R});
map_validate({Map, #{merge := true} = Doc, R}) ->
map_validate({nil, maps:remove(merge, Doc), maps:merge(Map, R)});
map_validate({_, #{without := W}, R}) when is_list(W) ->
map_validate({nil, #{}, maps:without(W, R)});
map_validate({_, #{}, R}) ->
R.
map_validate(#{} = Map, #{} = Doc) ->
map_validate({Map, Doc, #{}});
map_validate(_, _) ->
{error, 'no data'}.
map_validate_rule(required, #{key := K}, _) ->
{error, K};
map_validate_rule(nil, _, M) ->
M;
map_validate_rule(V, #{prefn := FN} = Rule, M) when is_function(FN) ->
map_validate_rule(FN(V), maps:remove(prefn, Rule), M);
map_validate_rule(V, #{posfn := FN} = Rule, M) when is_function(FN) ->
map_validate_rule(FN(V), maps:remove(posfn, Rule), M);
map_validate_rule(V, #{key := K}, M) ->
M#{K => V};
map_validate_rule(_, _, _) ->
{error, invalid}.
rand_bytes() ->
rand_bytes(8).

32
test/map_validate.erl Normal file
View file

@ -0,0 +1,32 @@
-module(map_validate).
-include_lib("eunit/include/eunit.hrl").
-define(SAMPLE, #{<<"name">> => <<"umgeher">>, email => <<"me@umgeher.org">>}).
returning_no_data_test() ->
?assertEqual({error, 'no data'}, utools:map_validate('not a map', #{})),
?assertEqual({error, 'no data'}, utools:map_validate(#{}, 'not a map')),
?assertEqual({error, 'no data'}, utools:map_validate('not a map', 'not a map')).
ok_without_doc_test() ->
?assertEqual(#{}, utools:map_validate(?SAMPLE, #{})).
ok_rule_required_test() ->
Rule = #{
key => <<"name">>,
required => true
},
?assertEqual(#{<<"name">> => <<"umgeher">>}, utools:map_validate(?SAMPLE, #{rules => [Rule]})).
error_required_missing_test() ->
Rule = #{key => some, required => true},
?assertEqual({error, some}, utools:map_validate(?SAMPLE, #{rules => [Rule]})).
ok_rule_not_required_with_default_value_test() ->
Rule = #{key => some, default => 123},
?assertEqual(#{some => 123}, utools:map_validate(?SAMPLE, #{rules => [Rule]})).
ok_merge_test() ->
Rule = #{key => some, default => 123},
?assertEqual(maps:merge(?SAMPLE, #{some => 123}), utools:map_validate(?SAMPLE, #{merge => true, rules => [Rule]})).