多索引表例子
优质
小牛编辑
137浏览
2023-12-01
create a struct
struct [[eosio::table]] mystruct
{
uint64_t key;
uint64_t secondid;
std::string name;
std::string account;
uint64_t primary_key() const { return key; } // getter for primary key
uint64_t by_id() const {return secondid; } // getter for additional key
};
[[eosio::table]]
被 ABI generator eosio-cpp 所需要,以识别该表并将其通过ABI暴露出去,并将其可见性扩展到合约外.- struct name 要小于12个字符并全是小写.
typedef the multi index table and the define the indexes
primary key
使用mystruct
定义一个multi index table,告诉它将以什么作为索引以及如何获取被索引的数据.主键会被自动创建,所以如果只想同光上面的struct创建一个只有主键的multi index table可以这样定义:
typedef eosio::multi_index<name(mystruct), mystruct> datastore;
它通过传入表名"name(mystruct)"以及struct名"mystruct"来定义multi index.name(mystruct)
执行了编译转换,将struct name转换成uint64_t并将这一uint64_t用来查找属于这个multi index table的数据.
additional or secondary indexes
如果想添加额外的或次要索引,使用 indexed_by 模板作为参数,可以定义为:
typedef eosio::multi_index<name(mystruct), mystruct, indexed_by<name(secondid), const_mem_fun<mystruct, uint64_t, &mystruct::by_id>>> datastore;
indexed_by<name(secondid), const_mem_fun<mystruct, uint64_t, &mystruct::by_id>>
中 parameters:
name(secondid)
—— 字段的名称会被转换为integerconst_mem_fun<mystruct, uint64_t, &mystruct::by_id>
—— 用户定义的 key extractor
three indexes
struct [[eosio::table]] mystruct
{
uint64_t key;
uint64_t secondid;
uint64_t anotherid;
std::string name;
std::string account;
uint64_t primary_key() const { return key; }
uint64_t by_id() const {return secondid; }
uint64_t by_anotherid() const {return anotherid; }
};
typedef eosio::multi_index<name(mystruct), mystruct, indexed_by<name(secondid), const_mem_fun<mystruct, uint64_t, &mystruct::by_id>>, indexed_by<name(anotherid), const_mem_fun<mystruct, uint64_t, &mystruct::by_anotherid>>> datastore;
诸如此类.
有一个重要的事情需要注意,struct name与table name相匹配,并且命名会在ABI文件中根据规则(12个字符并全是小写)被显示.如果不这样,那么通过ABI看不到该table(你可以通过编辑ABI文件来解决这个问题).
create local variables which are of the defined type
// local instances of the multi indexes
pollstable _polls;
votes _votes;
我现在定义了一个有两个索引的多索引表,我现在可以在我的智能合约中使用它们.
一个使用双索引表的智能合约例子如下所示.你能看到如何遍历该表以及如何在同一个合约中使用两张表.
#include <eosiolib/eosio.hpp>
using namespace eosio;
class youvote : public contract {
public:
youvote(eosio::name s):contract(s), _polls(s, s), _votes(s, s)
{}
// public methods exposed via the ABI
// on pollsTable
[[eosio::action]]
void version()
{
print("YouVote version 0.01");
};
[[eosio::action]]
void addpoll(eosio::name s, std::string pollName)
{
//require_auth(s);
print("Add poll ", pollName);
// update the table to include a new poll
_polls.emplace(get_self(), [&](auto& p)
{
p.key = _polls.available_primary_key();
p.pollId = _polls.available_primary_key();
p.pollName = pollName;
p.pollStatus = 0;
p.option = "";
p.count = 0;
});
};
[[eosio::action]]
void rmpoll(eosio::name s, std::string pollName)
{
//require_auth(s);
print("Remove poll ", pollName);
std::vector<uint64_t> keysForDeletion;
// find items which are for the named poll
for(auto& item : _polls)
{
if (item.pollName == pollName)
{
keysForDeletion.push_back(item.key);
}
}
// now delete each item for that poll
for (uint64_t key : keysForDeletion)
{
print("remove from _polls ", key);
auto itr = _polls.find(key);
if (itr != _polls.end())
{
_polls.erase(itr);
}
}
// add remove votes ... don't need it the actions are permanently stored on the block chain
std::vector<uint64_t> keysForDeletionFromVotes;
// find items which are for the named poll
for(auto& item : _votes)
{
if (item.pollName == pollName)
{
keysForDeletionFromVotes.push_back(item.key);
}
}
// now delete each item for that poll
for (uint64_t key : keysForDeletionFromVotes)
{
print("remove from _votes ", key);
auto itr = _votes.find(key);
if (itr != _votes.end())
{
_votes.erase(itr);
}
}
};
[[eosio::action]]
void status(std::string pollName)
{
print("Change poll status ", pollName);
std::vector<uint64_t> keysForModify;
// find items which are for the named poll
for(auto& item : _polls)
{
if (item.pollName == pollName)
{
keysForModify.push_back(item.key);
}
}
// now get each item and modify the status
for (uint64_t key : keysForModify)
{
print("modify _polls status", key);
auto itr = _polls.find(key);
if (itr != _polls.end())
{
_polls.modify(itr, get_self(), [&](auto& p)
{
p.pollStatus = p.pollStatus + 1;
});
}
}
};
[[eosio::action]]
void statusreset(std::string pollName)
{
print("Reset poll status ", pollName);
std::vector<uint64_t> keysForModify;
// find all poll items
for(auto& item : _polls)
{
if (item.pollName == pollName)
{
keysForModify.push_back(item.key);
}
}
// update the status in each poll item
for (uint64_t key : keysForModify)
{
print("modify _polls status", key);
auto itr = _polls.find(key);
if (itr != _polls.end())
{
_polls.modify(itr, get_self(), [&](auto& p)
{
p.pollStatus = 0;
});
}
}
};
[[eosio::action]]
void addpollopt(std::string pollName, std::string option)
{
print("Add poll option ", pollName, "option ", option);
// find the pollId, from _polls, use this to update the _polls with a new option
for(auto& item : _polls)
{
if (item.pollName == pollName)
{
// can only add if the poll is not started or finished
if(item.pollStatus == 0)
{
_polls.emplace(get_self(), [&](auto& p)
{
p.key = _polls.available_primary_key();
p.pollId = item.pollId;
p.pollName = item.pollName;
p.pollStatus = 0;
p.option = option;
p.count = 0;
});
}
else
{
print("Can not add poll option ", pollName, "option ", option, " Poll has started or is finished.");
}
break; // so you only add it once
}
}
};
[[eosio::action]]
void rmpollopt(std::string pollName, std::string option)
{
print("Remove poll option ", pollName, "option ", option);
std::vector<uint64_t> keysForDeletion;
// find and remove the named poll
for(auto& item : _polls)
{
if (item.pollName == pollName)
{
keysForDeletion.push_back(item.key);
}
}
for (uint64_t key : keysForDeletion)
{
print("remove from _polls ", key);
auto itr = _polls.find(key);
if (itr != _polls.end())
{
if (itr->option == option)
{
_polls.erase(itr);
}
}
}
};
[[eosio::abi]]
void vote(std::string pollName, std::string option, std::string accountName)
{
print("vote for ", option, " in poll ", pollName, " by ", accountName);
// is the poll open
for(auto& item : _polls)
{
if (item.pollName == pollName)
{
if (item.pollStatus != 1)
{
print("Poll ",pollName, " is not open");
return;
}
break; // only need to check status once
}
}
// has account name already voted?
for(auto& vote : _votes)
{
if (vote.pollName == pollName && vote.account == accountName)
{
print(accountName, " has already voted in poll ", pollName);
//eosio_assert(true, "Already Voted");
return;
}
}
uint64_t pollId =99999; // get the pollId for the _votes table
// find the poll and the option and increment the count
for(auto& item : _polls)
{
if (item.pollName == pollName && item.option == option)
{
pollId = item.pollId; // for recording vote in this poll
_polls.modify(item, get_self(), [&](auto& p)
{
p.count = p.count + 1;
});
}
}
// record that accountName has voted
_votes.emplace(get_self(), [&](auto& pv)
{
pv.key = _votes.available_primary_key();
pv.pollId = pollId;
pv.pollName = pollName;
pv.account = accountName;
});
};
private:
// create the multi index tables to store the data
struct [[eosio::table]] poll
{
uint64_t key; // primary key
uint64_t pollId; // second key, non-unique, this table will have dup rows for each poll because of option
std::string pollName; // name of poll
uint8_t pollStatus =0; // staus where 0 = closed, 1 = open, 2 = finished
std::string option; // the item you can vote for
uint32_t count =0; // the number of votes for each itme -- this to be pulled out to separte table.
uint64_t primary_key() const { return key; }
uint64_t by_pollId() const {return pollId; }
};
typedef eosio::multi_index<N(poll), poll, indexed_by<N(pollId), const_mem_fun<poll, uint64_t, &poll::by_pollId>>> pollstable;
struct [[eosio::table]] pollvotes
{
uint64_t key;
uint64_t pollId;
std::string pollName; // name of poll
std::string account; //this account has voted, use this to make sure noone votes > 1
uint64_t primary_key() const { return key; }
uint64_t by_pollId() const {return pollId; }
};
typedef eosio::multi_index<name(pollvotes), pollvotes, indexed_by<name(pollId), const_mem_fun<pollvotes, uint64_t, &pollvotes::by_pollId>>> votes;
// local instances of the multi indexes
pollstable _polls;
votes _votes;
};
EOSIO_DISPATCH( youvote, (version)(addpoll)(rmpoll)(status)(statusreset)(addpollopt)(rmpollopt)(vote))
注意EOSIO_ABI调用,它通过abi公开函数,重要的是函数名称与abi函数名称规则匹配.