Converting Erlang Record into Maps and Maps into Erlang Record

Hello All,

I am missing the boat on what I think should be a simple conversion process.

Given:

defmodule User do
  require Record
  Record.defrecord(:user, name: "meg", age: "25")
end

Record to map is fairly straightforward:

user_map = Enum.into(user(record), %{})

But this is not optimal because for every ‘defrecord’ declaration you would need to create a conversion function new ‘defrecord’ type. E.g. “user” above. But at least there is a solution.

However, for the return trip from map to record I do not see any path.

This works:

record = user([age: 45, name: "Mike"])
# -> {:user, "Mike", 45}

But this does not:

attrs = [age: 45, name: "Mike"]
record = user(attrs)

** !?!?!? **

I did get this to work but this seems just a tiny bit convoluted.

defmodule Test.This do 
  def map_to_record(map) do
    [ hd | _ ] = Enum.map(
      [map],
      fn %{age: age, name: name}
      ->
        {:user, age, name}
      end)  
    hd
    end
end

And again this requires a custom function for every ‘defrecord’ declaration to move between maps to records.

Thanks in advanced!

Records on the Erlang side are a compile-time-only concern - at runtime, they are just tuples. In Elixir the macros created by defrecord contain the information necessary to understand where name is in {:user, "meg", "25"}.

That’s also why your “reverse” case fails: the argument to user/1 needs to be a compile-time keyword list, but user(attrs) happens at runtime.

You’d need to write out the list explicitly:

attrs = [age: 45, name: "Mike"]
record = user(age: attrs[:age], name: attrs[:name])
4 Likes

That is a whole lot less convoluted!

Thank you, sir!