Current section
Files
Jump to
Current section
Files
src/utils/temporal_sdk_utils_maps.erl
-module(temporal_sdk_utils_maps).
% elp:ignore W0012 W0040
-moduledoc false.
-export([
pop/3,
store/3,
maybe_merge/4,
map_if_ok/2,
deep_merge_opts/2,
deep_merge_opts/3
]).
-spec pop(Key :: term(), Map1 :: map(), Default :: term()) ->
{ValueOrDefault :: term(), Map2 :: map()}.
pop(Key, Map, Default) ->
case Map of
#{Key := V} -> {V, maps:remove(Key, Map)};
#{} -> {Default, Map}
end.
-spec store(Key :: term(), Map :: map(), Value :: term()) -> map().
store(Key, Map, Value) when is_map(Map) ->
case Map of
#{Key := _} -> Map;
#{} -> Map#{Key => Value}
end.
-spec maybe_merge(Key :: term(), Value :: term(), IgnoredValue :: term(), Map :: map()) -> map().
maybe_merge(_Key, Value, Value, Map) -> Map;
maybe_merge(Key, Value, _IgnoredValue, Map) -> Map#{Key => Value}.
-spec map_if_ok(Fun :: fun((Key :: term(), Value1 :: term()) -> Value2 :: term()), Map :: map()) ->
map() | {error, Reason :: term()} | term().
map_if_ok(Fun, Map) when is_function(Fun), is_map(Map) ->
map_if_ok(maps:to_list(Map), Fun, []).
map_if_ok([{Key, Value} | T], Fun, Acc) ->
case Fun(Key, Value) of
{ok, V} -> map_if_ok(T, Fun, [{Key, V} | Acc]);
Err -> Err
end;
map_if_ok([], _Fun, Acc) ->
{ok, maps:from_list(Acc)}.
-spec deep_merge_opts(Map1 :: map(), Map2 :: map()) ->
{ok, MergedMap :: map()} | {error, {invalid_opts, map()}}.
deep_merge_opts(Map1, Map2) ->
deep_merge_opts(Map1, Map2, []).
-spec deep_merge_opts(Map1 :: map(), Map2 :: map(), Required :: [term()]) ->
{ok, MergedMap :: map()} | {error, {invalid_opts, map()}}.
deep_merge_opts(Map1, Map2, Required) ->
do_deep_merge(
lists:sort(proplists:from_map(Map1)),
lists:sort(proplists:from_map(Map2)),
lists:sort(Required),
[],
[]
).
do_deep_merge([{K, V1} | TMap1], [{K, V2} | TMap2], Required, IAcc, Acc) when
is_map(V1), is_map(V2)
->
case deep_merge_opts(V1, V2) of
{ok, V} -> do_deep_merge(TMap1, TMap2, Required, IAcc, [{K, V} | Acc]);
Err -> Err
end;
do_deep_merge([{K, _V1} | TMap1], [{K, V2} | TMap2], Required, IAcc, Acc) ->
do_deep_merge(TMap1, TMap2, Required, IAcc, [{K, V2} | Acc]);
do_deep_merge(Map1, [{Required, V} | TMap2], [Required | TRequired], IAcc, Acc) ->
do_deep_merge(Map1, TMap2, TRequired, IAcc, [{Required, V} | Acc]);
do_deep_merge([{K1, V1} | TMap1], [{K2, _V2} | TMap2] = Map2, Required, IAcc, Acc) ->
case proplists:is_defined(K2, TMap1) of
true ->
do_deep_merge(TMap1, Map2, Required, IAcc, [{K1, V1} | Acc]);
false ->
do_deep_merge(TMap1, TMap2, Required, [K2 | IAcc], [{K1, V1} | Acc])
end;
do_deep_merge([], [], [], [], Acc) ->
{ok, proplists:to_map(Acc)};
do_deep_merge(Map1, [], [], [], Acc) ->
{ok, proplists:to_map(Map1 ++ Acc)};
do_deep_merge(_, Map2, Required, IAcc, _Acc) ->
{error,
{invalid_opts, #{
invalid_keys => IAcc ++ proplists:get_keys(Map2), missing_keys => Required
}}}.