Wednesday, June 6, 2012

Erlang and mnesia select

This is copied from Erlang and mnesia:select

 

Here is an example from the official Erlang docs. The query returns the name of each male person aged more then 30.
MatchHead = #person{name='$1', sex=male, age='$2', _='_'},
Guard = {'>', '$2', 30},
Result = '$1',
mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),
Criterias are expressed with $ and the whole thing becomes quite convulted for anything more complicated.
Furthermore it is impossible to do what would be basic operations in other database engines, like sorting the results.
But, a module exists that makes queries better legible . QLC that stands for Query List Comprehension. It supports Mnesia, ETS and DETS.
Here is the previous query, rewritten:
Query = qlc:q([Person#person.name || Person <- mnesia:table(Tab), Person#person.sex == male, Person#person.age > 30]),
In this case the query is expressed as a list comprehension. Criterias are written in a comprehensible manner in the second par of the list comprehension.
If you want to execute this query in Mnesia, you have to do so in a transaction.
-include_lib("stdlib/include/qlc.hrl")
Transaction = fun() ->
    Query = qlc:q([Person#person.name || Person <- mnesia:table(Tab), Person#person.sex == male, Person#person.age > 30]),
    qlc:eval(Query)
end,
mnesia:transaction(Transaction),
To efficiently sort the result, qlc provides qlc:sort.
-include_lib("stdlib/include/qlc.hrl")
Transaction = fun() ->
    Query = qlc:q([Person#person.name || Person <- mnesia:table(Tab), Person#person.sex == male, Person#person.age > 30]),
    Order = fun(A, B) ->
        B#person.age > A#person.age
    end,
    qlc:eval(qlc:sort(Query, [order, Order]))
end,
mnesia:transaction(Transaction),