I am trying to have a function that ensures the table I need is already created and if not to create it. Here's the sample:
ensure_table_exists(Table, MnesiaTables, Nodes) ->
case lists:member(Table, MnesiaTables) of
true ->
throw({error, db_might_have_already_been_created});
false ->
mnesia:create_table(Table, [{disc_copies, Nodes},
{attributes, record_info(fields, Table)}]),
ok
end.
The issue is that when compiling I get the error: illegal record info
.
It might have to do that record_info is resolved at compile time or that the second argument to record info should actually be a record that can be retrieved from the source code ?
Yes, all record related things including record_info/2
are resolved at compile time. This means that record and field names must be known at compile time. This is the reason for the compiler error.
I don't think your function is really too defensive in that what you are doing is signaling a more specific error. It would be another matter if you were to return {error, ...}
.
One last point is that if you mean to raise an exception you should not use throw/1
but instead use erlang:error/1
. throw
is intended for non-local return (caught with a catch
) while erlang:error
is intended for raising an exception. In many cases the result may be the same but the actual error value may be misleading (nocatch
). It is always better the clearer you can show your intention, which in this case is signaling an error.
P.S. Yes, I know that catch
also catches errors/exits as well. This was intentional. In a perfect world maybe catch
should only catch throws and try
only errors/exits.
Unfortunately record_info is not really a function even if it looks like one.
You can verify that by testing the following. Create a file:
-module(something).
-record(a, {}).
Start the Erlang shell:
> rr(something).
[a]
> record_info(fields, a).
[]
> A = a.
> record_info(fields, A).
* 2: illegal record info
So my recommendation would be to either use a macro or a specialised function for the record_info part.
To answer your original question. Use something like:
tables() ->
[?TABLE_MACRO(tablename),
?TABLE_MACRO(tablename2),
...].
where TABLE_MACRO is something like:
-define(TABLE_MACRO(Table), fun() ->
mnesia:create_table(Table, [{disc_copies, Nodes},
{attributes, record_info(fields, Table)}])
end).
and then have a function using something like the below.
[case CreateTable of
{aborted, {already_exists, _}} -> ok;
{atomic, ok} -> ok
end || CreateTable <- tables()].
Yuck! Can be cleaned up quite a bit, but hopefully you understand the general idea.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With