fix(emqx_map_lib): ignore non-number non-map values

This commit is contained in:
Zaiming (Stone) Shi 2022-05-16 10:29:47 +02:00
parent 3524fb6994
commit 5deb0c4878
2 changed files with 96 additions and 9 deletions

View File

@ -269,17 +269,50 @@ error_type_two_maps(M1, _M2) ->
%% @doc Sum-merge map values. %% @doc Sum-merge map values.
%% For bad merges, ErrorLogger is called to log the key, and value in M2 is ignored. %% For bad merges, ErrorLogger is called to log the key, and value in M2 is ignored.
best_effort_recursive_sum(M1, M2, ErrorLogger) -> best_effort_recursive_sum(M10, M20, ErrorLogger) ->
FilterF = fun(K, V) ->
case erlang:is_number(V) of
true ->
true;
false ->
ErrorLogger(#{failed_to_merge => K, bad_value => V}),
false
end
end,
M1 = deep_filter(M10, FilterF),
M2 = deep_filter(M20, FilterF),
do_best_effort_recursive_sum(M1, M2, ErrorLogger).
do_best_effort_recursive_sum(M1, M2, ErrorLogger) ->
F = F =
fun(Key, V1, V2) -> fun(Key, V1, V2) ->
case {erlang:is_map(V1), erlang:is_map(V2)} of case {erlang:is_map(V1), erlang:is_map(V2)} of
{true, true} -> {true, true} ->
best_effort_recursive_sum(V1, V2, ErrorLogger); do_best_effort_recursive_sum(V1, V2, ErrorLogger);
{false, false} when is_number(V1) andalso is_number(V2) -> {true, false} ->
V1 + V2; ErrorLogger(#{failed_to_merge => Key, bad_value => V2}),
_ -> do_best_effort_recursive_sum(V1, #{}, ErrorLogger);
ErrorLogger(#{failed_to_merge => Key}), {false, true} ->
V1 ErrorLogger(#{failed_to_merge => Key, bad_value => V1}),
do_best_effort_recursive_sum(V2, #{}, ErrorLogger);
{false, false} ->
true = is_number(V1),
true = is_number(V2),
V1 + V2
end end
end, end,
merge_with(F, M1, M2). merge_with(F, M1, M2).
deep_filter(M, F) when is_map(M) ->
%% maps:filtermap is not available before OTP 24
maps:from_list(
lists:filtermap(
fun
({K, V}) when is_map(V) ->
{true, {K, deep_filter(V, F)}};
({K, V}) ->
F(K, V) andalso {true, {K, V}}
end,
maps:to_list(M)
)
).

View File

@ -49,8 +49,62 @@ best_effort_recursive_sum_test_() ->
), ),
receive receive
{log, Log} -> {log, Log} ->
?assertEqual(#{failed_to_merge => bar}, Log) ?assertEqual(#{failed_to_merge => bar, bad_value => bar}, Log)
after 1000 -> error(timeout) after 1000 -> error(timeout)
end end
end end,
?_assertEqual(
#{},
emqx_map_lib:best_effort_recursive_sum(
#{foo => foo}, #{foo => bar}, DummyLogger
)
),
?_assertEqual(
#{foo => 1},
emqx_map_lib:best_effort_recursive_sum(
#{foo => 1}, #{foo => bar}, DummyLogger
)
),
?_assertEqual(
#{foo => 1},
emqx_map_lib:best_effort_recursive_sum(
#{foo => bar}, #{foo => 1}, DummyLogger
)
),
?_assertEqual(
#{foo => #{bar => 1}},
emqx_map_lib:best_effort_recursive_sum(
#{foo => #{bar => 1}}, #{foo => 1}, DummyLogger
)
),
?_assertEqual(
#{foo => #{bar => 1}},
emqx_map_lib:best_effort_recursive_sum(
#{foo => 1}, #{foo => #{bar => 1}}, DummyLogger
)
),
?_assertEqual(
#{foo => #{bar => 1}},
emqx_map_lib:best_effort_recursive_sum(
#{foo => 1, bar => ignored}, #{foo => #{bar => 1}}, DummyLogger
)
),
?_assertEqual(
#{foo => #{bar => 2}, bar => #{foo => 1}},
emqx_map_lib:best_effort_recursive_sum(
#{foo => 1, bar => #{foo => 1}}, #{foo => #{bar => 2}, bar => 2}, DummyLogger
)
),
?_assertEqual(
#{foo => #{bar => 2}, bar => #{foo => 1}},
emqx_map_lib:best_effort_recursive_sum(
#{foo => #{bar => 2}, bar => 2}, #{foo => 1, bar => #{foo => 1}}, DummyLogger
)
),
?_assertEqual(
#{foo => #{bar => #{}}},
emqx_map_lib:best_effort_recursive_sum(
#{foo => #{bar => #{foo => []}}}, #{foo => 1}, DummyLogger
)
)
]. ].