A C++ library for efficient implementation of in-memory relational models.
Relational models are a very effective way to store data. They provide a natural syntax for querying and manipulating data, using high level query language such as SQL. They are efficient since they manage collections of objects, and indexes are maintained and used implicitly.
Although the C++ Standard Library containers provide efficient collections via its containers library, its syntax is bulkier and less natural than higher level query languages.
It is not possible to query standard containers, instead they must be iterated and post-filtered. It is difficult to maintain keys, for example to have multiple keys into the same data, to modify the key of an item in a container, or to delete a row from multiple indexes. When querying multiple tables using the Standard Library, the programmer must perform this in a low level way with nested loops, while a relational notation uses “joins” to combine several tables.
In relational databases, query analyzers transform queries expressed in a high level language into execution strategies for data retrieval. Relational Model Library (RML) does this using template metaprogramming.
RML allows programmers to write queries such as
select( (customers, accounts),
customers.name == ”smith” &&
customers.customer_id == accounts.customer_id &&
accounts.value > 10 )
which is executed as
r = customer_name_map.equal_range(“smith”);
r.first != r.second; ++r.first)
CustomerAccountMap::const_iterator j =
if(j != customer_account_map.end() &&
j->account_value > 10)
// Do stuff
Because this transformation is performed at compile-time, code generated by RML is as efficient as hand-crafted code. The code is much more efficient than the C++ Standard Library when there are multiple keys per table, because RML provides an efficient multi-index implementation, similar to Boost.MultiIndex. See the benchmarks.
A table can be defined
// Define the row
// Define the table
Indexes are maintained automatically when the data is inserted, updated or deleted,
// Insert a row
customers.insert(Customer(1, "Calum", "B28 0AP", 0.0));
// Update a row using a condition
customers.update_where( customers.balance = 100,
customers.customer_id == 1);
// Erase all rows matching the condition
customers.erase_where(customers.customer_id == 1);
Queries can be written using operator-overloaded syntax,
customers.name == "Calum" &&
customers.balance < 0 )
More complex queries can be formulated by joining multiple tables together,
select( (orders, customers, accounts),
orders.date < “2002-05-21” &&
orders.status = outstanding &&
customers.customer_id = orders.customer_id &&
accounts.customer_id == customers.id &&
orders.value > accounts.balance)
Data can be loaded and saved to CSV files,
// Save tables
file << customers << accounts << orders;
// Load tables
file >> customers >> accounts >> orders;
Home page: http://calumgrant.net/relational
Author: Calum Grant (http://calumgrant.net/)
Email: See http://calumgrant.net/
Please feel welcome to give feedback or ask for help.