Dynamically create Tables using Amnesia

I’m trying to create a table using meh’s Amnesia library and it works as long as everything is specified explicitly, but when I try to create a table where the name or attributes are being loaded from another variable during compile-time it raises an error.

This is my table:

use Amnesia

defdatabase MyApp.DB do
  @attrs [:id, :a, :b, :c]

  deftable SomeTable, @attrs, type: :bag do
  end 
end

and this is the error:

Compiling 1 file (.ex)

== Compilation error on file lib/mnesia.ex ==
** (ArgumentError) argument error
    :erlang.length({:@, [line: 6], [{:attrs, [line: 6], nil}]})
    lib/amnesia/table/definition.ex:63: Amnesia.Table.Definition.define/4
    expanding macro: Amnesia.Database.deftable/4
    lib/db.ex:6: MyApp.DB (module)

I’ve tried everything I could think of, but eventually gave in and opened an issue on Github. The author of the library is also not sure how to get this to work, because of the way quote works. I’m hoping someone can point out the issue in the implementation of the deftable macro, so we can try to fix it. This is the Github Issue:

And this is the current implementation of deftable:

It is a macro, you have to supply the literals, not a @attribute, so just change your deftable line to be:

deftable SomeTable, [:id, :a, :b, :c], type: :bag ... etc

I know that it works that way, and that’s what I’m asking. Is there a way to define the table name or attributes from a variable or a module attribute?

Yes but not by using deftable, instead you can just use the raw mnesia calls directly. Amnesia just adds a DSEL for defining such ‘static’ tables on mnesia itself, so if you are not needing the static parts, just use mnesia straight. :slight_smile:

If you have a static list of tables you want to generate in Amnesia you can do that if you want, but not dynamically at runtime from what I’ve seen.

But yes, to generate a deftable at compile-time from a compile-time variable you can do that:

defdatabase MyApp.DB do
  @attrs [:id, :a, :b, :c]

  quote do
    deftable SomeTable, unquote(@attrs), type: :bag do
    end 
  end
end

Or something along those lines. :slight_smile:

Thank you for responding. I’ve been trying to make do with the raw mnesia calls in the mean time, but I thought it would’ve been better if we corrected Amnesia’s behavior since it already provides so many nice wrappers.

As for your sample code, when I tried using it, the application did compile but it didn’t define the table. MyApp.DB.SomeTable isn’t available and calling MyApp.DB.tables() returns an empty list.

I also found another similar issue on Github:

Maybe? Honestly I’d be more interested in seeing something more data driven or that involved less macro magic. There’s definitely a role for macros in that some of the mnesia query syntax is pretty gnarly, but Amnesia is SO macro heavy it’s very hard to know what’s going on sometimes.

1 Like