-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Persistence API
A Multi-Index container abstraction of persistent data on EOSIO blockchains
- Overview
- The EOSIO Multi-Index API
- Putting It All Together
- Vehicle Maintenance Tracker Example
- C++ API Reference
EOSIO provides a set of services and interfaces that enable contract developers to persist state across action, and consequently transaction, boundaries. Without persistence, state that is generated during the processing of actions and transactions will be lost when processing goes out of scope. The persistence components include:
- Services to persist state in a database
- Enhanced query capabilities to find and retrieve database content
- C++ APIs to these services, intended for use by contract developers
- C APIs for access to core services, of interest to library and system developers
This document covers the first three topics.
Actions perform the work of EOSIO contracts. Actions operate within an environment known as the action context. As illustrated in the diagram below, an action context provides several things necessary for the execution of the action. One of those things is the action's working memory. This is where the action maintains its working state. Before processing an action, EOSIO sets up a clean working memory for the action. Variables that might have been set when another action executed are not available within the new action's context. The only way to pass state among actions is to persist it to and retrieve it from the EOSIO database.
The EOSIO Multi-Index API provides a C++ interface to the EOSIO database. The EOSIO Multi-Index API a is patterned after
Boost Multi-Index Containers. This API provides a
model for object storage with rich retrieval capabilities, enabling the use of multiple indices with different sorting
and access semantics. The Multi-Index API is provided by the eosio::multi_index
C++ class found in the contracts/eosiolib
folder of the EOSIO/eos
GitHub repository.
This class enables a contract written in C++ to read and modify persistent state in the EOSIO database.
The Multi-Index container interface eosio::multi_index
provides a homogeneous container of an arbitrary
C++ type (and it does not need to be a plain-old data type or be fixed-size) that is kept sorted in multiple indices by
keys of various types that are derived from the objects. It can be compared to a traditional database table with rows,
columns, and indices. It can also be easily compared to Boost Multi-index Containers.
In fact many of the member function signatures of eosio::multi_index
are modeled after boost::multi_index
, although
there are important differences.
eosio::multi_index
can be conceptually viewed as tables in a conventional database in which the rows are the
individual objects in the container, the columns are the member properties of the objects in the container,
and the indices provide fast lookup of an object by a key compatible with an object member property.
Traditional database tables allow the index to be a user-defined function over some number of columns of the table.
eosio::multi_index
similarly allows the index to be any user-defined function (provided as a member function of
the class
/struct
of the element type) but with its return value restricted to one of a limited set of supported key
types.
Traditional database tables typically have a single unique primary key that allows
unambiguously identifying a particular row in the table and also provides the standard sort order for the rows in the
table. eosio::multi_index
supports a similar semantic, but the primary key of the object in the eosio::multi_index
container must be a unique unsigned 64-bit integer. The objects in the eosio::multi_index
container are sorted by the
primary key index in ascending order of the unsigned 64-bit integer primary key.
A key differentiator of the EOSIO persistence services over other blockchain infrastructures is its Multi-Index iterators. Unlike some other blockchains that only provide a key-value store, EOSIO Multi-Index tables allow a contract developer to keep a collection of objects sorted by a variety of different key types, which could be derived from the data within the object. This enables rich retrieval capabilities. Up to 16 secondary indices can be defined, each having its own way of ordering and retrieving table contents.
The EOSIO Multi-Index iterators follow a pattern that is common to C++ iterators. All iterators are bi-directional
const
, either const_iterator
or const_reverse_iterator
. The iterators can be dereferenced to provide access to an
object in the Multi-Index table.
Here is a summary of the steps to create your own persistent data using EOSIO Multi-Index tables.
- Define your object(s) using C++
class
orstruct
. Each object will be in its own Multi-Index table. - Define a
const
member function in theclass
/struct
calledprimary_key
that returns theuint64_t
primary key value of your object. - Determine the secondary indices. Up to 16 additional indices are supported. A secondary index
supports several key types, listed below.
-
idx64
- Primitive 64-bit unsigned integer key -
idx128
- Primitive 128-bit unsigned integer key -
idx256
- 256-bit fixed-size lexicographical key -
idx_double
- Double precision floating point key -
idx_long_double
- Quadruple precision floating point key
-
- Define a key extractor for each secondary index. The key extractor is a function used to obtain the keys from the elements of the Multi-Index table. See Multi-Index Constructor and indexed_by sections below.
- Instantiate your Multi-Index table.
- Insert (
emplace
) into, and subsequentlymodify
orerase
objects in your table as required by your contract. - Locate and traverse objects in your table using
get
,find
and iterator operations.
In the following example, we will look at how to use the EOSIO Multi-Index API to implement a simple vehicle maintenance tracker. The tracker will keep a ledger of vehicle maintenance activities.
The target users of the tracker are service mechanics and their customers. A service mechanic will add records to the ledger as service jobs are done. They can use this information to track service history and notify customers when service is due. Customers can also track their service history. They can also periodically update their vehicle mileage to enable their mechanic to better determine when service is needed.
If we were implementing the full contract for this example, we might have actions such as:
- Create a new service record, which can only be done by the mechanic
- Update mileage, which can be done by the mechanic for any vehicle or a customer for its vehicle
- Various types of reporting actions
For the purposes of this example, we will focus on the aspects of storage and retrieval, and not the contract actions.
We actually need two tables for our application. The first table will contain individual service transactions created by the mechanic. The same customer can have many records in this table, representing each time the vehicle was serviced. Our second table will contain the current state for a customer. Each customer will have one entry in this table. Note that for simplicity, our design here limits one vehicle per customer.
We'll call the table that contains individual service transactions the service
table. This table
will be used to create service record reports. The records of this table will contain the following properties:
- Primary key - the Customer ID can't be the primary key, since a customer can have many records. In fact, we don't need the primary key directly, so we can let the system generate one for us.
- Customer ID - this will correspond to the account name (a uint64_t value) of the customer
- Date of Service - the date when the service was performed
- Odometer - the vehicle's odometer reading at date of service
We want to be able to search this table by customer,
so we will create a secondary index on the customer property. The diagram below illustrates the service
table and
its secondary index, bycustomer
.
We will declare a struct service_rec
with these properties to represent our service record object:
struct service_rec {
uint64_t pkey; // opaque, will use available_primary_key()
account_name customer; // will create a secondary index on this
uint32_t service_date;
uint32_t odometer;
auto primary_key()const { return pkey; }
account_name get_customer()const { return customer; }
EOSLIB_SERIALIZE( service_rec, (pkey)(customer)(service_date)(odometer) )
};
To instantiate our service
table (we'll call our instance service_table
), we write the following in our contract,
where mechanic
is the account name for the mechanic.
using service_table_type = multi_index<service, service_rec,
indexed_by< N(bycustomer), const_mem_fun<service_rec, account_name, &service_rec::get_customer> >
>;
service_table_type service_table( current_receiver(), mechanic );
The two parameters passed to the constructor establish access privileges to the table. The first parameter (the
code
parameter, see below) determines whether the action is accessing the contract's
own persistent state (i.e., code == current_receiver())
, in which case the action context has both
read and write access to the table, or if it is accessing some other contract's persistent state and is,
therefore, read-only.
To add records to service_table
, we can use C++ similar to the following (assuming corresponding local variables for
the service record content). Variable customer_name
contains the human-readable string name of the customer,
which we must convert to the account_name
encoding of the customer stored in the table.
service_table.emplace(mechanic, [&]( auto& s_rec ) {
s_rec.pkey = service_table.available_primary_key();
s_rec.customer = eosio::chain::string_to_name(customer_name);
s_rec.service_date = service_date;
s_rec.odometer = odometer;
});
To find all service records for a customer, we first get the bycustomer
secondary index,
auto customer_index = service_table.template get_index<N(bycustomer)>();
then we can find
the desired customer using the secondary index.
account_name customer_acct = eosio::chain::string_to_name(customer_name);
auto cust_itr = customer_index.find(customer_acct);
We can iterate through the secondary index to get all service
records for the customer.
while (cust_itr != service_table.end() && cust_itr->customer == customer_acct) {
// code to process customer record...
...
cust_itr++;
}
Our second table will contain the current state for a customer. We'll call this the customer
table. This state consists
of the following properties:
- Customer ID - this will be unique for the
customer
table, so we can use it as our primary key (note that for simplicity, this example limits to one vehicle per customer); - Last Service Date - the last time the vehicle was in for routine service
- Odometer at Last Service Date - the odometer reading when the vehicle was last in for service
- Miles Since Last Service - this will be calculated each time the customer or mechanic updates the latest odometer value (e.g., voluntarily by the customer, and each time the mechanic performs a service)
We will index the customer
table on the Last Service Date and on the Miles Since Last Service. The diagram below
illustrates the customer
table and its two secondary indices, bydate
and bymiles
. Note in the example that Sue has
volunteered her latest odometer reading, presumably using an interface provided by the application. The corresponding Miles
Since Last Service is calculated whenever the customer enters miles, and this value is indexed. This enables the mechanic
to identify customers needing service by date or by miles, at least for customers who choose to participate. Examples
of using these values are given below.
We will declare a struct customer_rec
with these properties to represent our customer record object:
struct customer_rec {
account_name customer_id // primary key
uint64_t last_service_date; // will create a secondary index on this
unit32_t odometer_at_last_service;
uint32_t latest_odometer;
auto primary_key()const { return customer_id; }
uint64_t get_last_service_date()const { return last_service_date; }
uint64_t get_miles_since_service()const {
return latest_odometer > odometer_at-last_service ? latest_odometer - odometer_at_last_service : 0;
}
EOSLIB_SERIALIZE( customer_rec, (customer_id)(last_service_date)(odometer_at_last_service)(latest_odometer) )
};
To instantiate our customer
table (we'll call it customer_table
), we write the following in our contract,
where mechanic
is the account name for the mechanic.
using customer_table_type = multi_index<customer, customer_rec,
indexed_by< N(bydate), const_mem_fun<customer_rec, uint64_t, &customer_rec::get_last_service_date> >,
indexed_by< N(bymiles), const_mem_fun<customer_rec, uint64_t, &customer_rec::get_miles_since_service> >
>;
customer_table_type customer_table( current_receiver(), mechanic );
To add records to customer_table
, we can use C++ similar to the following (assuming corresponding local variables for
the customer record content). Variable customer_name
contains the human-readable string name of the customer, which
we must convert to the account_name
encoding of the customer stored in the table.
customer_table.emplace(mechanic, [&]( auto& c_rec ) {
c_rec.customer_id = eosio::chain::string_to_name(customer_name);
c_rec.last_service_date = current_date;
c_rec.latest_odometer = current_odometer;
c_rec.miles_since_service = 0;
});
We can find
a customer using the primary key, customer_id
.
account_name customer_id = eosio::chain::string_to_name(customer_name);
auto cust_itr = customer_table.find(customer_id);
To update the latest_odometer
property, use something similar to the following.
account_name customer_id = eosio::chain::string_to_name(customer_name);
customer_table.modify(customer_table.get(customer_id), mechanic, [&]( auto& c_rec) {
c_rec.latest_odometer = customer_provided_odometer_reading; // customer provided input
c_rec.miles_since_service = customer_odometer_at_last_service; // obtained from the service_table
});
Parameter mechanic
is the payer for the update action. Our example allows the mechanic or
customer to update the latest_odometer
property, but we don't want the customer paying just to
volunteer their latest odometer reading.
Note that the above requires calculating the miles_since_service
property. The example assumes the
variable customer_odometer_at_last_service
holds the odometer reading from the customer's last service.
We can obtain the most recent service record for the customer by using the bycustomer
secondary
index of the service
table. See the service
table example above for using this index.
To get the secondary indices for customer_table
, use something similar to the following.
auto last_service_date_index = customer_table.template get_index<N(bydate)>();
auto miles_since_service_index = customer_table.template get_index<N(bymiles)>();
We can iterate backwards through the bydate
secondary index to get all customers who are due for service, e.g., because their
last service is more than 3 months ago.
auto overdue_date_itr = last_service_date_index.upper_bound(three_months_ago); // date for three months earlier than today
// code to iterate the customer table backwards from three months ago
...
We can iterate forward through the bymiles
secondary index to get all customers who are due for service, e.g.,
because their miles since last service is greater than 3000.
auto over_miles_itr = last_service_date_index.lower_bound(3000); // all records 3000 or more miles
// code to iterate the customer table forward for greater than 3000 miles
...
This section documents the eosio::multi_index
C++ API. This interface is, effectively, an adaptation of the
Boost Multi-Index container library. It makes direct use of the boost/multi_index/const_mem_fun
class template for key
extraction. It also uses the Boost Hana library for metaprogramming. Please refer to the Boost documentation
at www.boost.org for additional conceptual information and detail.
In the descriptions below, the following aliases will be used for common template declarations.
Alias | Description |
---|---|
object_type | The type of an object in the Multi-Index table |
secondary_index | The type of the appropriate Secondary Index of the Multi-Index table |
Method | Description |
---|---|
multi_index( uint64_t code, uint64_t scope ) |
Constructs an instance of a Multi-Index table |
Parameters | |
code |
account that owns table |
scope |
scope identifier within the code hierarchy |
Postcondition | A new empty instance of a Multi-Index table is created |
code and scope member properties are initialized |
|
each secondary index table initialized |
Note: The eosio::multi_index
template has template parameters <uint64_t TableName, typename T, typename... Indices>
, where:
-
TableName
is the name of the table, maximum 12 characters long, characters in the name from the set of lowercase letters, digits 1 to 5, and the "." (period) character; -
T
is the object type (i.e., row definition); -
Indices
is a list of up to 16 secondary indices.- Each must be a default constructable class or struct
- Each must have a function call operator that takes a const reference to the table object type and returns either a secondary key type or a reference to a secondary key type
- It is recommended to use the eosio::const_mem_fun template, which is a type alias to the boost::multi_index::const_mem_fun. See the documentation for the Boost const_mem_fun key extractor for more details.
Copy constructors and assignment operators are not supported.
Method | Description |
---|---|
const_iterator emplace( unit64_t payer, Lambda&& constructor ) |
Adds a new object (i.e., row) to the table. |
Parameters | |
payer |
account name of the payer for the Storage usage of the new object |
constructor |
lambda function that does an in-place initialization of the object to be created in the table |
Returns | a primary key Iterator to the newly created object |
Precondition | |
payer is a valid account that authorized the current action (and thus allowed to be billed for storage usage) |
|
Postcondition | |
A new object is created in the Multi-Index table, with a unique primary key (as specified in the object). The object is serialized and written to the table. If the table does not exist, it is created. | |
Secondary indices are updated to refer to the newly added object. If the secondary index tables do not exist, they are created. | |
The payer is charged for the storage usage of the new object and, if the table (and secondary index tables) must be created, for the overhead of the table creation. | |
Exceptions | The current receiver is not the account that owns the table (the code of multi_index ). |
Method | Description |
---|---|
const object_type& get( uint64_t primary )const |
Retrieves an existing object from a table using its primary key. |
Parameters | |
primary |
primary key value of the object |
Returns | A constant reference to the object containing the specified primary key. |
Precondition | None |
Postcondition | None |
Exceptions | No object matches the given key |
Method | Description |
---|---|
const_iterator find( uint64_t primary )const |
Search for an existing object in a table using its primary key. |
Parameters | |
primary |
primary key value of the object |
Returns | |
An iterator to the found object which has a primary key equal to primary , OR
|
|
The end iterator of the referenced table if an object with primary key primary is not found |
|
Precondition | None |
Postcondition | None |
Exceptions | None |
Method | Description |
---|---|
void modify( const_iterator itr, uint64_t payer, Lambda&& updater ) |
Modifies an existing object in a table. |
void modify( const object_type &obj, uint64_t payer, Lambda&& updater ) |
|
Parameters | |
itr |
an iterator pointing to the object to be updated |
obj |
a reference to the object to be updated |
payer |
account name of the payer for the Storage usage of the updated row; a value of 0 indicates that the payer of the modified row is the same as the existing payer. |
updater |
lambda function that updates the target object |
Precondition | |
itr points to, or obj is an existing object in the table. |
|
payer is a valid account that authorized the current action (and thus allowed to be billed for storage usage) |
|
Postcondition | |
The modified object is serialized, then replaces the existing object in the table. | |
Secondary indices are updated; the primary key of the updated object is not changed. | |
The payer is charged for the storage usage of the updated object. |
|
If payer is the same as the existing payer, payer only pays for the usage difference between existing and updated object (and is refunded if this difference is negative). |
|
If payer is different from the existing payer, the existing payer is refunded for the storage usage of the existing object. |
|
Exceptions | |
If called with an invalid precondition, execution is aborted. | |
The current receiver is not the account that owns the table (the code of multi_index ). |
Method | Description |
---|---|
const_iterator erase( const_iterator itr ) |
Remove an existing object from a table using its primary key. |
void erase( const object_type& obj ) |
|
Parameters | |
itr |
an iterator pointing to the object to be removed |
obj |
a reference to the object to be removed |
Returns | For the signature with const_iterator , returns a pointer to the object following the removed object. |
Precondition | None |
Postcondition | |
The object is removed from the table and all associated storage is reclaimed. | |
Secondary indices associated with the table are updated. | |
The existing payer for storage usage of the object is refunded for the table and secondary indices usage of the removed object, and if the table and indices are removed, for the associated overhead. | |
Exceptions | |
The object to be removed is not in the table. | |
The action is not authorized to modify the table. | |
The given iterator is invalid. |
Method | Description |
---|---|
uint64_t get_code() const |
Returns the code member property. |
Returns | account name of the Code that owns the Primary Table |
Method | Description |
---|---|
uint64_t get_scope() const |
Returns the scope member property. |
Returns | scope id of the Scope within the Code of the Current Receiver under which the desired Primary Table instance can be found |
Method | Description |
---|---|
uint64_t available_primary_key()const |
Returns an available (unused) primary key value, intended to be used in tables in which the primary keys of the table are strictly intended to be auto-incrementing, and thus will never be set to custom values by the contract. Violating this expectation could result in the table appearing to be full due to inability to allocate an available primary key. |
The Multi-Index iterators follow a pattern that is common to C++ iterators. All iterators are bi-directional
const
, either const_iterator
or const_reverse_iterator
. The iterators can be dereferenced to provide access to an
object in the Multi-Index table.
Method | Description |
---|---|
const_iterator begin()const |
Returns an iterator pointing to the object_type with the lowest primary key value in the Multi-Index table. |
const_iterator cbegin()const |
Method | Description |
---|---|
const_iterator end()const |
Returns an iterator pointing to the virtual row representing just past the last row of the table (assuming one exists); cannot be dereferenced; can be advanced backward but not forward. |
const_iterator cend()const |
Method | Description |
---|---|
const_iterator rbegin()const |
Returns a reverse iterator pointing to the object_type with the highest primary key value in the Multi-Index table. |
const_iterator crbegin()const |
Method | Description |
---|---|
const_iterator rend()const |
Returns an iterator pointing to the virtual row representing just past the last row of the table (assuming one exists); cannot be dereferenced; can be advanced forward but not backward. |
const_iterator crend()const |
Method | Description |
---|---|
const_iterator lower_bound( uint64_t primary )const |
Searches for the object_type with the lowest primary key that is greater than or equal to a given primary key. |
Parameters | |
primary |
Primary key that establishes the target value for the lower bound search |
Returns | |
an iterator pointing to the object_type that has the lowest primary key that is greater than or equal to primary , OR
|
|
the end iterator if an object could not be found, including if the table does not exist |
Method | Description |
---|---|
const_iterator upper_bound( uint64_t primary )const |
Searches for the object_type with the lowest primary key that is greater than a given primary key. |
Parameters | |
primary |
Primary key that establishes the target value for the upper bound search |
Returns | |
an iterator pointing to the object_type that has the lowest primary key that is greater than primary , OR
|
|
the end iterator if an object could not be found, including if the table does not exist |
Method | Description |
---|---|
secondary_index get_index<IndexName>() |
Returns an appropriately typed Secondary Index. |
secondary_index get_index<IndexName>() const |
|
Parameters | |
IndexName |
the ID of the desired secondary index |
Returns | An index of the appropriate type, i.e., one of the following: |
idx64 |
Primitive 64-bit unsigned integer key |
idx128 |
Primitive 128-bit unsigned integer key |
idx256 |
256-bit fixed-size lexicographical key |
idx_double |
Double precision floating point key |
idx_long_double |
Quadruple precision floating point key |
Method | Description |
---|---|
const_iterator iterator_to( const object_type& obj )const |
Returns an iterator to the given object in a Multi-Index table. |
Parameters | |
obj |
a reference to the desired object |
Returns | An iterator to the given object |
The indexed_by
struct is used to instantiate the indices for the Multi-Index table. In EOSIO, up to 16 secondary indices
can be specified.
template<uint64_t IndexName, typename Extractor>
struct indexed_by {
enum constants { index_name = IndexName };
typedef Extractor secondary_extractor_type;
};
Parameters
-
IndexName
is the name of the index. The name must be provided as an EOSIO base32 encoded 64-bit integer and must conform to the EOSIO naming requirements of a maximum of 13 characters, the first twelve from the lowercase characters a-z, digits 0-5, and ".", and if there is a 13th character, it is restricted to lowercase characters a-p and ".". -
Extractor
is a function call operator that takes a const reference to the table object type and returns either a secondary key type or a reference to a secondary key type. It is recommended to use theeosio::const_mem_fun
template, which is a type alias to theboost::multi_index::const_mem_fun
. See the documentation for the Boostconst_mem_fun
key extractor for more details.
Example
multi_index<mytable, record,
indexed_by< N(bysecondary), const_mem_fun<record, uint128_t, &record::get_secondary> >
> table( code, scope);
In this example, the Multi-Index table is named mytable
, has object (row) type record
, is indexed by a secondary index
named bysecondary
, whose name is converted to the required encoded format using
the N
macro. A const_mem_fun
key extractor is specified for the record
object class; the key type is uint128_t
,
obtained using the record::get_secondary
function.
An EOSIO Multi-Index table can have up to 16 secondary indices. An index
can be retrieved from the multi_index
object using the get_index
method, and can then be iterated using a common
C++ iterator pattern.
The index
API described here operates in many ways the same as the multi_index
described above, but it also
differs in some significant ways.
- An
index
is intended to provide alternate means to access the Multi-Index Table. - The content of a secondary index table is basically a key mapping to a primary key. That mapping is transparent to the user.
- Some operations do not apply to secondary indices, most notably, one does not
emplace
content using a secondary index. Objects can be modified and erased using a secondary index. - Operations for retrieving primary content using a secondary table are virtually the same, differing primarily in the
key values that are used (you cannot pass an object to a secondary index to find it in the table). The key values will
be one of the supported secondary index types:
-
idx64
- Primitive 64-bit unsigned integer key -
idx128
- Primitive 128-bit unsigned integer key -
idx256
- 256-bit fixed-size lexicographical key (does not support arithmetic operations) -
idx_double
- Double precision floating point key -
idx_long_double
- Long Double (quadruple) precision floating point key
-
- Secondary indices have
code
andscope
member properties, the same as the corresponding properties on the Multi-Index table.
Alias | Description |
---|---|
object_type | The typename of an object in the Multi-Index table |
secondary_index | An appropriately typed reference to a Secondary Index |
A secondary index is created as part of the construction of the Multi-Index table. Direct construction of index
is
not supported.
Copy constructors and assignment operators are not supported.
Method | Description |
---|---|
const object_type& get( secondary_key_type&& secondary )const |
Retrieves an existing object from a table using its secondary key. Multiple signatures are available. |
const object_type& get( const secondary_key_type& secondary )const |
|
Parameters | |
secondary |
secondary key value of the object |
Returns | A constant reference to the object containing the specified secondary key. |
Precondition | None |
Postcondition | None |
Exceptions | No object matches the given key |
Method | Description |
---|---|
const_iterator find( secondary_key_type&& secondary )const |
Search for an existing object in a table using a secondary key. |
const_iterator find( const secondary_key_type&& secondary )const |
|
Parameters | |
secondary |
secondary key value of the object |
Returns | |
An iterator to the found object which has a secondary key equal to secondary , OR
|
|
The end iterator if an object with secondary key secondary is not found |
|
Precondition | None |
Postcondition | None |
Exceptions | None |
Method | Description |
---|---|
void modify( const_iterator itr, uint64_t payer, Lambda&& updater ) |
Modifies an existing object in a table. |
Parameters | |
itr |
an iterator pointing to the object to be updated |
payer |
account name of the payer for the Storage usage of the updated row; a value of 0 indicates that the payer of the modified row is the same as the existing payer. |
updater |
lambda function that updates the target object |
Precondition | |
itr points to an existing object in the table. |
|
payer is a valid account that authorized the current action (and thus allowed to be billed for storage usage) |
|
Postcondition | |
The modified object is serialized, then replaces the existing object in the table. | |
Secondary indices are updated; the primary key of the updated object is not changed. | |
The payer is charged for the storage usage of the updated object. |
|
If payer is the same as the existing payer, payer only pays for the usage difference between existing and updated object (and is refunded if this difference is negative). |
|
If payer is different from the existing payer, the existing payer is refunded for the storage usage of the existing object. |
|
Exceptions | |
If called with an invalid precondition, execution is aborted. | |
The current receiver is not the account that owns the table (the code of multi_index ). |
Method | Description |
---|---|
const_iterator erase( const_iterator itr ) |
Remove an existing object from a table using its secondary key. |
Parameters | |
itr |
an iterator pointing to the object to be removed |
Returns | For the signature with const_iterator , returns a pointer to the object following the removed object. |
Precondition | None |
Postcondition | |
The object is removed from the table and all associated storage is reclaimed. | |
Secondary indices associated with the table are updated. | |
The existing payer for storage usage of the object is refunded for the table and secondary indices usage of the removed object, and if the table and indices are removed, for the associated overhead. | |
Exceptions | |
The object to be removed is not in the table. | |
The action is not authorized to modify the table. | |
The given iterator is invalid. |
Method | Description |
---|---|
uint64_t get_code() const |
Returns the code member property. |
Returns | account name of the Code that owns the Secondary Index Table |
Method | Description |
---|---|
uint64_t get_scope() const |
Returns the scope member property. |
Returns | scope id of the Scope within the Code of the Current Receiver under which the desired Secondary Index Table instance can be found |
Method | Description |
---|---|
constexpr static uint64_t name() |
Returns the index_table_name member constant. |
Returns | the table name of the Secondary Index |
Method | Description |
---|---|
constexpr static uint64_t number() |
Returns the index_number member constant. |
Returns | the number of the Secondary Index |
The EOSIO secondary index iterators follow a pattern that is common to C++ iterators.
Method | Description |
---|---|
struct const_iterator : public std::iterator<std::bidirectional_iterator_tag, const object_type> |
A bi-directional iterator to objects in a Multi-Index table. |
Parameters | |
object_type |
the typename of the object in the table |
Method | Description |
---|---|
typedef std::reverse_iterator<const_iterator> const_reverse_iterator |
A reverse bi-directional iterator to objects in a Multi-Index table. |
Method | Description |
---|---|
const_iterator begin()const |
Returns an iterator pointing to the lowest secondary key value in the secondary index table. |
const_iterator cbegin()const |
Method | Description |
---|---|
const_iterator end()const |
Returns an iterator pointing to the virtual row representing just past the last row of the table (assuming one exists); cannot be dereferenced; can be advanced backward but not forward. |
const_iterator cend()const |
Method | Description |
---|---|
const_iterator rbegin()const |
Returns a reverse iterator pointing to the highest secondary key value in the secondary index table. |
const_iterator crbegin()const |
Method | Description |
---|---|
const_iterator rend()const |
Returns a reverse iterator pointing to the virtual row representing just before the first row of the table (assuming one exists); cannot be dereferenced; can be advanced forward but not backward. |
const_iterator crend()const |
Method | Description |
---|---|
const_iterator lower_bound( secondary_key_type&& secondary )const |
Searches for the object_type with the lowest secondary key that is greater than or equal to a given secondary key. |
const_iterator lower_bound( const secondary_key_type&& secondary )const |
|
Parameters | |
secondary |
Secondary key that establishes the target value for the lower bound search |
Returns | |
an iterator pointing to the object in the secondary index that has the lowest secondary key that is greater than or equal to secondary , OR
|
|
the end iterator if an object could not be found, including if the table does not exist |
Method | Description |
---|---|
const_iterator upper_bound( secondary_key_type&& secondary )const |
Searches for the object_type with the lowest secondary key that is greater than a given secondary key. |
const_iterator upper_bound( const secondary_key_type&& secondary )const |
|
Parameters | |
secondary |
Secondary key that establishes the target value for the upper bound search |
Returns | |
an iterator pointing to the object in the secondary index that has the lowest secondary key that is greater than secondary , OR
|
|
the end iterator if an object could not be found, including if the table does not exist |
Method | Description |
---|---|
const_iterator iterator_to( const object_type& obj )const |
Returns a secondary index iterator to the given object in the Multi-Index table. |
Parameters | |
obj |
a const reference to the desired object |
Returns | An iterator to the given object |
Method | Description |
---|---|
static auto extract_secondary_key(const object_type& obj) |
Returns the secondary key value for an object from a secondary index. |
Parameters | |
obj |
a const reference to the desired object |
Returns | A key value for the given object, for that index |