Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Commit

Permalink
Merge pull request #1010 from EOSIO/docs/kv_map
Browse files Browse the repository at this point in the history
[docs] add kv::map documentation
  • Loading branch information
ovi authored Dec 10, 2020
2 parents c928b65 + ab88322 commit 6012476
Show file tree
Hide file tree
Showing 21 changed files with 822 additions and 118 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ link_text: How To Perform Authorization Checks

The following conditions are assumed:

1. You have the sources of a contract with one of the actions defined, let's call it `hi` action.
1. You have the sources of a contract with `hi` action defined.
2. The `hi` action has defined one input parameter `user` of type `name`.
3. The `hi` action prints the name of the `user` account.
4. The `hi` action needs to authorize the `user` account.
Expand Down
44 changes: 6 additions & 38 deletions docs/06_how-to-guides/30_key-value-api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ link_text: "Key-Value API"

## Overview

The Key-Value API provides a set of C++ classes and structures which facilitates the creation of datastore key value tables on-chain. It is meant to provide the same functionality the multi-index provides in a `simpler` and more `flexible` API with comparable performance.
The Key-Value API provides a set of C++ classes and structures which facilitates the creation of datastore key value tables and maps on-chain. It is meant to provide the same functionality the multi-index provides in a `simpler` and more `flexible` API with comparable performance.

[[caution | Alpha version]]
| `Key-Value Table` is designated as `alpha` and should not be used in production code.
Expand All @@ -18,42 +18,10 @@ On top of flexibility, this new API has a simpler interface and it helps the dev

### Related Terminology and Concepts

A `datastore key value table on-chain`, or a `KV Table`, serves as a storage location which is organized as a table of rows where each row stores objects with the same definition.
The KV API provides two types of storage:

The `object definition` consists of a list of `properties` and each property is stored on the corresponding row in the table. The properties of the objects are also referred to as `fields`.
* [Key-Value Map](./kv_map/index.md), or shorter `KV Map`
* [Key-Value Table](./kv_table/index.md), or shorter `KV Table`

A `KV Table` requires one unique index, of any type, that can be serialized to a binary representation.

A `KV Table` supports zero or more secondary indexes, of any type, that can be serialized to a binary representation. Indexes must be a data member or a function member.

Two types of indexes can be defined, unique or non-unique.

A unique index can be defined just for one property, and it will sort the objects stored in the `KV Table` based on the `specified property`. The unique index also ensures only one instance of an object is stored with a particular value for the `specified property`, and thus ensures the uniqueness of the property for which it is defined.

A non-unique index can be defined for one or multiple properties, and it will sort the objects stored in the `KV Table` based on the `specified property` or the combination of the `specified properties`. Very important though, a non-unique index requires as the first property of its definition a property which has unique values. Therefore although the non-unique index is intended for just one property, its definition will have two properties specified:

1. the first property which must have unique values
2. and the second property, the one for which the non-unique index is built

The main operations provided by the KV API are the following:

* Create an instance of `KV Table`
* Insert object in the `KV Table` instance
* Update object in the `KV Table` instance
* Delete object from the `KV Table` instance
* Search an object in the `KV Table` instance
* Verify if an object exists in the `KV Table` instance
* Retrieve a range of objects from the `KV Table` instance
* Iterate through the objects store in the `KV Table` instance

Consult the [KV API Reference](../../group__keyvalue) the `KV API How-To`s listed below for details.

* [How To Use KV Table](./10_how-to-use-kv-table.md)
* [How To Create Indexes](./20_how-to-create-indexes.md)
* [How To Upsert Into Table](./30_how-to-upsert-into-table.md)
* [How To Delete From Table](./40_how-to-delete-from-table.md)
* [How To Iterate](./50_how-to-iterate.md)
* [How To Check A Record](./60_how-to-check-a-record.md)
* [How To Find In Table](./70_how-to-find-in-table.md)
* [How To Query Range In Table](./80_how-to-query-range-in-table.md)
* [How To Allow Users To Pay](./90_how-to-allow-users-to-pay.md)
[[caution | Alpha version]]
| `Key-Value Table` is designated as `alpha` and should not be used in production code.
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
content_title: How-To Use Key-Value Map
link_text: "How-To Use Key-Value Map"
---

## Summary

This how-to procedure demonstrates how to define and use a `Key-Value Map` (`kv map`) in your smart contract.

To accomplish this task use `eosio::kv::map` template class, specify the name for the map object instantiated, the type of the key, and the type for the values stored for each key. The types used for the key and the values can be any standard type, or a user defined type.

## Prerequisites

* The EOSIO development environment, for details consult the [Get Started](https://developers.eos.io/welcome/latest/getting-started/development-environment/introduction) Guide.
* A smart contract named `smrtcontract`.
* A user defined type named `person`, which defines the data stored in the map.

Refer to the following possible implementation of your starting point.

`smartcontract.hpp file`

```cpp
struct person {
eosio::name account_name;
std::string first_name;
std::string last_name;
};

class [[eosio::contract]] smartcontract : public eosio::contract {
public:
using contract::contract;
smartcontract(eosio::name receiver, eosio::name code, eosio::datastream<const char*> ds)
: contract(receiver, code, ds) {}
};
```
## Procedure
Complete the following steps to define the `my_map_t` type, based on the `eosio::kv::map`, which stores objects of type `person` with unique keys of type `int` and instantiate a map object of type `my_map_t`:
* Define the `my_map_t` type based on `eosio::kv::map`.
* Specify `"kvmap"_n`, which is an `eosio::name`, as the first parameter, to name for the map object.
* Specify `int` as the second parameter to give the type of the unique keys.
* Specify `person` as the third parameter to give the type of the values stored in the map with each key.
* Declare and instantiate, as a private data member, an instance of the type `my_map_t`, and name it `my_map`.
Refer below for a possible implementation of the above described steps:
`smartcontract.hpp file`
```cpp
class [[eosio::contract]] smartcontract : public eosio::contract {
using my_map_t = eosio::kv::map<"kvmap"_n, int, person>;
public:
using contract::contract;
smartcontract(eosio::name receiver, eosio::name code, eosio::datastream<const char*> ds)
: contract(receiver, code, ds) {}
private:
my_map_t my_map{};
};
```

## Next Steps

The following option is available when you complete the procedure:

* You can can add values in the map object created.
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
---
content_title: How-To Upsert Into Key-Value Map
link_text: "How-To Upsert Into Key-Value Map"
---

## Summary

This how-to procedure provides instructions to upsert into `Key-Value Map` (`kv map`). Upsert means insert when the item doesn't already exist, and update the item if it already exists in the map.

## Prerequisites

Before you begin, complete the following prerequisites:

* An EOSIO development environment, for details consult the [Get Started](https://developers.eos.io/welcome/latest/getting-started/development-environment/introduction) Guide
* A smart contract named `smrtcontract`
* A user defined type named `person`, which defines the data stored in the map
* A `kv map` object, name `my_map`, which stores objects of type `person`, with unique keys of type `int`.

Refer to the following possible implementation of your starting point.

`smartcontract.hpp file`

```cpp
struct person {
eosio::name account_name;
std::string first_name;
std::string last_name;
};

class [[eosio::contract]] smartcontract : public eosio::contract {

using my_map_t = eosio::kv::map<"kvmap"_n, int, person>;

public:
using contract::contract;
smartcontract(eosio::name receiver, eosio::name code, eosio::datastream<const char*> ds)
: contract(receiver, code, ds) {}

private:
my_map_t my_map{};
};
```
## Procedure
Complete the following steps to insert a new `person` object with a given ID, if it doesn't exist already, or update it in the `kv map` if the `person` with the given ID already exists:
1. Create a new action in your contract, named `upsert`, which takes as input parameters the person `id`, an `account_name`, a `first_name` and a `last_name`.
2. Create an instance of the `person` class, named `person_upsert`, based on the input parameters: `account_name`, `first_name` and `last_name`.
3. Use the `[]` operator defined for the `kv::map` type, and set the newly created `person_upsert` object as the value for the `id` key.
Refer to the following possible implementation to insert a new `person` object, and then update it, in the `kv map`:
`smartcontract.hpp file`
```cpp
struct person {
eosio::name account_name;
std::string first_name;
std::string last_name;
};
class [[eosio::contract]] smartcontract : public eosio::contract {
using my_map_t = eosio::kv::map<"kvmap"_n, int, person>;
public:
using contract::contract;
smartcontract(eosio::name receiver, eosio::name code, eosio::datastream<const char*> ds)
: contract(receiver, code, ds) {}
// inserts a person if not exists, or updates it if already exists.
// the payer for the resources consumed is the account that created the kv::map
// object in the first place, the account that owns this smart contract.
[[eosio::action]]
void upsert(int id,
eosio::name account_name,
std::string first_name,
std::string last_name);
private:
my_map_t my_map{};
};
```

`smartcontract.cpp file`

```cpp
// inserts if not exists, or updates if already exists, a person
[[eosio::action]]
void smartcontract::upsert(
int id,
eosio::name account_name,
std::string first_name,
std::string last_name) {

// create the person object which will be stored in kv::map
const person& person_upsert = person{
account_name = account_name,
first_name = first_name,
last_name = last_name};

// upsert into kv::map
my_map[id] = person_upsert;
}
```
## Next Steps
The following options are available when you complete the procedure:
* Verify if the newly inserted `person` actually exists in the map. To accomplish this task use the `find()` function of the `kv_map`.
* Delete the newly created or updated `person` from the map. To accomplish this task, use the `erase()` function of the `kv map`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
---
content_title: How-To Delete from Key-Value Map
link_text: "How-To Delete from Key-Value Map"
---

## Summary

This how-to procedure provides instructions to delete from `Key-Value Map` (`kv map`) based on the unique key.

## Prerequisites

Before you begin, complete the following prerequisites:

* An EOSIO development environment, for details consult the [Get Started](https://developers.eos.io/welcome/latest/getting-started/development-environment/introduction) Guide
* A smart contract named `smrtcontract`
* A user defined type named `person`, which defines the data stored in the map
* A `kv map` object, name `my_map`, which stores objects of type `person`, with unique keys of type `int`.

Refer to the following possible implementation of your starting point.

`smartcontract.hpp file`

```cpp
struct person {
eosio::name account_name;
std::string first_name;
std::string last_name;
};

class [[eosio::contract]] smartcontract : public eosio::contract {

using my_map_t = eosio::kv::map<"kvmap"_n, int, person>;

public:
using contract::contract;
smartcontract(eosio::name receiver, eosio::name code, eosio::datastream<const char*> ds)
: contract(receiver, code, ds) {}

private:
my_map_t my_map{};
};
```
## Procedure
Complete the following steps to delete a `person` object with a given ID from the `kv map`, and print an informative message otherwise:
1. Create a new action in your contract, named `delete`, which takes as input parameters the person ID.
2. Use the `find()` function defined for the `kv::map` type, with the give ID as parameter, to find the `person` which is to be deleted.
3. If the `person` with the give ID is found use the `erase()` function defined for the `kv::map`, with the given ID as parameter, to erase the person object from the map.
4. If the `person` with the given ID is not found print an informative error message.
Refer to the following possible implementation to delete a `person` object from the `kv map`:
`smartcontract.hpp file`
```cpp
struct person {
eosio::name account_name;
std::string first_name;
std::string last_name;
};
class [[eosio::contract]] smartcontract : public eosio::contract {
using my_map_t = eosio::kv::map<"kvmap"_n, int, person>;
public:
using contract::contract;
smartcontract(eosio::name receiver, eosio::name code, eosio::datastream<const char*> ds)
: contract(receiver, code, ds) {}
// deletes a person based on unique id
[[eosio::action]]
void del(int id);
private:
my_map_t my_map{};
};
```

`smartcontract.cpp file`

```cpp
// deletes a person based on unique id
[[eosio::action]]
void kv_map::delete(int id) {

// search for person based on unique id
auto itr = my_map.find(id);

// check if person was found
if (itr != my_map.end()) {
// extract person from iterator and delete it
const auto person_found = itr->second();

// delete it from kv::map
my_map.erase(id);
eosio::print_f("Person (%, %, %) was successfully deleted.",
person_found.first_name, person_found.last_name, person_found.personal_id);
}
else {
eosio::print_f("Person with ID % not found.", id);
}
}
```
Loading

0 comments on commit 6012476

Please sign in to comment.