Add MetaDataRef:get_keys (#12841)

This commit is contained in:
Jude Melton-Houghton 2022-11-15 10:45:12 -05:00 committed by GitHub
parent 1a045da0dd
commit cd8a7fe472
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 125 additions and 0 deletions

@ -6863,6 +6863,7 @@ and [`PlayerMetaRef`].
* `get_int(key)`: Returns `0` if key not present. * `get_int(key)`: Returns `0` if key not present.
* `set_float(key, value)` * `set_float(key, value)`
* `get_float(key)`: Returns `0` if key not present. * `get_float(key)`: Returns `0` if key not present.
* `get_keys()`: returns a list of all keys in the metadata.
* `to_table()`: returns `nil` or a table with keys: * `to_table()`: returns `nil` or a table with keys:
* `fields`: key-value storage * `fields`: key-value storage
* `inventory`: `{list1 = {}, ...}}` (NodeMetaRef only) * `inventory`: `{list1 = {}, ...}}` (NodeMetaRef only)

@ -30,6 +30,14 @@ local function test_metadata(meta)
assert(tab.fields.d == "4") assert(tab.fields.d == "4")
assert(tab.fields.e == "e") assert(tab.fields.e == "e")
local keys = meta:get_keys()
assert(table.indexof(keys, "a") > 0)
assert(table.indexof(keys, "b") > 0)
assert(table.indexof(keys, "c") > 0)
assert(table.indexof(keys, "d") > 0)
assert(table.indexof(keys, "e") > 0)
assert(#keys == 5)
assert(not meta:contains("")) assert(not meta:contains(""))
assert(meta:contains("a")) assert(meta:contains("a"))
assert(meta:contains("b")) assert(meta:contains("b"))
@ -57,6 +65,7 @@ local function test_metadata(meta)
meta:from_table() meta:from_table()
assert(next(meta:to_table().fields) == nil) assert(next(meta:to_table().fields) == nil)
assert(#meta:get_keys() == 0)
assert(not meta:equals(compare_meta)) assert(not meta:equals(compare_meta))
end end

@ -247,6 +247,13 @@ const StringMap &ModMetadata::getStrings(StringMap *place) const
return *place; return *place;
} }
const std::vector<std::string> &ModMetadata::getKeys(std::vector<std::string> *place) const
{
place->clear();
m_database->getModKeys(m_mod_name, place);
return *place;
}
const std::string *ModMetadata::getStringRaw(const std::string &name, std::string *place) const const std::string *ModMetadata::getStringRaw(const std::string &name, std::string *place) const
{ {
return m_database->getModEntry(m_mod_name, name, place) ? place : nullptr; return m_database->getModEntry(m_mod_name, name, place) ? place : nullptr;

@ -127,6 +127,8 @@ public:
const StringMap &getStrings(StringMap *place) const override; const StringMap &getStrings(StringMap *place) const override;
const std::vector<std::string> &getKeys(std::vector<std::string> *place) const override;
protected: protected:
const std::string *getStringRaw(const std::string &name, const std::string *getStringRaw(const std::string &name,
std::string *place) const override; std::string *place) const override;

@ -92,6 +92,17 @@ bool Database_Dummy::getModEntries(const std::string &modname, StringMap *storag
return true; return true;
} }
bool Database_Dummy::getModKeys(const std::string &modname, std::vector<std::string> *storage)
{
const auto mod_pair = m_mod_meta_database.find(modname);
if (mod_pair != m_mod_meta_database.cend()) {
storage->reserve(storage->size() + mod_pair->second.size());
for (const auto &pair : mod_pair->second)
storage->push_back(pair.first);
}
return true;
}
bool Database_Dummy::getModEntry(const std::string &modname, bool Database_Dummy::getModEntry(const std::string &modname,
const std::string &key, std::string *value) const std::string &key, std::string *value)
{ {

@ -38,6 +38,7 @@ public:
void listPlayers(std::vector<std::string> &res); void listPlayers(std::vector<std::string> &res);
bool getModEntries(const std::string &modname, StringMap *storage); bool getModEntries(const std::string &modname, StringMap *storage);
bool getModKeys(const std::string &modname, std::vector<std::string> *storage);
bool getModEntry(const std::string &modname, bool getModEntry(const std::string &modname,
const std::string &key, std::string *value); const std::string &key, std::string *value);
bool hasModEntry(const std::string &modname, const std::string &key); bool hasModEntry(const std::string &modname, const std::string &key);

@ -396,6 +396,21 @@ bool ModMetadataDatabaseFiles::getModEntries(const std::string &modname, StringM
return true; return true;
} }
bool ModMetadataDatabaseFiles::getModKeys(const std::string &modname,
std::vector<std::string> *storage)
{
Json::Value *meta = getOrCreateJson(modname);
if (!meta)
return false;
std::vector<std::string> keys = meta->getMemberNames();
storage->reserve(storage->size() + keys.size());
for (std::string &key : keys)
storage->push_back(std::move(key));
return true;
}
bool ModMetadataDatabaseFiles::getModEntry(const std::string &modname, bool ModMetadataDatabaseFiles::getModEntry(const std::string &modname,
const std::string &key, std::string *value) const std::string &key, std::string *value)
{ {

@ -79,6 +79,7 @@ public:
virtual ~ModMetadataDatabaseFiles() = default; virtual ~ModMetadataDatabaseFiles() = default;
virtual bool getModEntries(const std::string &modname, StringMap *storage); virtual bool getModEntries(const std::string &modname, StringMap *storage);
virtual bool getModKeys(const std::string &modname, std::vector<std::string> *storage);
virtual bool getModEntry(const std::string &modname, virtual bool getModEntry(const std::string &modname,
const std::string &key, std::string *value); const std::string &key, std::string *value);
virtual bool hasModEntry(const std::string &modname, const std::string &key); virtual bool hasModEntry(const std::string &modname, const std::string &key);

@ -775,6 +775,7 @@ ModMetadataDatabaseSQLite3::~ModMetadataDatabaseSQLite3()
FINALIZE_STATEMENT(m_stmt_set) FINALIZE_STATEMENT(m_stmt_set)
FINALIZE_STATEMENT(m_stmt_has) FINALIZE_STATEMENT(m_stmt_has)
FINALIZE_STATEMENT(m_stmt_get) FINALIZE_STATEMENT(m_stmt_get)
FINALIZE_STATEMENT(m_stmt_get_keys)
FINALIZE_STATEMENT(m_stmt_get_all) FINALIZE_STATEMENT(m_stmt_get_all)
} }
@ -796,6 +797,7 @@ void ModMetadataDatabaseSQLite3::createDatabase()
void ModMetadataDatabaseSQLite3::initStatements() void ModMetadataDatabaseSQLite3::initStatements()
{ {
PREPARE_STATEMENT(get_all, "SELECT `key`, `value` FROM `entries` WHERE `modname` = ?"); PREPARE_STATEMENT(get_all, "SELECT `key`, `value` FROM `entries` WHERE `modname` = ?");
PREPARE_STATEMENT(get_keys, "SELECT `key` FROM `entries` WHERE `modname` = ?");
PREPARE_STATEMENT(get, PREPARE_STATEMENT(get,
"SELECT `value` FROM `entries` WHERE `modname` = ? AND `key` = ? LIMIT 1"); "SELECT `value` FROM `entries` WHERE `modname` = ? AND `key` = ? LIMIT 1");
PREPARE_STATEMENT(has, PREPARE_STATEMENT(has,
@ -825,6 +827,24 @@ bool ModMetadataDatabaseSQLite3::getModEntries(const std::string &modname, Strin
return true; return true;
} }
bool ModMetadataDatabaseSQLite3::getModKeys(const std::string &modname,
std::vector<std::string> *storage)
{
verifyDatabase();
str_to_sqlite(m_stmt_get_keys, 1, modname);
while (sqlite3_step(m_stmt_get_keys) == SQLITE_ROW) {
const char *key_data = (const char *) sqlite3_column_blob(m_stmt_get_keys, 0);
size_t key_len = sqlite3_column_bytes(m_stmt_get_keys, 0);
storage->emplace_back(key_data, key_len);
}
sqlite3_vrfy(sqlite3_errcode(m_database), SQLITE_DONE);
sqlite3_reset(m_stmt_get_keys);
return true;
}
bool ModMetadataDatabaseSQLite3::getModEntry(const std::string &modname, bool ModMetadataDatabaseSQLite3::getModEntry(const std::string &modname,
const std::string &key, std::string *value) const std::string &key, std::string *value)
{ {

@ -240,6 +240,7 @@ public:
virtual ~ModMetadataDatabaseSQLite3(); virtual ~ModMetadataDatabaseSQLite3();
virtual bool getModEntries(const std::string &modname, StringMap *storage); virtual bool getModEntries(const std::string &modname, StringMap *storage);
virtual bool getModKeys(const std::string &modname, std::vector<std::string> *storage);
virtual bool getModEntry(const std::string &modname, virtual bool getModEntry(const std::string &modname,
const std::string &key, std::string *value); const std::string &key, std::string *value);
virtual bool hasModEntry(const std::string &modname, const std::string &key); virtual bool hasModEntry(const std::string &modname, const std::string &key);
@ -258,6 +259,7 @@ protected:
private: private:
sqlite3_stmt *m_stmt_get_all = nullptr; sqlite3_stmt *m_stmt_get_all = nullptr;
sqlite3_stmt *m_stmt_get_keys = nullptr;
sqlite3_stmt *m_stmt_get = nullptr; sqlite3_stmt *m_stmt_get = nullptr;
sqlite3_stmt *m_stmt_has = nullptr; sqlite3_stmt *m_stmt_has = nullptr;
sqlite3_stmt *m_stmt_set = nullptr; sqlite3_stmt *m_stmt_set = nullptr;

@ -92,6 +92,7 @@ public:
virtual ~ModMetadataDatabase() = default; virtual ~ModMetadataDatabase() = default;
virtual bool getModEntries(const std::string &modname, StringMap *storage) = 0; virtual bool getModEntries(const std::string &modname, StringMap *storage) = 0;
virtual bool getModKeys(const std::string &modname, std::vector<std::string> *storage) = 0;
virtual bool hasModEntry(const std::string &modname, const std::string &key) = 0; virtual bool hasModEntry(const std::string &modname, const std::string &key) = 0;
virtual bool getModEntry(const std::string &modname, virtual bool getModEntry(const std::string &modname,
const std::string &key, std::string *value) = 0; const std::string &key, std::string *value) = 0;

@ -108,6 +108,15 @@ const StringMap &SimpleMetadata::getStrings(StringMap *) const
return m_stringvars; return m_stringvars;
} }
const std::vector<std::string> &SimpleMetadata::getKeys(std::vector<std::string> *place) const
{
place->clear();
place->reserve(m_stringvars.size());
for (const auto &pair : m_stringvars)
place->push_back(pair.first);
return *place;
}
const std::string *SimpleMetadata::getStringRaw(const std::string &name, std::string *) const const std::string *SimpleMetadata::getStringRaw(const std::string &name, std::string *) const
{ {
const auto found = m_stringvars.find(name); const auto found = m_stringvars.find(name);

@ -60,6 +60,9 @@ public:
// May (not must!) put strings in `place` and return a reference to these strings. // May (not must!) put strings in `place` and return a reference to these strings.
virtual const StringMap &getStrings(StringMap *place) const = 0; virtual const StringMap &getStrings(StringMap *place) const = 0;
// May (not must!) put keys in `place` and return a reference to these keys.
virtual const std::vector<std::string> &getKeys(std::vector<std::string> *place) const = 0;
// Add support for variable names in values. Uses place like getString. // Add support for variable names in values. Uses place like getString.
const std::string &resolveString(const std::string &str, std::string *place, const std::string &resolveString(const std::string &str, std::string *place,
u16 recursion = 0) const; u16 recursion = 0) const;
@ -88,6 +91,8 @@ public:
bool contains(const std::string &name) const override; bool contains(const std::string &name) const override;
virtual bool setString(const std::string &name, const std::string &var) override; virtual bool setString(const std::string &name, const std::string &var) override;
const StringMap &getStrings(StringMap *) const override final; const StringMap &getStrings(StringMap *) const override final;
const std::vector<std::string> &getKeys(std::vector<std::string> *place)
const override final;
// Simple version of getters, possible due to in-memory storage: // Simple version of getters, possible due to in-memory storage:

@ -97,6 +97,7 @@ const luaL_Reg ItemStackMetaRef::methods[] = {
luamethod(MetaDataRef, set_int), luamethod(MetaDataRef, set_int),
luamethod(MetaDataRef, get_float), luamethod(MetaDataRef, get_float),
luamethod(MetaDataRef, set_float), luamethod(MetaDataRef, set_float),
luamethod(MetaDataRef, get_keys),
luamethod(MetaDataRef, to_table), luamethod(MetaDataRef, to_table),
luamethod(MetaDataRef, from_table), luamethod(MetaDataRef, from_table),
luamethod(MetaDataRef, equals), luamethod(MetaDataRef, equals),

@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "serverenvironment.h" #include "serverenvironment.h"
#include "map.h" #include "map.h"
#include "server.h" #include "server.h"
#include "util/basic_macros.h"
MetaDataRef *MetaDataRef::checkAnyMetadata(lua_State *L, int narg) MetaDataRef *MetaDataRef::checkAnyMetadata(lua_State *L, int narg)
{ {
@ -196,6 +197,31 @@ int MetaDataRef::l_set_float(lua_State *L)
return 0; return 0;
} }
// get_keys(self)
int MetaDataRef::l_get_keys(lua_State *L)
{
MAP_LOCK_REQUIRED;
MetaDataRef *ref = checkAnyMetadata(L, 1);
IMetadata *meta = ref->getmeta(false);
if (meta == NULL) {
lua_newtable(L);
return 1;
}
std::vector<std::string> keys_;
const std::vector<std::string> &keys = meta->getKeys(&keys_);
int i = 0;
lua_createtable(L, keys.size(), 0);
for (const std::string &key : keys) {
lua_pushlstring(L, key.c_str(), key.size());
lua_rawseti(L, -2, ++i);
}
return 1;
}
// to_table(self) // to_table(self)
int MetaDataRef::l_to_table(lua_State *L) int MetaDataRef::l_to_table(lua_State *L)
{ {

@ -74,6 +74,9 @@ protected:
// set_float(self, name, var) // set_float(self, name, var)
static int l_set_float(lua_State *L); static int l_set_float(lua_State *L);
// get_keys(self)
static int l_get_keys(lua_State *L);
// to_table(self) // to_table(self)
static int l_to_table(lua_State *L); static int l_to_table(lua_State *L);

@ -209,6 +209,7 @@ const luaL_Reg NodeMetaRef::methodsServer[] = {
luamethod(MetaDataRef, set_int), luamethod(MetaDataRef, set_int),
luamethod(MetaDataRef, get_float), luamethod(MetaDataRef, get_float),
luamethod(MetaDataRef, set_float), luamethod(MetaDataRef, set_float),
luamethod(MetaDataRef, get_keys),
luamethod(MetaDataRef, to_table), luamethod(MetaDataRef, to_table),
luamethod(MetaDataRef, from_table), luamethod(MetaDataRef, from_table),
luamethod(NodeMetaRef, get_inventory), luamethod(NodeMetaRef, get_inventory),
@ -230,6 +231,7 @@ const luaL_Reg NodeMetaRef::methodsClient[] = {
luamethod(MetaDataRef, get_string), luamethod(MetaDataRef, get_string),
luamethod(MetaDataRef, get_int), luamethod(MetaDataRef, get_int),
luamethod(MetaDataRef, get_float), luamethod(MetaDataRef, get_float),
luamethod(MetaDataRef, get_keys),
luamethod(MetaDataRef, to_table), luamethod(MetaDataRef, to_table),
{0,0} {0,0}
}; };

@ -70,6 +70,7 @@ const luaL_Reg PlayerMetaRef::methods[] = {
luamethod(MetaDataRef, set_int), luamethod(MetaDataRef, set_int),
luamethod(MetaDataRef, get_float), luamethod(MetaDataRef, get_float),
luamethod(MetaDataRef, set_float), luamethod(MetaDataRef, set_float),
luamethod(MetaDataRef, get_keys),
luamethod(MetaDataRef, to_table), luamethod(MetaDataRef, to_table),
luamethod(MetaDataRef, from_table), luamethod(MetaDataRef, from_table),
luamethod(MetaDataRef, equals), luamethod(MetaDataRef, equals),

@ -74,6 +74,7 @@ const luaL_Reg StorageRef::methods[] = {
luamethod(MetaDataRef, set_int), luamethod(MetaDataRef, set_int),
luamethod(MetaDataRef, get_float), luamethod(MetaDataRef, get_float),
luamethod(MetaDataRef, set_float), luamethod(MetaDataRef, set_float),
luamethod(MetaDataRef, get_keys),
luamethod(MetaDataRef, to_table), luamethod(MetaDataRef, to_table),
luamethod(MetaDataRef, from_table), luamethod(MetaDataRef, from_table),
luamethod(MetaDataRef, equals), luamethod(MetaDataRef, equals),

@ -286,8 +286,11 @@ void TestModMetadataDatabase::testRecallFail()
{ {
ModMetadataDatabase *mod_meta_db = mod_meta_provider->getModMetadataDatabase(); ModMetadataDatabase *mod_meta_db = mod_meta_provider->getModMetadataDatabase();
StringMap recalled; StringMap recalled;
std::vector<std::string> recalled_keys;
mod_meta_db->getModEntries("mod1", &recalled); mod_meta_db->getModEntries("mod1", &recalled);
mod_meta_db->getModKeys("mod1", &recalled_keys);
UASSERT(recalled.empty()); UASSERT(recalled.empty());
UASSERT(recalled_keys.empty());
std::string key1_value; std::string key1_value;
UASSERT(!mod_meta_db->getModEntry("mod1", "key1", &key1_value)); UASSERT(!mod_meta_db->getModEntry("mod1", "key1", &key1_value));
UASSERT(!mod_meta_db->hasModEntry("mod1", "key1")); UASSERT(!mod_meta_db->hasModEntry("mod1", "key1"));
@ -303,9 +306,13 @@ void TestModMetadataDatabase::testRecall()
{ {
ModMetadataDatabase *mod_meta_db = mod_meta_provider->getModMetadataDatabase(); ModMetadataDatabase *mod_meta_db = mod_meta_provider->getModMetadataDatabase();
StringMap recalled; StringMap recalled;
std::vector<std::string> recalled_keys;
mod_meta_db->getModEntries("mod1", &recalled); mod_meta_db->getModEntries("mod1", &recalled);
mod_meta_db->getModKeys("mod1", &recalled_keys);
UASSERTCMP(std::size_t, ==, recalled.size(), 1); UASSERTCMP(std::size_t, ==, recalled.size(), 1);
UASSERTCMP(std::size_t, ==, recalled_keys.size(), 1);
UASSERTCMP(std::string, ==, recalled["key1"], "value1"); UASSERTCMP(std::string, ==, recalled["key1"], "value1");
UASSERTCMP(std::string, ==, recalled_keys[0], "key1");
std::string key1_value; std::string key1_value;
UASSERT(mod_meta_db->getModEntry("mod1", "key1", &key1_value)); UASSERT(mod_meta_db->getModEntry("mod1", "key1", &key1_value));
UASSERTCMP(std::string, ==, key1_value, "value1"); UASSERTCMP(std::string, ==, key1_value, "value1");