Multi Index Table Usage Guide
Description
Below is a usage guide for the multi index table.
In the interest of being thorough and providing clarity, sections of the final .cpp file will be broken out and discussed in further detail. Note that the complete .cpp file can be found at the bottom of this page.
Glossary
code
- Refers to anaccount_name
where a contract has been published.scope
- Anaccount_name
that the data in question belongs to.table_name
- The name of the table that is stored in memory.
Code Break Down
Struct to be stored##
The data to be stored in the multi index table is the limit_order
struct. The functions primary_key()
, get_expiration()
, get_price()
are used to return the table. The returned table will be sorted based on which function was called.
struct limit_order {
uint64_t id;
uint128_t price;
uint64_t expiration;
account_name owner;
auto primary_key() const { return id; }
uint64_t get_expiration() const { return expiration; }
uint128_t get_price() const { return price; }
EOSLIB_SERIALIZE( limit_order, ( id )( price )( expiration )( owner ) )
};
Creating the multi index table##
auto payer = ilm.get_account();
...
payer
is the variable that holds the account who will be "billed" for adding elements to the multi index table and modifying elements already in the multi index table.
...
eosio::multi_index< N( orders ), limit_order,
...
N( orders )
is the name of the multi index table and limit_orders
is the data to be stored in the table.
...
indexed_by< N( byexp ), const_mem_fun< limit_order, uint64_t,
&limit_order::get_expiration> >,
...
indexed_by< N( byexp ), const_mem_fun< limit_order, uint64_t, &limit_order::get_expiration> >
is the definition of a way the orders
multi index table can be indexed. N( byexp )
is the name of this index. The const_mem_fun
indicates the data type being retrieved, limit_order
, the type of variable being sorted by, uint64_t
, and the function that will be used get the variable, get_expiration
.
...
indexed_by< N( byprice ), const_mem_fun< limit_order, uint128_t, &limit_order::get_price> >
...
indexed_by< N( byprice ), const_mem_fun< limit_order, uint128_t, &limit_order::get_price> >
is the definition of a way the orders
multi index table can be indexed. N( byprice )
is the name of this index. The const_mem_fun
indicates the data type being retrieved, limit_order
, the type of variable being sorted by, uint128_t
, and the function that will be used get the variable, get_price
.
orders( N( limitorders ), N( limitorders )
orders
is the multi index table.
auto payer = ilm.get_account();
print("Creating multi index table 'orders'.\n");
eosio::multi_index< N( orders ), limit_order,
indexed_by< N( byexp ), const_mem_fun< limit_order, uint64_t, &limit_order::get_expiration> >,
indexed_by< N( byprice ), const_mem_fun< limit_order, uint128_t, &limit_order::get_price> >
> orders( N( limitorders ), N( limitorders ) );
Adding to the multi index table##
Below, two limit_order
s are added to the orders
table. Note that payer
is the account that is being "billed" for the modification to the orders
table.
orders.emplace( payer, [&]( auto& o ) {
o.id = 1;
o.expiration = 300;
o.owner = N(dan);
});
auto order2 = orders.emplace( payer, [&]( auto& o ) {
o.id = 2;
o.expiration = 200;
o.owner = N(thomas);
});
Sorted by primary key##
By default, the orders
table is sorted by primary key.
print("Items sorted by primary key:\n");
for( const auto& item : orders ) {
print(" ID=", item.id, ", expiration=", item.expiration, ", owner=", name{item.owner}, "\n");
}
Sorted by secondary index - expiration##
The orders
table gets sorted by expiration and assigned to expidx
.
auto expidx = orders.get_index<N(byexp)>();
print("Items sorted by expiration:\n");
for( const auto& item : expidx ) {
print(" ID=", item.id, ", expiration=", item.expiration, ", owner=", name{item.owner}, "\n");
}
Sorted by secondary index - price##
The orders
table gets sorted by price and assigned to pridx
.
auto pridx = orders.get_index<N(byprice)>();
print("Items sorted by price:\n");
for( const auto& item : pridx ) {
print(" ID=", item.id, ", expiration=", item.expiration, ", owner=", name{item.owner}, "\n");
}
Modify an entry##
Below, the entry with "ID=2" gets modified. Note that payer
is the account that is being "billed" for the modification to the orders
table.
print("Modifying expiration of order with ID=2 to 400.\n");
orders.modify( order2, payer, [&]( auto& o ) {
o.expiration = 400;
});
Getting the lower bound##
auto lower = expidx.lower_bound(100);
print("First order with an expiration of at least 100 has ID=", lower->id, " and expiration=", lower->get_expiration(), "\n");
Complete .cpp file
#include <eosiolib/eosio.hpp>
#include <eosiolib/dispatcher.hpp>
#include <eosiolib/multi_index.hpp>
using namespace eosio;
namespace limit_order_table {
struct limit_order {
uint64_t id;
uint128_t price;
uint64_t expiration;
account_name owner;
auto primary_key() const { return id; }
uint64_t get_expiration() const { return expiration; }
uint128_t get_price() const { return price; }
EOSLIB_SERIALIZE( limit_order, ( id )( price )( expiration )( owner ) )
};
class limit_order_table {
public:
ACTION( N( limitorders ), issue_limit_order ) {
EOSLIB_SERIALIZE( issue_limit_order )
};
static void on( const issue_limit_order& ilm ) {
auto payer = ilm.get_account();
print("Creating multi index table 'orders'.\n");
eosio::multi_index< N( orders ), limit_order,
indexed_by< N( byexp ), const_mem_fun< limit_order, uint64_t, &limit_order::get_expiration> >,
indexed_by< N( byprice ), const_mem_fun< limit_order, uint128_t, &limit_order::get_price> >
> orders( N( limitorders ), N( limitorders ) );
orders.emplace( payer, [&]( auto& o ) {
o.id = 1;
o.expiration = 300;
o.owner = N(dan);
});
auto order2 = orders.emplace( payer, [&]( auto& o ) {
o.id = 2;
o.expiration = 200;
o.owner = N(thomas);
});
print("Items sorted by primary key:\n");
for( const auto& item : orders ) {
print(" ID=", item.id, ", expiration=", item.expiration, ", owner=", name{item.owner}, "\n");
}
auto expidx = orders.get_index<N(byexp)>();
print("Items sorted by expiration:\n");
for( const auto& item : expidx ) {
print(" ID=", item.id, ", expiration=", item.expiration, ", owner=", name{item.owner}, "\n");
}
auto pridx = orders.get_index<N(byprice)>();
print("Items sorted by price:\n");
for( const auto& item : pridx ) {
print(" ID=", item.id, ", expiration=", item.expiration, ", owner=", name{item.owner}, "\n");
}
print("Modifying expiration of order with ID=2 to 400.\n");
orders.modify( order2, payer, [&]( auto& o ) {
o.expiration = 400;
});
auto lower = expidx.lower_bound(100);
print("First order with an expiration of at least 100 has ID=", lower->id, " and expiration=", lower->get_expiration(), "\n");
};
} /// limit_order_table
namespace limit_order_table {
extern "C" {
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t code, uint64_t action ) {
require_auth( code );
eosio_assert( eosio::dispatch< limit_order_table, limit_order_table::issue_limit_order >( code, action ), "Could not dispatch" );
}
}
}
Deleting a Table
Tables cannot be directly deleted, however, a table will delete itself automatically after all rows have been deleted.
Updated about 7 years ago