Skip to content

Commit

Permalink
Merge pull request #253 from emqx/mix-alias
Browse files Browse the repository at this point in the history
fix: merge struct when mix alias
  • Loading branch information
zhongwencool authored May 4, 2023
2 parents ef14b33 + a470865 commit b1ccc20
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 12 deletions.
18 changes: 12 additions & 6 deletions src/hocon_tconf.erl
Original file line number Diff line number Diff line change
Expand Up @@ -423,8 +423,8 @@ map_fields([{_, FieldSchema} = Field | Fields], Conf0, Acc, Opts) ->

map_fields_cont([{_, FieldSchema} = Field | Fields], Conf0, Acc, Opts) ->
FieldType = field_schema(FieldSchema, type),
[FieldName | Aliases] = name_and_aliases(Field),
FieldValue = get_field_value(Opts, [FieldName | Aliases], Conf0),
[FieldName | Aliases] = NameAliases = name_and_aliases(Field),
FieldValue = get_field_value(Opts, NameAliases, Conf0),
NewOpts = push_stack(Opts, FieldName),
{FAcc, FValue} =
try
Expand Down Expand Up @@ -1047,12 +1047,18 @@ mkrich(Map, Box) when is_map(Map) ->
mkrich(Val, Box) ->
boxit(Val, Box).

get_field_value(_, [], _Conf) ->
undefined;
get_field_value(Opts, [Path | Rest], Conf) ->
get_field_value(Opts, NameAliases, Conf) ->
get_field_value(Opts, NameAliases, Conf, #{}).

get_field_value(_, [], _Conf, Acc) when Acc =:= #{} -> undefined;
get_field_value(_, [], _Conf, Acc) ->
Acc;
get_field_value(Opts, [Path | Rest], Conf, Acc) ->
case do_get_field_value(Opts, Path, Conf) of
undefined ->
get_field_value(Opts, Rest, Conf);
get_field_value(Opts, Rest, Conf, Acc);
Value when is_map(Value) ->
get_field_value(Opts, Rest, Conf, hocon_maps:deep_merge(Value, Acc));
Value ->
Value
end.
Expand Down
127 changes: 122 additions & 5 deletions test/hocon_schema_aliases_tests.erl
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,21 @@ roots() ->
].

fields("root1") ->
[{key1, integer()}];
[
{key1, hoconsc:mk(integer(), #{required => false})},
{key2, hoconsc:mk(integer(), #{required => false})}
];
fields("root2") ->
[
{key2, #{aliases => [old_key2], type => integer()}},
{key3, string()}
{key3, string()},
{key4, #{
aliases => [old_key4], type => integer(), converter => fun incr/2, required => false
}}
].

%% test a root field can be safely renamed
%% in this case, one of the root level fieds in the test schema ?MODULE.
%% in this case, one of the root level fields in the test schema ?MODULE.
%% old_root1 is renamed to root1
check_root_test() ->
ConfText = "{old_root1 = {key1 = 1}, root2 = {key2 = 2, key3 = \"foo\"}}",
Expand All @@ -59,6 +65,40 @@ check_root_test() ->
<<"root2">> => #{<<"key2">> => 2, <<"key3">> => "foo"}
},
hocon_tconf:check_plain(?MODULE, Conf)
),
{ok, RichConf} = hocon:binary(ConfText, #{format => richmap}),
?assertEqual(
#{
<<"old_root1">> => #{<<"key1">> => 1},
<<"root1">> => #{<<"key1">> => 1},
<<"root2">> => #{<<"key2">> => 2, <<"key3">> => "foo"}
},
hocon_util:richmap_to_map(hocon_tconf:check(?MODULE, RichConf))
).

check_converter_test() ->
ConfText = "{old_root1 = {key1 = 1}, root2 = {key2 = 2, key3 = \"foo\", old_key4 = 3}}",
{ok, Conf} = hocon:binary(ConfText),
?assertEqual(
#{
<<"root1">> => #{<<"key1">> => 1},
<<"root2">> => #{<<"key2">> => 2, <<"key3">> => "foo", <<"key4">> => 4}
},
hocon_tconf:check_plain(?MODULE, Conf)
),
{ok, RichConf} = hocon:binary(ConfText, #{format => richmap}),
?assertEqual(
#{
<<"old_root1">> => #{<<"key1">> => 1},
<<"root1">> => #{<<"key1">> => 1},
<<"root2">> => #{
<<"key2">> => 2,
<<"key3">> => "foo",
<<"old_key4">> => 3,
<<"key4">> => 4
}
},
hocon_util:richmap_to_map(hocon_tconf:check(?MODULE, RichConf))
).

check_field_test() ->
Expand All @@ -72,6 +112,18 @@ check_field_test() ->
<<"root2">> => #{<<"key2">> => 2, <<"key3">> => "foo"}
},
hocon_tconf:check_plain(?MODULE, Conf)
),
{ok, RichConf} = hocon:binary(ConfText, #{format => richmap}),
?assertEqual(
#{
<<"old_root1">> => #{<<"key1">> => 1},
<<"root1">> => #{<<"key1">> => 1},
<<"root2">> => #{<<"key2">> => 2, <<"key3">> => "foo", <<"old_key2">> => 2}
%% deprecated field(old_root3,root3) is not included in the map
%%<<"old_root3">> => a,
%% <<"root3">> => b
},
hocon_util:richmap_to_map(hocon_tconf:check(?MODULE, RichConf))
).

check_env_test() ->
Expand All @@ -83,12 +135,74 @@ check_env_test() ->
?assertEqual(
#{
<<"root1">> => #{<<"key1">> => 42},
<<"root2">> => #{<<"key2">> => 43, <<"key3">> => "foo"}
<<"root2">> => #{<<"key2">> => 43, <<"key3">> => "foo", <<"key4">> => 2}
},
hocon_tconf:check_plain(?MODULE, Conf)
),
{ok, RichConf} = hocon:binary(ConfText, #{format => richmap}),
Conf1 = hocon_tconf:merge_env_overrides(?MODULE, RichConf, all, #{format => richmap}),
?assertEqual(
#{
<<"root1">> => #{<<"key1">> => 42},
<<"old_root1">> => #{<<"key1">> => 42},
<<"root2">> => #{
<<"key2">> => 43,
<<"old_key2">> => 43,
<<"key3">> => "foo",
<<"key4">> => 2,
<<"old_key4">> => 1
}
},
hocon_util:richmap_to_map(hocon_tconf:check(?MODULE, Conf1))
)
end,
with_envs(Fun, [], envs([{"EMQX_OLD_ROOT1__key1", "42"}, {"EMQX_ROOT2__OLD_KEY2", "43"}])).
with_envs(
Fun,
[],
envs([
{"EMQX_OLD_ROOT1__key1", "42"},
{"EMQX_ROOT2__OLD_KEY2", "43"},
{"EMQX_ROOT2__OLD_KEY4", "1"}
])
).

check_mix_env_test() ->
Fun =
fun() ->
ConfText = "{old_root1 = {key1 = 0, key2 = 1}}",
{ok, Conf0} = hocon:binary(ConfText),
Conf = hocon_tconf:merge_env_overrides(?MODULE, Conf0, all, #{format => map}),
?assertEqual(
#{
<<"root1">> => #{<<"key1">> => 0, <<"key2">> => 2},
<<"root2">> => #{<<"key2">> => 42, <<"key3">> => "foo"}
},
hocon_tconf:check_plain(?MODULE, Conf)
),
{ok, RichConf} = hocon:binary(ConfText, #{format => richmap}),
Conf1 = hocon_tconf:merge_env_overrides(?MODULE, RichConf, all, #{format => richmap}),
?assertEqual(
#{
<<"root1">> => #{<<"key1">> => 0, <<"key2">> => 2},
<<"old_root1">> => #{<<"key1">> => 0, <<"key2">> => 1},
<<"root2">> => #{
<<"key2">> => 42,
<<"old_key2">> => 42,
<<"key3">> => "foo"
}
},
hocon_util:richmap_to_map(hocon_tconf:check(?MODULE, Conf1))
)
end,
with_envs(
Fun,
[],
envs([
{"EMQX_ROOT1__KEY2", "2"},
{"EMQX_ROOT2__OLD_KEY2", "42"},
{"EMQX_ROOT2__KEY3", "foo"}
])
).

no_value_test() ->
ConfText = "{root3 = b, old_root3 = a}",
Expand All @@ -100,3 +214,6 @@ with_envs(Fun, Args, Envs) ->

envs(Envs) ->
[{"HOCON_ENV_OVERRIDE_PREFIX", "EMQX_"} | Envs].

incr(undefined, _Opts) -> undefined;
incr(Val, _Opts) -> Val + 1.
2 changes: 1 addition & 1 deletion test/hocon_tconf_tests.erl
Original file line number Diff line number Diff line change
Expand Up @@ -825,7 +825,7 @@ type_stack_cannot_concatenate_test() ->
#{
path := "f1.1.maybe",
matched_type := "s1/s2",
errors := [_ | _]
reason := required_field
},
hocon_tconf:check_plain(Sc, #{<<"f1">> => [#{<<"maybe">> => #{}}]}, #{})
),
Expand Down

0 comments on commit b1ccc20

Please sign in to comment.