Skip to content
This repository was archived by the owner on Nov 8, 2022. It is now read-only.

Commit c59255b

Browse files
committed
refactor(utils): re-org based on usage
1 parent 416d2ed commit c59255b

File tree

2 files changed

+159
-140
lines changed

2 files changed

+159
-140
lines changed

lib/helper/utils/map.ex

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
defmodule Helper.Utils.Map do
2+
@moduledoc """
3+
unitil functions
4+
"""
5+
import Ecto.Query, warn: false
6+
import Helper.ErrorHandler
7+
import Helper.ErrorCode
8+
9+
import Helper.Validator.Guards, only: [g_none_empty_str: 1]
10+
11+
alias Helper.Cache
12+
13+
def map_key_stringify(%{__struct__: _} = map) when is_map(map) do
14+
map = Map.from_struct(map)
15+
map |> Enum.reduce(%{}, fn {key, val}, acc -> Map.put(acc, to_string(key), val) end)
16+
end
17+
18+
def map_key_stringify(map) when is_map(map) do
19+
map |> Enum.reduce(%{}, fn {key, val}, acc -> Map.put(acc, to_string(key), val) end)
20+
end
21+
22+
@doc """
23+
see https://stackoverflow.com/a/61559842/4050784
24+
adjust it for map keys from atom to string
25+
"""
26+
def keys_to_atoms(json) when is_map(json) do
27+
Map.new(json, &reduce_keys_to_atoms/1)
28+
end
29+
30+
def keys_to_atoms(string) when is_binary(string), do: string
31+
32+
defp reduce_keys_to_atoms({key, val}) when is_map(val),
33+
# do: {String.to_existing_atom(key), keys_to_atoms(val)}
34+
do: {String.to_atom(key), keys_to_atoms(val)}
35+
36+
defp reduce_keys_to_atoms({key, val}) when is_list(val),
37+
do: {String.to_atom(key), Enum.map(val, &keys_to_atoms(&1))}
38+
39+
defp reduce_keys_to_atoms({key, val}), do: {String.to_atom(key), val}
40+
41+
@doc """
42+
see https://stackoverflow.com/a/61559842/4050784
43+
adjust it for map keys from atom to string
44+
"""
45+
@spec keys_to_strings(map) :: map
46+
def keys_to_strings(json) when is_map(json) do
47+
Map.new(json, &reduce_keys_to_strings/1)
48+
end
49+
50+
defp reduce_keys_to_strings({key, val}) when is_map(val),
51+
do: {Atom.to_string(key), keys_to_strings(val)}
52+
53+
defp reduce_keys_to_strings({key, val}) when is_list(val),
54+
do: {Atom.to_string(key), Enum.map(val, &keys_to_strings(&1))}
55+
56+
defp reduce_keys_to_strings({key, val}), do: {Atom.to_string(key), val}
57+
58+
@doc """
59+
Recursivly camelize the map keys
60+
usage: convert factory attrs to used for simu Graphql parmas
61+
"""
62+
def camelize_map_key(map, v_trans \\ :ignore) do
63+
map_list =
64+
Enum.map(map, fn {k, v} ->
65+
v =
66+
cond do
67+
is_datetime?(v) ->
68+
DateTime.to_iso8601(v)
69+
70+
is_map(v) ->
71+
camelize_map_key(safe_map(v))
72+
73+
is_binary(v) ->
74+
handle_camelize_value_trans(v, v_trans)
75+
76+
true ->
77+
v
78+
end
79+
80+
map_to_camel({k, v})
81+
end)
82+
83+
Enum.into(map_list, %{})
84+
end
85+
86+
defp handle_camelize_value_trans(v, :ignore), do: v
87+
defp handle_camelize_value_trans(v, :downcase), do: String.downcase(v)
88+
defp handle_camelize_value_trans(v, :upcase), do: String.upcase(v)
89+
90+
defp safe_map(%{__struct__: _} = map), do: Map.from_struct(map)
91+
defp safe_map(map), do: map
92+
93+
defp map_to_camel({k, v}), do: {Recase.to_camel(to_string(k)), v}
94+
95+
@spec snake_map_key(map) :: map
96+
def snake_map_key(map) do
97+
map_list =
98+
Enum.map(map, fn {k, v} ->
99+
v =
100+
cond do
101+
is_datetime?(v) ->
102+
DateTime.to_iso8601(v)
103+
104+
is_map(v) ->
105+
snake_map_key(safe_map(v))
106+
107+
true ->
108+
v
109+
end
110+
111+
{Recase.to_snake(to_string(k)), v}
112+
end)
113+
114+
Enum.into(map_list, %{})
115+
end
116+
117+
defp is_datetime?(%DateTime{}), do: true
118+
defp is_datetime?(_), do: false
119+
120+
def map_atom_value(attrs, :string) do
121+
results =
122+
Enum.map(attrs, fn {k, v} ->
123+
cond do
124+
v == true or v == false ->
125+
{k, v}
126+
127+
is_atom(v) ->
128+
{k, v |> to_string() |> String.downcase()}
129+
130+
true ->
131+
{k, v}
132+
end
133+
end)
134+
135+
results |> Enum.into(%{})
136+
end
137+
138+
def deep_merge(left, right), do: Map.merge(left, right, &deep_resolve/3)
139+
140+
# Key exists in both maps, and both values are maps as well.
141+
# These can be merged recursively.
142+
# defp deep_resolve(_key, left = %{},right = %{}) do
143+
defp deep_resolve(_key, %{} = left, %{} = right), do: deep_merge(left, right)
144+
145+
# Key exists in both maps, but at least one of the values is
146+
# NOT a map. We fall back to standard merge behavior, preferring
147+
# the value on the right.
148+
defp deep_resolve(_key, _left, right), do: right
149+
end

lib/helper/utils.ex renamed to lib/helper/utils/utils.ex

Lines changed: 10 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,16 @@ defmodule Helper.Utils do
88

99
import Helper.Validator.Guards, only: [g_none_empty_str: 1]
1010

11-
alias Helper.Cache
11+
alias Helper.{Cache, Utils}
12+
13+
defdelegate map_key_stringify(map), to: Utils.Map
14+
defdelegate keys_to_atoms(map), to: Utils.Map
15+
defdelegate keys_to_strings(map), to: Utils.Map
16+
defdelegate camelize_map_key(map), to: Utils.Map
17+
defdelegate camelize_map_key(map, opt), to: Utils.Map
18+
defdelegate snake_map_key(map), to: Utils.Map
19+
defdelegate deep_merge(left, right), to: Utils.Map
20+
defdelegate map_atom_value(attrs, opt), to: Utils.Map
1221

1322
def get_config(section, key, app \\ :groupher_server)
1423

@@ -87,117 +96,6 @@ defmodule Helper.Utils do
8796
|> Absinthe.Resolution.put_result({:error, message: err_msg, code: ecode()})
8897
end
8998

90-
def map_key_stringify(%{__struct__: _} = map) when is_map(map) do
91-
map = Map.from_struct(map)
92-
map |> Enum.reduce(%{}, fn {key, val}, acc -> Map.put(acc, to_string(key), val) end)
93-
end
94-
95-
def map_key_stringify(map) when is_map(map) do
96-
map |> Enum.reduce(%{}, fn {key, val}, acc -> Map.put(acc, to_string(key), val) end)
97-
end
98-
99-
@doc """
100-
see https://stackoverflow.com/a/61559842/4050784
101-
adjust it for map keys from atom to string
102-
"""
103-
def keys_to_atoms(json) when is_map(json) do
104-
Map.new(json, &reduce_keys_to_atoms/1)
105-
end
106-
107-
def keys_to_atoms(string) when is_binary(string), do: string
108-
109-
def reduce_keys_to_atoms({key, val}) when is_map(val),
110-
# do: {String.to_existing_atom(key), keys_to_atoms(val)}
111-
do: {String.to_atom(key), keys_to_atoms(val)}
112-
113-
def reduce_keys_to_atoms({key, val}) when is_list(val),
114-
do: {String.to_atom(key), Enum.map(val, &keys_to_atoms(&1))}
115-
116-
def reduce_keys_to_atoms({key, val}), do: {String.to_atom(key), val}
117-
118-
@doc """
119-
see https://stackoverflow.com/a/61559842/4050784
120-
adjust it for map keys from atom to string
121-
"""
122-
@spec keys_to_strings(map) :: map
123-
def keys_to_strings(json) when is_map(json) do
124-
Map.new(json, &reduce_keys_to_strings/1)
125-
end
126-
127-
defp reduce_keys_to_strings({key, val}) when is_map(val),
128-
do: {Atom.to_string(key), keys_to_strings(val)}
129-
130-
defp reduce_keys_to_strings({key, val}) when is_list(val),
131-
do: {Atom.to_string(key), Enum.map(val, &keys_to_strings(&1))}
132-
133-
defp reduce_keys_to_strings({key, val}), do: {Atom.to_string(key), val}
134-
135-
@doc """
136-
Recursivly camelize the map keys
137-
usage: convert factory attrs to used for simu Graphql parmas
138-
"""
139-
def camelize_map_key(map, v_trans \\ :ignore) do
140-
map_list =
141-
Enum.map(map, fn {k, v} ->
142-
v =
143-
cond do
144-
is_datetime?(v) ->
145-
DateTime.to_iso8601(v)
146-
147-
is_map(v) ->
148-
camelize_map_key(safe_map(v))
149-
150-
is_binary(v) ->
151-
handle_camelize_value_trans(v, v_trans)
152-
153-
true ->
154-
v
155-
end
156-
157-
map_to_camel({k, v})
158-
end)
159-
160-
Enum.into(map_list, %{})
161-
end
162-
163-
defp handle_camelize_value_trans(v, :ignore), do: v
164-
defp handle_camelize_value_trans(v, :downcase), do: String.downcase(v)
165-
defp handle_camelize_value_trans(v, :upcase), do: String.upcase(v)
166-
167-
defp safe_map(%{__struct__: _} = map), do: Map.from_struct(map)
168-
defp safe_map(map), do: map
169-
170-
defp map_to_camel({k, v}), do: {Recase.to_camel(to_string(k)), v}
171-
172-
@spec snake_map_key(map) :: map
173-
def snake_map_key(map) do
174-
map_list =
175-
Enum.map(map, fn {k, v} ->
176-
v =
177-
cond do
178-
is_datetime?(v) ->
179-
DateTime.to_iso8601(v)
180-
181-
is_map(v) ->
182-
snake_map_key(safe_map(v))
183-
184-
true ->
185-
v
186-
end
187-
188-
{Recase.to_snake(to_string(k)), v}
189-
end)
190-
191-
Enum.into(map_list, %{})
192-
end
193-
194-
def is_datetime?(%DateTime{}), do: true
195-
def is_datetime?(_), do: false
196-
197-
def deep_merge(left, right) do
198-
Map.merge(left, right, &deep_resolve/3)
199-
end
200-
20199
def integerfy(id) when is_binary(id), do: String.to_integer(id)
202100
def integerfy(id), do: id
203101

@@ -220,38 +118,10 @@ defmodule Helper.Utils do
220118
end)
221119
end
222120

223-
def map_atom_value(attrs, :string) do
224-
results =
225-
Enum.map(attrs, fn {k, v} ->
226-
cond do
227-
v == true or v == false ->
228-
{k, v}
229-
230-
is_atom(v) ->
231-
{k, v |> to_string() |> String.downcase()}
232-
233-
true ->
234-
{k, v}
235-
end
236-
end)
237-
238-
results |> Enum.into(%{})
239-
end
240-
241121
def empty_pagi_data do
242122
%{entries: [], total_count: 0, page_size: 0, total_pages: 1, page_number: 1}
243123
end
244124

245-
# Key exists in both maps, and both values are maps as well.
246-
# These can be merged recursively.
247-
# defp deep_resolve(_key, left = %{},right = %{}) do
248-
defp deep_resolve(_key, %{} = left, %{} = right), do: deep_merge(left, right)
249-
250-
# Key exists in both maps, but at least one of the values is
251-
# NOT a map. We fall back to standard merge behavior, preferring
252-
# the value on the right.
253-
defp deep_resolve(_key, _left, right), do: right
254-
255125
@doc """
256126
["a", "b", "c", "c"] => %{"a" => 1, "b" => 1, "c" => 2}
257127
"""

0 commit comments

Comments
 (0)