Skip to content

Instantly share code, notes, and snippets.

@mpugach
Last active October 11, 2022 02:04
Show Gist options
  • Save mpugach/2d264c063db9bc91af0f7c7ec8175037 to your computer and use it in GitHub Desktop.
Save mpugach/2d264c063db9bc91af0f7c7ec8175037 to your computer and use it in GitHub Desktop.
Convert deeply nested Elixir struct into map
defmodule MapFromDeepStruct do
def from_deep_struct(%{} = map), do: convert(map)
defp convert(data) when is_struct(data) do
data |> Map.from_struct() |> convert()
end
defp convert(data) when is_map(data) do
for {key, value} <- data, reduce: %{} do
acc ->
case key do
:__meta__ ->
acc
other ->
Map.put(acc, other, convert(value))
end
end
end
defp convert(other), do: other
end
defmodule MapFromDeepStructTest do
defmodule DummyA do
@type t() :: %__MODULE__{
name: String.t(),
address: DummyB.t()
}
defstruct name: "", address: nil
end
defmodule DummyB do
@type t() :: %__MODULE__{
street: String.t()
}
defstruct street: ""
end
defmodule DummyC do
use Ecto.Schema
schema "dummies" do
field :street, :string
end
end
use ExUnit.Case
setup_all do
{:ok, expected: %{name: "John", address: %{street: "Baker"}}}
end
test "struct in struct", state do
input = %DummyA{
name: "John",
address: %DummyB{street: "Baker"}
}
assert MapFromDeepStruct.from_deep_struct(input) == state.expected
end
test "struct in map", state do
input = %{
name: "John",
address: %DummyB{street: "Baker"}
}
assert MapFromDeepStruct.from_deep_struct(input) == state.expected
end
test "map in map", state do
input = %{
name: "John",
address: %{street: "Baker"}
}
assert MapFromDeepStruct.from_deep_struct(input) == state.expected
end
test "ecto struct" do
input = %DummyC{street: "Baker"}
assert Poc.MapFromDeepStruct.from_deep_struct(input) == %{id: nil, street: "Baker"}
end
end
@Nezteb
Copy link

Nezteb commented Oct 11, 2022

If anyone seeing this wants to account for lists as well, simply add:

defp convert(data) when is_list(data) do
  Enum.map(data, fn item ->
    convert(item)
  end)
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment