3.1 Starting Again
We've had a quick taste of Mnesia, and what some of the calls look like in LFE. Next we're going to tackle a bit more heady stuff: tables and relationships.
Go ahead and re-start the REPL, using a different database name this time:
$ DB=./Company.DB make mnesia-shell
> (mnesia:create_schema (list (node))) ok > (mnesia:start) ok >
Then pull in the code that will let us define our tables, adding them to the Mnesia schema we just created:
> (slurp '"src/structure.lfe") #(ok structure) >
3.2 Records as Tables
structure module includes LFE records that act as our table definitions,
as well as a macro that lets us create Mnesia tables with almost no boilerplate.
The following records are defined in
(defrecord employee id name salary gender phone room-number) (defrecord department id name) (defrecord project name number) (defrecord manager employee-id department-id) (defrecord in-department employee-id department-id) (defrecord in-project employee-id project-name)
These records (tables) are taken from the example given in the Erlang Mnesia tutorial which also gives this entity diagram for their proposed "Company" database:
3.3 Creating Our Tables
src/structure.lfe module which we have just imported, some utility
functions are defined which will lets us easily create tables in Mnesia based
on the records defined in the
include/tables.lfe file. Of particular
interest right now is the
(init) function; let's call it:
> (init) #(ok (#(create-set-tables (#(atomic ok) #(atomic ok) #(atomic ok) #(atomic ok))) #(create-bag-tables (#(atomic ok) #(atomic ok))))) >
This just created all our Mnesia tables for us. If we run it again, we'll see errors indicating that the tables have already been created:
> (init) #(error (#(create-set-tables (#(aborted #(already_exists employee)) #(aborted #(already_exists department)) #(aborted #(already_exists project)) #(aborted #(already_exists in-department)))) #(create-bag-tables (#(aborted #(already_exists manager)) #(aborted #(already_exists in-project)))))) >
As you may guess from the output of that second call, under the covers, the
init function calls a couple of utility functions:
These, in turn, call a macro we created to make table-creation much easier. The custom macro alleviates the dev from having to write tedious and repetitive boilerplate code. This macro actually calls another macro that is generated -- by LFE -- for each record (one that gets a list of all the fields for a given record).
Next, let's re-run that
info function we saw in the previous section:
The output of that function will be very similar to what we saw in the previous section. However, do note that our new tables are reported in the "Active tables" section:
... ---> Active tables <--- in-project : with 0 records occupying 305 words of mem in-department : with 0 records occupying 305 words of mem manager : with 0 records occupying 305 words of mem project : with 0 records occupying 305 words of mem department : with 0 records occupying 305 words of mem employee : with 0 records occupying 305 words of mem ...
If you would like to check up on the tables created above, you can use the
table_info function to pull out certain data. For instance, here's how
you find what backend type is being used for any given table:
> (mnesia:table_info 'employee 'type) set > (mnesia:table_info 'in-project 'type) bag >
If you're interested in seeing all the details of any given table, you can
do so with the
> (mnesia:table_info 'employee 'all) (#(access_mode read_write) #(active_replicas (nonode@nohost)) #(all_nodes (nonode@nohost)) #(arity 7) #(attributes (id name salary gender phone room-number)) #(checkpoints ()) #(commit_work ()) #(cookie #(#(1396 680215 616649) nonode@nohost)) #(cstruct #(cstruct employee set (nonode@nohost) () () 0 read_write false () () false employee (id name salary gender ...) () () () #(...)...)) #(disc_copies ()) #(disc_only_copies ()) #(frag_properties ()) #(index ()) #(load_by_force false) #(load_node nonode@nohost) #(load_order 0) #(load_reason #(dumper create_table)) #(local_content false) #(majority false) #(master_nodes ()) #(memory 317) #(ram_copies (nonode@nohost)) #(record_name employee) #(record_validation #(employee 7 set)) #(type set) #(size 0) #(snmp ()) #(storage_properties ...) #(...)...) >
Next up, we'll start inserting some data.