@csaintc: Here is how you can do it without any extra library:
# example structs:
defmodule Author do
defstruct contact_email: "", first_name: "", last_name: ""
end
defmodule Comment do
defstruct author: %Author{}, body: ""
end
defmodule Post do
defstruct author: %Author{}, body: "", comments: [], title: ""
end
# here is my module with to_struct proposition
defmodule Example do
# here we are calling to_struct for has_many associations
def to_struct(list, mod) when is_list(list) and is_atom(mod),
do: Enum.map(list, &to_struct(&1, mod))
# here we are calling to_struct for has_one and belongs_to association
def to_struct(map, key, mod) when is_map(map) and is_atom(key) and is_atom(mod),
do: Map.update!(map, key, &to_struct(&1, mod))
# here is custome to_struct for Post, because it has 2 extra relations
def to_struct(map, Post) do
Post
|> struct(map)
|> to_struct(:author, Author)
|> to_struct(:comments, Comment)
end
# here is custom to_struct for Comment, because it has 1 extra relation
def to_struct(map, Comment) do
Comment
|> struct(map)
|> to_struct(:author, Author)
end
# this applies to any other module - without relation i.e. sub-structs
def to_struct(map, module) when is_map(map) and is_atom(module),
do: struct(module, map)
end
# example post data:
post = %{
author: %{
contact_email: "michael_smith@example.com",
first_name: "Michael",
last_name: "Smith",
},
body: "Elixir rules! Elixir is the best! Elixir ...",
comments: [
%{
author: %{
contact_email: "david_smith@example.com",
first_name: "David",
last_name: "Smith",
},
body: "Nice article",
},
%{
author: %{
contact_email: "john_smith@example.com",
first_name: "John",
last_name: "Smith",
},
body: "John was here!",
}
],
title: "An awesome title here ...",
}
IO.inspect post
IO.inspect Example.to_struct(post, Post)
# you can also call lists of posts:
Example.to_struct([post], Post)
If I would suggest a library then it would be Ecto, because it also supports validations.