A tiny library to facilitate record upgrades in Elixir
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



ExRecord is a simple convention and a library to facilitate easier Elixir record upgrades (normally during code change / release upgrades).


In order to benefit from ExRecord, define your records this way:

defrecord MyRecord, __version__: 1, field: nil do
  use ExRecord

You can also rename __version__ to any other name:

use ExRecord, version: :__version_field__


In order to upgrade (or downgrade) your record, call MyRecord.__convert__(record_to_be_converted) and you'll get a converted up-to-date record.

By default, the algorithm for conversion is very simple: it takes the original (to be converted record), extracts all fields values and creates a new record with these fields. It will silently ignore fields that no longer exist in the actual record.

You can also override a convertion procedure for any version by overriding __convert__(version, record) function:

defrecord TestCustomChangeRecord, __version__: 2, a: 1 do
  use ExRecord

  def __convert__(1, src) do
    super(version, src).a(2)

You can also rename the __convert__ function:

use ExRecord, convert: :__my_convert__


iex(1)> defrecord Foo, __version__: 1, bar: nil do
...(1)>   use ExRecord
...(1)> end
iex(2)> Foo.new(bar: 1)
Foo[__version__: {1,[:__version__,:bar]}, bar: 1]
iex(3)> inspect v(-1), raw: true

Now, let's copy the raw record representation and reuse it in a new IEx session:

iex(1)> defrecord Foo, __version__: 2, bar: nil, foo: nil do
...(1)>   use ExRecord
...(1)> end
iex(2)> record = {Foo,{1,[:__version__,:bar]},1}
iex(3)> Foo.__convert__(record)
Foo[__version__: {2,[:__version__,:bar,:foo]}, bar: 1, foo: nil]

As you can see, the old record got automatically converted to a new record that contains more fields.


It is important to understand that each ExRecordified record will carry its version & field information in the very first field:

iex(1)> defrecord Foo, __version__: 1, bar: 2 do
...(1)>   use ExRecord
...(1)> end
iex(2)> Foo.new
Foo[__version__: {1,[:__version__,:bar]}, bar: 2]

Also, you don't need to have a runtime dependency on the exrecord application as all work is done during compile time. All of the conversion code gets compiled into your record modules.