Last active
June 5, 2024 07:04
-
-
Save mpugach/2d264c063db9bc91af0f7c7ec8175037 to your computer and use it in GitHub Desktop.
Convert deeply nested Elixir struct into map
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If anyone seeing this wants to account for lists as well, simply add: