JSON serialized storage of properties table.

This commit is contained in:
Christian Speckner 2021-01-01 19:12:48 +01:00
parent 2724ce30ee
commit 37abfb3dfe
22 changed files with 496 additions and 88 deletions

View File

@ -101,6 +101,8 @@
"ranges": "cpp",
"stop_token": "cpp",
"version": "cpp",
"shared_mutex": "cpp"
"shared_mutex": "cpp",
"compare": "cpp",
"concepts": "cpp"
}
}

View File

@ -33,6 +33,8 @@ MODULE_OBJS := \
src/common/sdl_blitter/QisBlitter.o \
src/common/sdl_blitter/BlitterFactory.o \
src/common/repository/KeyValueRepositoryPropertyFile.o \
src/common/repository/KeyValueRepositoryJsonFile.o \
src/common/repository/CompositeKVRJsonAdapter.o
MODULE_DIRS += \
src/common

View File

@ -0,0 +1,77 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include <sstream>
#include "CompositeKVRJsonAdapter.hxx"
#include "repository/KeyValueRepositoryJsonFile.hxx"
namespace {
class ProxyRepository : public KeyValueRepository {
public:
ProxyRepository(KeyValueRepositoryAtomic& kvr, const string& key)
: myKvr(kvr), myKey(key)
{}
std::map<string, Variant> load() override {
if (!myKvr.has(myKey)) return std::map<string, Variant>();
string serialized;
myKvr.get(myKey, serialized);
stringstream in{serialized};
return KeyValueRepositoryJsonFile::load(in);
}
bool save(const std::map<string, Variant>& values) override {
stringstream out;
if (!KeyValueRepositoryJsonFile::save(out, values)) return false;
return myKvr.save(myKey, out.str());
}
private:
KeyValueRepositoryAtomic& myKvr;
const string& myKey;
};
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CompositeKVRJsonAdapter::CompositeKVRJsonAdapter(KeyValueRepositoryAtomic& kvr)
: myKvr(kvr)
{}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
shared_ptr<KeyValueRepository> CompositeKVRJsonAdapter::get(const string& key)
{
return make_shared<ProxyRepository>(myKvr, key);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CompositeKVRJsonAdapter::has(const string& key)
{
return myKvr.has(key);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CompositeKVRJsonAdapter::remove(const string& key)
{
return myKvr.remove(key);
}

View File

@ -0,0 +1,41 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef COMPOSITE_KVR_JSON_ADAPTER_HXX
#define COMPOSITE_KVR_JSON_ADAPTER_HXX
#include "repository/CompositeKeyValueRepository.hxx"
#include "repository/KeyValueRepository.hxx"
#include "bspf.hxx"
class CompositeKVRJsonAdapter : public CompositeKeyValueRepository {
public:
CompositeKVRJsonAdapter(KeyValueRepositoryAtomic& kvr);
shared_ptr<KeyValueRepository> get(const string& key) override;
bool has(const string& key) override;
void remove(const string& key) override;
private:
KeyValueRepositoryAtomic& myKvr;
};
#endif // COMPOSITE_KVR_JSON_ADAPTER_HXX

View File

@ -23,6 +23,11 @@
#include "Variant.hxx"
#include "bspf.hxx"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Woverloaded-virtual"
class KeyValueRepositoryAtomic;
class KeyValueRepository
{
public:
@ -33,9 +38,22 @@ class KeyValueRepository
virtual bool save(const std::map<string, Variant>& values) = 0;
virtual KeyValueRepositoryAtomic* atomic() { return nullptr; }
};
class KeyValueRepositoryAtomic : public KeyValueRepository {
public:
virtual bool has(const string& key) = 0;
virtual bool get(const string& key, string& value) = 0;
virtual bool save(const string& key, const Variant& value) = 0;
virtual void remove(const string& key) = 0;
KeyValueRepositoryAtomic* atomic() override { return this; }
};
#pragma clang diagnostic pop
#endif // KEY_VALUE_REPOSITORY_HXX

View File

@ -21,7 +21,7 @@
#include "FSNode.hxx"
#include "KeyValueRepository.hxx"
class KeyValueRepositoryConfigfile : public KeyValueRepository
class KeyValueRepositoryConfigfile : public KeyValueRepositoryAtomic
{
public:
@ -31,10 +31,6 @@ class KeyValueRepositoryConfigfile : public KeyValueRepository
bool save(const std::map<string, Variant>& values) override;
bool save(const string& key, const Variant& value) override { return false; }
void remove(const string& key) override {}
private:
FilesystemNode myFile;

View File

@ -0,0 +1,99 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef KEY_VALUE_REPOSITORY_FILE_HXX
#define KEY_VALUE_REPOSITORY_FILE_HXX
#include <sstream>
#include "KeyValueRepository.hxx"
#include "Logger.hxx"
#include "FSNode.hxx"
#include "bspf.hxx"
template<class T>
class KeyValueRepositoryFile : public KeyValueRepository {
public:
KeyValueRepositoryFile(const FilesystemNode& node);
std::map<string, Variant> load() override;
bool save(const std::map<string, Variant>& values) override;
protected:
const FilesystemNode& myNode;
};
///////////////////////////////////////////////////////////////////////////////
// IMPLEMEMNTATION
///////////////////////////////////////////////////////////////////////////////
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
template<class T>
KeyValueRepositoryFile<T>::KeyValueRepositoryFile(const FilesystemNode& node)
: myNode(node)
{}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
template<class T>
std::map<string, Variant> KeyValueRepositoryFile<T>::load()
{
if (!myNode.exists()) return std::map<string, Variant>();
stringstream in;
try {
myNode.read(in);
return T::load(in);
}
catch (const runtime_error& err) {
Logger::error(err.what());
return std::map<string, Variant>();
}
catch (...) {
return std::map<string, Variant>();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
template<class T>
bool KeyValueRepositoryFile<T>::save(const std::map<string, Variant>& values)
{
if (values.size() == 0) return true;
stringstream out;
try {
T::save(out, values);
myNode.write(out);
return true;
}
catch (const runtime_error& err) {
Logger::error(err.what());
return false;
}
catch (...)
{
return false;
}
}
#endif // KEY_VALUE_REPOSITORY_FILE

View File

@ -0,0 +1,81 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "repository/KeyValueRepositoryJsonFile.hxx"
#include "Logger.hxx"
#include "json_lib.hxx"
using nlohmann::json;
namespace {
json jsonIfValid(const string& s) {
json parsed = json::parse(s, nullptr, false);
return parsed.is_discarded() ? json(s) : parsed;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyValueRepositoryJsonFile::KeyValueRepositoryJsonFile(const FilesystemNode& node)
: KeyValueRepositoryFile<KeyValueRepositoryJsonFile>(node)
{}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::map<string, Variant> KeyValueRepositoryJsonFile::load(istream& in)
{
try {
std::map<string, Variant> map;
json deserialized = json::parse(in);
if (!deserialized.is_object()) {
Logger::error("KeyVallueRepositoryJsonFile: not an object");
return map;
}
for (const auto& [key, value] : deserialized.items())
map[key] = value.is_string() ? value.get<string>() : value.dump();
return map;
}
catch (const json::exception& err) {
Logger::error("KeyValueRepositoryJsonFile: error during deserialization: " + string(err.what()));
return std::map<string, Variant>();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool KeyValueRepositoryJsonFile::save(ostream& out, const std::map<string, Variant>& values)
{
try {
json serializedJson = json::object();
for (const auto& [key, value] : values)
serializedJson[key] = jsonIfValid(value.toString());
out << serializedJson.dump(2);
return true;
}
catch (const json::exception& err) {
Logger::error("KeyValueRepositoryJsonFile: error during serialization: " + string(err.what()));
return false;
}
}

View File

@ -0,0 +1,36 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef KEY_VALUE_REPOSITORY_JSON_FILE_HXX
#define KEY_VALUE_REPOSITORY_JSON_FILE_HXX
#include <istream>
#include <ostream>
#include "repository/KeyValueRepositoryFile.hxx"
#include "bspf.hxx"
class KeyValueRepositoryJsonFile : public KeyValueRepositoryFile<KeyValueRepositoryJsonFile> {
public:
KeyValueRepositoryJsonFile(const FilesystemNode& node);
static std::map<string, Variant> load(istream& in);
static bool save(ostream& out, const std::map<string, Variant>& values);
};
#endif // KEY_VALUE_REPOSITORY_JSON_FILE_HXX

View File

@ -20,7 +20,7 @@
#include "KeyValueRepository.hxx"
class KeyValueRepositoryNoop : public KeyValueRepository
class KeyValueRepositoryNoop : public KeyValueRepositoryAtomic
{
public:
@ -28,6 +28,10 @@ class KeyValueRepositoryNoop : public KeyValueRepository
return std::map<string, Variant>();
}
bool has(const string& key) override { return false; }
bool get(const string& key, string& value) override { return false; }
bool save(const std::map<string, Variant>& values) override { return false; }
bool save(const string& key, const Variant& value) override { return false; }

View File

@ -8,20 +8,14 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include <istream>
#include <ostream>
#include <sstream>
#include <map>
#include "repository/KeyValueRepositoryPropertyFile.hxx"
#include "Logger.hxx"
namespace {
@ -77,30 +71,14 @@ namespace {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyValueRepositoryPropertyFile::KeyValueRepositoryPropertyFile(const FilesystemNode& node)
: myNode(node)
: KeyValueRepositoryFile<KeyValueRepositoryPropertyFile>(node)
{}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::map<string, Variant> KeyValueRepositoryPropertyFile::load()
std::map<string, Variant> KeyValueRepositoryPropertyFile::load(istream& in)
{
std::map<string, Variant> map;
if (!myNode.exists()) return map;
stringstream in;
try {
myNode.read(in);
}
catch (const runtime_error& err) {
Logger::error(err.what());
return map;
}
catch (...) {
return map;
}
// Loop reading properties
string key, value;
for(;;)
@ -129,12 +107,8 @@ std::map<string, Variant> KeyValueRepositoryPropertyFile::load()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool KeyValueRepositoryPropertyFile::save(const std::map<string, Variant>& values)
bool KeyValueRepositoryPropertyFile::save(ostream& out, const std::map<string, Variant>& values)
{
if (values.size() == 0) return true;
stringstream out;
for (auto& [key, value]: values) {
writeQuotedString(out, key);
out.put(' ');
@ -142,22 +116,5 @@ bool KeyValueRepositoryPropertyFile::save(const std::map<string, Variant>& value
out.put('\n');
}
writeQuotedString(out, "");
out.put('\n');
out.put('\n');
try {
myNode.write(out);
return true;
}
catch (const runtime_error& err) {
Logger::error(err.what());
return false;
}
catch (...)
{
return false;
}
}

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -18,25 +18,19 @@
#ifndef KEY_VALUE_REPOSITORY_PROPERTY_FILE_HXX
#define KEY_VALUE_REPOSITORY_PROPERTY_FILE_HXX
#include "repository/KeyValueRepository.hxx"
#include "FSNode.hxx"
#include <istream>
#include <ostream>
#include "repository/KeyValueRepositoryFile.hxx"
#include "bspf.hxx"
class KeyValueRepositoryPropertyFile : public KeyValueRepository {
class KeyValueRepositoryPropertyFile : public KeyValueRepositoryFile<KeyValueRepositoryPropertyFile> {
public:
KeyValueRepositoryPropertyFile(const FilesystemNode& node);
std::map<string, Variant> load() override;
static std::map<string, Variant> load(istream& in);
bool save(const std::map<string, Variant>& values) override;
bool save(const string& key, const Variant& value) override { return false; }
void remove(const string& key) override {}
private:
const FilesystemNode& myNode;
static bool save(ostream& out, const std::map<string, Variant>& values);
};
#endif
#endif // KEY_VALUE_REPOSITORY_PROPERTY_FILE_HXX

View File

@ -40,6 +40,47 @@ std::map<string, Variant> AbstractKeyValueRepositorySqlite::load()
return values;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool AbstractKeyValueRepositorySqlite::has(const string& key)
{
try {
SqliteStatement& stmt{stmtCount(key)};
if (!stmt.step()) throw new SqliteError("count failed");
const bool result = stmt.columnInt(0) != 0;
stmt.reset();
return result;
}
catch (const SqliteError& err) {
Logger::error(err.what());
return false;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool AbstractKeyValueRepositorySqlite::get(const string& key, string& value)
{
try {
SqliteStatement& stmt{stmtSelectOne(key)};
if (!stmt.step()) return false;
value = stmt.columnText(0);
stmt.reset();
return true;
}
catch (const SqliteError& err) {
Logger::error(err.what());
return false;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool AbstractKeyValueRepositorySqlite::save(const std::map<string, Variant>& values)
{

View File

@ -6,10 +6,14 @@
#include "SqliteDatabase.hxx"
#include "SqliteStatement.hxx"
class AbstractKeyValueRepositorySqlite : public KeyValueRepository
class AbstractKeyValueRepositorySqlite : public KeyValueRepositoryAtomic
{
public:
bool has(const string& key) override;
bool get(const string& key, string& value) override;
std::map<string, Variant> load() override;
bool save(const std::map<string, Variant>& values) override;
@ -23,6 +27,8 @@ class AbstractKeyValueRepositorySqlite : public KeyValueRepository
virtual SqliteStatement& stmtInsert(const string& key, const string& value) = 0;
virtual SqliteStatement& stmtSelect() = 0;
virtual SqliteStatement& stmtDelete(const string& key) = 0;
virtual SqliteStatement& stmtCount(const string& key) = 0;
virtual SqliteStatement& stmtSelectOne(const string& key) = 0;
virtual SqliteDatabase& database() = 0;
};

View File

@ -35,15 +35,15 @@ shared_ptr<KeyValueRepository> CompositeKeyValueRepositorySqlite::get(const stri
bool CompositeKeyValueRepositorySqlite::has(const string& key)
{
try {
myStmtCount->reset();
myStmtCount->bind(1, key.c_str());
myStmtCountSet->reset();
myStmtCountSet->bind(1, key.c_str());
if (!myStmtCount->step())
if (!myStmtCountSet->step())
throw new SqliteError("count failed");
Int32 rowCount = myStmtCount->columnInt(0);
Int32 rowCount = myStmtCountSet->columnInt(0);
myStmtCount->reset();
myStmtCountSet->reset();
return rowCount > 0;
} catch (const SqliteError& err) {
@ -78,9 +78,11 @@ void CompositeKeyValueRepositorySqlite::initialize()
myStmtInsert = make_unique<SqliteStatement>(myDb, "INSERT OR REPLACE INTO `" + myTableName + "` VALUES (?, ?, ?)");
myStmtSelect = make_unique<SqliteStatement>(myDb, "SELECT `key2`, `VALUE` FROM `" + myTableName + "` WHERE `key1` = ?");
myStmtCount = make_unique<SqliteStatement>(myDb, "SELECT COUNT(*) FROM `" + myTableName + "` WHERE `key1` = ?");
myStmtCountSet = make_unique<SqliteStatement>(myDb, "SELECT COUNT(*) FROM `" + myTableName + "` WHERE `key1` = ?");
myStmtDelete = make_unique<SqliteStatement>(myDb, "DELETE FROM `" + myTableName + "` WHERE `key1` = ? AND `key2` = ?");
myStmtDeleteSet = make_unique<SqliteStatement>(myDb, "DELETE FROM `" + myTableName + "` WHERE `key1` = ?");
myStmtSelectOne = make_unique<SqliteStatement>(myDb, "SELECT `value` FROM `" + myTableName + "` WHERE `key1` = ? AND `key2` = ?");
myStmtCount = make_unique<SqliteStatement>(myDb, "SELECT COUNT(`key1`) FROM `" + myTableName + "` WHERE `key1` = ? AND `key2` = ?");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -121,6 +123,25 @@ SqliteStatement& CompositeKeyValueRepositorySqlite::ProxyRepository::stmtDelete(
.bind(2, key.c_str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SqliteStatement& CompositeKeyValueRepositorySqlite::ProxyRepository::stmtSelectOne(const string& key)
{
myRepo.myStmtSelectOne->reset();
return (*myRepo.myStmtSelectOne)
.bind(1, myKey.c_str())
.bind(2, key.c_str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SqliteStatement& CompositeKeyValueRepositorySqlite::ProxyRepository::stmtCount(const string& key)
{
myRepo.myStmtCount->reset();
return (*myRepo.myStmtCount)
.bind(1, myKey.c_str())
.bind(2, key.c_str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SqliteDatabase& CompositeKeyValueRepositorySqlite::ProxyRepository::database()

View File

@ -49,6 +49,8 @@ class CompositeKeyValueRepositorySqlite : public CompositeKeyValueRepository {
SqliteStatement& stmtInsert(const string& key, const string& value) override;
SqliteStatement& stmtSelect() override;
SqliteStatement& stmtDelete(const string& key) override;
SqliteStatement& stmtCount(const string& key) override;
SqliteStatement& stmtSelectOne(const string& key) override;
SqliteDatabase& database() override;
private:
@ -71,9 +73,11 @@ class CompositeKeyValueRepositorySqlite : public CompositeKeyValueRepository {
unique_ptr<SqliteStatement> myStmtInsert;
unique_ptr<SqliteStatement> myStmtSelect;
unique_ptr<SqliteStatement> myStmtCount;
unique_ptr<SqliteStatement> myStmtCountSet;
unique_ptr<SqliteStatement> myStmtDelete;
unique_ptr<SqliteStatement> myStmtDeleteSet;
unique_ptr<SqliteStatement> myStmtSelectOne;
unique_ptr<SqliteStatement> myStmtCount;
private:

View File

@ -53,6 +53,24 @@ SqliteStatement& KeyValueRepositorySqlite::stmtDelete(const string& key)
.bind(1, key.c_str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SqliteStatement& KeyValueRepositorySqlite::stmtCount(const string& key)
{
myStmtCount->reset();
return (*myStmtCount)
.bind(1, key.c_str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SqliteStatement& KeyValueRepositorySqlite::stmtSelectOne(const string& key)
{
myStmtSelectOne->reset();
return (*myStmtSelectOne)
.bind(1, key.c_str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SqliteDatabase& KeyValueRepositorySqlite::database()
{
@ -67,6 +85,8 @@ void KeyValueRepositorySqlite::initialize()
);
myStmtInsert = make_unique<SqliteStatement>(myDb, "INSERT OR REPLACE INTO `" + myTableName + "` VALUES (?, ?)");
myStmtSelect = make_unique<SqliteStatement>(myDb, "SELECT `key`, `VALUE` FROM `" + myTableName + "`");
myStmtSelect = make_unique<SqliteStatement>(myDb, "SELECT `key`, `value` FROM `" + myTableName + "`");
myStmtDelete = make_unique<SqliteStatement>(myDb, "DELETE FROM `" + myTableName + "` WHERE `key` = ?");
myStmtSelectOne = make_unique<SqliteStatement>(myDb, "SELECT `value` FROM `" + myTableName + "` WHERE `key` = ?");
myStmtCount = make_unique<SqliteStatement>(myDb, "SELECT COUNT(`key`) FROM `" + myTableName + "` WHERE `key` = ?");
}

View File

@ -37,6 +37,8 @@ class KeyValueRepositorySqlite : public AbstractKeyValueRepositorySqlite
SqliteStatement& stmtSelect() override;
SqliteStatement& stmtDelete(const string& key) override;
SqliteDatabase& database() override;
SqliteStatement& stmtCount(const string& key) override;
SqliteStatement& stmtSelectOne(const string& key) override;
private:
@ -46,6 +48,8 @@ class KeyValueRepositorySqlite : public AbstractKeyValueRepositorySqlite
unique_ptr<SqliteStatement> myStmtInsert;
unique_ptr<SqliteStatement> myStmtSelect;
unique_ptr<SqliteStatement> myStmtDelete;
unique_ptr<SqliteStatement> myStmtSelectOne;
unique_ptr<SqliteStatement> myStmtCount;
private:

View File

@ -36,8 +36,10 @@ bool SettingsDb::initialize()
mySettingsRepository = make_unique<KeyValueRepositorySqlite>(*myDb, "settings");
mySettingsRepository->initialize();
myPropertyRepository = make_unique<CompositeKeyValueRepositorySqlite>(*myDb, "properties");
myPropertyRepository->initialize();
myPropertyRepositoryHost = make_unique<KeyValueRepositorySqlite>(*myDb, "properties");
myPropertyRepositoryHost->initialize();
myPropertyRepository = make_unique<CompositeKVRJsonAdapter>(*myPropertyRepositoryHost);
}
catch (const SqliteError& err) {
Logger::error("sqlite DB " + databaseFileName() + " failed to initialize: " + err.what());

View File

@ -21,7 +21,7 @@
#include "bspf.hxx"
#include "SqliteDatabase.hxx"
#include "KeyValueRepositorySqlite.hxx"
#include "CompositeKeyValueRepositorySqlite.hxx"
#include "repository/CompositeKVRJsonAdapter.hxx"
class SettingsDb
{
@ -44,7 +44,8 @@ class SettingsDb
shared_ptr<SqliteDatabase> myDb;
unique_ptr<KeyValueRepositorySqlite> mySettingsRepository;
unique_ptr<CompositeKeyValueRepositorySqlite> myPropertyRepository;
unique_ptr<KeyValueRepositorySqlite> myPropertyRepositoryHost;
unique_ptr<CompositeKVRJsonAdapter> myPropertyRepository;
};
#endif // SETTINGS_DB_HXX

View File

@ -50,11 +50,12 @@ bool Properties::save(KeyValueRepository& repo) const
std::map<string, Variant> props;
for (size_t i = 0; i < static_cast<size_t>(PropType::NumTypes); i++) {
if (myProperties[i] == ourDefaultProperties[i])
repo.remove(ourPropertyNames[i]);
else
if (myProperties[i] == ourDefaultProperties[i]) {
if (repo.atomic()) repo.atomic()->remove(ourPropertyNames[i]);
} else {
props[ourPropertyNames[i]] = myProperties[i];
}
}
return repo.save(props);
}

View File

@ -717,7 +717,7 @@ void Settings::setValue(const string& key, const Variant& value, bool persist)
{
auto it = myPermanentSettings.find(key);
if(it != myPermanentSettings.end()) {
if (persist && it->second != value) myRespository->save(key, value);
if (persist && it->second != value && myRespository->atomic()) myRespository->atomic()->save(key, value);
it->second = value;
}
else
@ -760,5 +760,6 @@ void Settings::migrate()
{
while (getInt(SETTINGS_VERSION_KEY) < SETTINGS_VERSION) migrateOne();
myRespository->save(SETTINGS_VERSION_KEY, SETTINGS_VERSION);
if (myRespository->atomic())
myRespository->atomic()->save(SETTINGS_VERSION_KEY, SETTINGS_VERSION);
}