Skip to content

Commit

Permalink
Merge pull request #200 from emqx/support-early-return-with-throw
Browse files Browse the repository at this point in the history
feat: allow early return when throw in validations/translations
  • Loading branch information
zhongwencool authored Jun 1, 2022
2 parents 229abbb + 0b80063 commit e50e632
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 15 deletions.
2 changes: 1 addition & 1 deletion SCHEMA.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ min_max(Conf) ->
Max = hocon_maps:get("foo.max", Conf),
case Min =< Max of
true -> ok %% return true | ok to pass this validation
false -> "min > max is not allowed"
false -> "min > max is not allowed" %% or If you need to return early, use throw(Reason)
end.
```

Expand Down
41 changes: 28 additions & 13 deletions src/hocon_tconf.erl
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,14 @@ do_translate([{MappedField, Translator} | More], TrNamespace, Conf, Acc) ->
Value ->
do_translate(More, TrNamespace, Conf, [{string:tokens(MappedField0, "."), Value} | Acc])
catch
throw:Reason ->
Error =
{error,
?TRANSLATION_ERRS(#{
reason => Reason,
path => MappedField0
})},
do_translate(More, TrNamespace, Conf, [Error | Acc]);
Exception:Reason:St ->
Error =
{error,
Expand Down Expand Up @@ -173,20 +181,10 @@ assert_integrity(Schema, [{Name, Validator} | Rest], Conf, Acc) ->
OK when OK =:= true orelse OK =:= ok ->
assert_integrity(Schema, Rest, Conf, Acc);
Other ->
assert_integrity(
Schema,
Rest,
Conf,
[
{error,
?VALIDATION_ERRS(#{
reason => integrity_validation_failure,
validation_name => Name,
result => Other
})}
]
)
assert_integrity_failure(Schema, Rest, Conf, Name, Other)
catch
throw:Reason ->
assert_integrity_failure(Schema, Rest, Conf, Name, Reason);
Exception:Reason:St ->
Error =
{error,
Expand All @@ -199,6 +197,21 @@ assert_integrity(Schema, [{Name, Validator} | Rest], Conf, Acc) ->
assert_integrity(Schema, Rest, Conf, [Error | Acc])
end.

assert_integrity_failure(Schema, Rest, Conf, Name, Reason) ->
assert_integrity(
Schema,
Rest,
Conf,
[
{error,
?VALIDATION_ERRS(#{
reason => integrity_validation_failure,
validation_name => Name,
result => Reason
})}
]
).

merge_opts(Default, Opts) ->
maps:merge(
Default#{
Expand Down Expand Up @@ -1039,6 +1052,8 @@ do_validate(Opts, Schema, Value, [H | T]) ->
{error, Reason} ->
validation_errs(Opts, Reason, obfuscate(Schema, Value))
catch
throw:Reason ->
validation_errs(Opts, Reason, obfuscate(Schema, Value));
C:E:St ->
validation_errs(
Opts,
Expand Down
34 changes: 33 additions & 1 deletion test/hocon_tconf_tests.erl
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,22 @@ translation_crash_test() ->
{ok, Data} = hocon:binary("f1=12,f2=foo", #{format => richmap}),
{Mapped, Conf} = hocon_tconf:map(Sc, Data),
?assertThrow(
{_, [{translation_error, #{reason := always, exception := error}}]},
{_, [{translation_error, #{reason := always, exception := error, stacktrace := _}}]},
hocon_tconf:translate(Sc, Conf, Mapped)
).

translation_throw_test() ->
Sc = #{
roots => [
{f1, hoconsc:mk(integer())},
{f2, hoconsc:mk(string())}
],
translations => #{"tr1" => [{"f3", fun(_Conf) -> throw(expect) end}]}
},
{ok, Data} = hocon:binary("f1=12,f2=foo", #{format => richmap}),
{Mapped, Conf} = hocon_tconf:map(Sc, Data),
?assertThrow(
{_, [{translation_error, #{reason := expect}}]},
hocon_tconf:translate(Sc, Conf, Mapped)
).

Expand Down Expand Up @@ -1022,6 +1037,23 @@ integrity_crash_test() ->
),
ok.

integrity_throw_test() ->
Sc = #{
roots => [root],
fields => #{root => [{f1, integer()}]},
validations => [{"always-throw", fun(_) -> throw(expect) end}]
},
Data1 = "root={f1=1}",
?VALIDATION_ERR(
#{
reason := integrity_validation_failure,
validation_name := "always-throw",
result := expect
},
check_plain_bin(Sc, Data1, #{atom_key => true})
),
ok.

check_plain_bin(Sc, Data, Opts) ->
{ok, Conf} = hocon:binary(Data, #{}),
hocon_tconf:check_plain(Sc, Conf, Opts).
Expand Down

0 comments on commit e50e632

Please sign in to comment.