Current section
Files
Jump to
Current section
Files
lib/flattener.ex
defmodule Digger.Flattener do
@moduledoc false
alias Digger.Opts.Flattener, as: Opts
def flatten(map, opts) do
[separator: separator] = Opts.set_options(opts)
do_flatten(map, nil, separator, %{})
end
def unflatten(map, opts) do
[separator: separator] = Opts.set_options(opts)
Enum.reduce(map, %{}, fn {key, value}, acc ->
put_path(acc, split_key(key, separator), value)
end)
end
defp do_flatten(map, prefix, separator, acc) do
Enum.reduce(map, acc, fn {key, value}, acc ->
path = join(prefix, key, separator)
if is_map(value) and value != %{} and not is_struct(value) do
do_flatten(value, path, separator, acc)
else
Map.put(acc, path, value)
end
end)
end
defp join(nil, key, _separator), do: to_string(key)
defp join(prefix, key, separator), do: prefix <> separator <> to_string(key)
defp split_key(key, separator) when is_binary(key),
do: String.split(key, separator)
defp split_key(key, _separator), do: [key]
defp put_path(map, [key], value), do: Map.put(map, key, value)
defp put_path(map, [key | rest], value) do
inner =
case Map.get(map, key) do
%{} = existing when not is_struct(existing) -> existing
_ -> %{}
end
Map.put(map, key, put_path(inner, rest, value))
end
end