defmodule ExStructTranslator do
@moduledoc """
A Translator of Structs in Elixir.
"""
@doc """
translate a map with string-key to atom-key recursively.
"""
def to_atom_struct(list) when is_list(list) do
Enum.map(list, fn ele ->
to_atom_struct(ele)
end)
end
def to_atom_struct(struct) when is_map(struct) do
for {key, val} <- struct, into: %{}, do: {translate_key(key), to_atom_struct(val)}
end
def to_atom_struct(else_ele) do
else_ele
end
defp translate_key(key) when is_atom(key), do: key
defp translate_key(key), do: String.to_atom(key)
@doc """
struct => map
"""
def struct_to_map(struct) do
struct
|> Map.from_struct()
|> Map.delete(:__meta__)
|> Enum.reject(fn {_, v} ->
case is_assoc_loaded_type?(v) do
true ->
not Ecto.assoc_loaded?(v)
false ->
false
end
end)
|> Enum.into(%{})
end
def is_assoc_loaded_type?(%Ecto.Association.NotLoaded{}), do: true
def is_assoc_loaded_type?(_), do: false
@doc """
map => struct
"""
@spec map_to_struct(atom(), map()) :: Struct.t()
def map_to_struct(kind, attrs) do
struct = struct(kind)
Enum.reduce(Map.to_list(struct), struct, fn {k, _}, acc ->
case Map.fetch(attrs, Atom.to_string(k)) do
{:ok, v} ->
%{acc | k => v}
:error ->
case Map.fetch(attrs, k) do
{:ok, v} -> %{acc | k => v}
:error -> acc
end
end
end)
end
@doc """
map => str
"""
def map_to_str(map) when is_nil(map), do: nil
def map_to_str(map), do: Poison.encode!(map)
@doc """
str => atom map
"""
def str_to_atom_map(str) do
str
|> str_to_map()
|> to_atom_struct()
end
@doc """
str => map
"""
def str_to_map(str) do
str
|> String.replace("\'", "\"")
|> Poison.decode!()
end
end