sticker/Database: wrap in class StickerDatabase
This commit is contained in:
parent
c88d5616f7
commit
77c9081f78
@ -107,9 +107,9 @@ Instance::OnDatabaseSongRemoved(const char *uri) noexcept
|
|||||||
|
|
||||||
#ifdef ENABLE_SQLITE
|
#ifdef ENABLE_SQLITE
|
||||||
/* if the song has a sticker, remove it */
|
/* if the song has a sticker, remove it */
|
||||||
if (sticker_enabled()) {
|
if (HasStickerDatabase()) {
|
||||||
try {
|
try {
|
||||||
sticker_song_delete(uri);
|
sticker_song_delete(*sticker_database, uri);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@ class ClientList;
|
|||||||
struct Partition;
|
struct Partition;
|
||||||
class StateFile;
|
class StateFile;
|
||||||
class RemoteTagCache;
|
class RemoteTagCache;
|
||||||
|
class StickerDatabase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A utility class which, when used as the first base class, ensures
|
* A utility class which, when used as the first base class, ensures
|
||||||
@ -125,6 +126,10 @@ struct Instance final
|
|||||||
|
|
||||||
StateFile *state_file = nullptr;
|
StateFile *state_file = nullptr;
|
||||||
|
|
||||||
|
#ifdef ENABLE_SQLITE
|
||||||
|
std::unique_ptr<StickerDatabase> sticker_database;
|
||||||
|
#endif
|
||||||
|
|
||||||
Instance();
|
Instance();
|
||||||
~Instance() noexcept;
|
~Instance() noexcept;
|
||||||
|
|
||||||
@ -166,6 +171,12 @@ struct Instance final
|
|||||||
const Database &GetDatabaseOrThrow() const;
|
const Database &GetDatabaseOrThrow() const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_SQLITE
|
||||||
|
bool HasStickerDatabase() noexcept {
|
||||||
|
return sticker_database != nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void BeginShutdownUpdate() noexcept;
|
void BeginShutdownUpdate() noexcept;
|
||||||
|
|
||||||
#ifdef ENABLE_CURL
|
#ifdef ENABLE_CURL
|
||||||
|
24
src/Main.cxx
24
src/Main.cxx
@ -237,23 +237,23 @@ InitDatabaseAndStorage(const ConfigData &config)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_SQLITE
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure and initialize the sticker subsystem.
|
* Configure and initialize the sticker subsystem.
|
||||||
*/
|
*/
|
||||||
static void
|
static std::unique_ptr<StickerDatabase>
|
||||||
glue_sticker_init(const ConfigData &config)
|
LoadStickerDatabase(const ConfigData &config)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_SQLITE
|
|
||||||
auto sticker_file = config.GetPath(ConfigOption::STICKER_FILE);
|
auto sticker_file = config.GetPath(ConfigOption::STICKER_FILE);
|
||||||
if (sticker_file.IsNull())
|
if (sticker_file.IsNull())
|
||||||
return;
|
return nullptr;
|
||||||
|
|
||||||
sticker_global_init(std::move(sticker_file));
|
return std::make_unique<StickerDatabase>(std::move(sticker_file));
|
||||||
#else
|
|
||||||
(void)config;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
glue_state_file_init(const ConfigData &raw_config)
|
glue_state_file_init(const ConfigData &raw_config)
|
||||||
{
|
{
|
||||||
@ -513,7 +513,9 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
|
|||||||
const bool create_db = InitDatabaseAndStorage(raw_config);
|
const bool create_db = InitDatabaseAndStorage(raw_config);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
glue_sticker_init(raw_config);
|
#ifdef ENABLE_SQLITE
|
||||||
|
instance->sticker_database = LoadStickerDatabase(raw_config);
|
||||||
|
#endif
|
||||||
|
|
||||||
command_init();
|
command_init();
|
||||||
|
|
||||||
@ -625,10 +627,6 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_SQLITE
|
|
||||||
sticker_global_finish();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include "Permission.hxx"
|
#include "Permission.hxx"
|
||||||
#include "tag/Type.h"
|
#include "tag/Type.h"
|
||||||
#include "Partition.hxx"
|
#include "Partition.hxx"
|
||||||
|
#include "Instance.hxx"
|
||||||
#include "client/Client.hxx"
|
#include "client/Client.hxx"
|
||||||
#include "client/Response.hxx"
|
#include "client/Response.hxx"
|
||||||
#include "util/Macros.hxx"
|
#include "util/Macros.hxx"
|
||||||
@ -216,7 +217,7 @@ command_available(gcc_unused const Partition &partition,
|
|||||||
{
|
{
|
||||||
#ifdef ENABLE_SQLITE
|
#ifdef ENABLE_SQLITE
|
||||||
if (StringIsEqual(cmd->cmd, "sticker"))
|
if (StringIsEqual(cmd->cmd, "sticker"))
|
||||||
return sticker_enabled();
|
return partition.instance.HasStickerDatabase();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "client/Client.hxx"
|
#include "client/Client.hxx"
|
||||||
#include "client/Response.hxx"
|
#include "client/Response.hxx"
|
||||||
#include "Partition.hxx"
|
#include "Partition.hxx"
|
||||||
|
#include "Instance.hxx"
|
||||||
#include "util/StringAPI.hxx"
|
#include "util/StringAPI.hxx"
|
||||||
#include "util/ScopeExit.hxx"
|
#include "util/ScopeExit.hxx"
|
||||||
|
|
||||||
@ -50,7 +51,9 @@ sticker_song_find_print_cb(const LightSong &song, const char *value,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static CommandResult
|
static CommandResult
|
||||||
handle_sticker_song(Response &r, Partition &partition, Request args)
|
handle_sticker_song(Response &r, Partition &partition,
|
||||||
|
StickerDatabase &sticker_database,
|
||||||
|
Request args)
|
||||||
{
|
{
|
||||||
const Database &db = partition.GetDatabaseOrThrow();
|
const Database &db = partition.GetDatabaseOrThrow();
|
||||||
|
|
||||||
@ -62,7 +65,8 @@ handle_sticker_song(Response &r, Partition &partition, Request args)
|
|||||||
assert(song != nullptr);
|
assert(song != nullptr);
|
||||||
AtScopeExit(&db, song) { db.ReturnSong(song); };
|
AtScopeExit(&db, song) { db.ReturnSong(song); };
|
||||||
|
|
||||||
const auto value = sticker_song_get_value(*song, args[3]);
|
const auto value = sticker_song_get_value(sticker_database,
|
||||||
|
*song, args[3]);
|
||||||
if (value.empty()) {
|
if (value.empty()) {
|
||||||
r.Error(ACK_ERROR_NO_EXIST, "no such sticker");
|
r.Error(ACK_ERROR_NO_EXIST, "no such sticker");
|
||||||
return CommandResult::ERROR;
|
return CommandResult::ERROR;
|
||||||
@ -77,7 +81,7 @@ handle_sticker_song(Response &r, Partition &partition, Request args)
|
|||||||
assert(song != nullptr);
|
assert(song != nullptr);
|
||||||
AtScopeExit(&db, song) { db.ReturnSong(song); };
|
AtScopeExit(&db, song) { db.ReturnSong(song); };
|
||||||
|
|
||||||
const auto sticker = sticker_song_get(*song);
|
const auto sticker = sticker_song_get(sticker_database, *song);
|
||||||
sticker_print(r, sticker);
|
sticker_print(r, sticker);
|
||||||
|
|
||||||
return CommandResult::OK;
|
return CommandResult::OK;
|
||||||
@ -87,7 +91,8 @@ handle_sticker_song(Response &r, Partition &partition, Request args)
|
|||||||
assert(song != nullptr);
|
assert(song != nullptr);
|
||||||
AtScopeExit(&db, song) { db.ReturnSong(song); };
|
AtScopeExit(&db, song) { db.ReturnSong(song); };
|
||||||
|
|
||||||
sticker_song_set_value(*song, args[3], args[4]);
|
sticker_song_set_value(sticker_database, *song,
|
||||||
|
args[3], args[4]);
|
||||||
return CommandResult::OK;
|
return CommandResult::OK;
|
||||||
/* delete song song_id [key] */
|
/* delete song song_id [key] */
|
||||||
} else if ((args.size == 3 || args.size == 4) &&
|
} else if ((args.size == 3 || args.size == 4) &&
|
||||||
@ -97,8 +102,9 @@ handle_sticker_song(Response &r, Partition &partition, Request args)
|
|||||||
AtScopeExit(&db, song) { db.ReturnSong(song); };
|
AtScopeExit(&db, song) { db.ReturnSong(song); };
|
||||||
|
|
||||||
bool ret = args.size == 3
|
bool ret = args.size == 3
|
||||||
? sticker_song_delete(*song)
|
? sticker_song_delete(sticker_database, *song)
|
||||||
: sticker_song_delete_value(*song, args[3]);
|
: sticker_song_delete_value(sticker_database, *song,
|
||||||
|
args[3]);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
r.Error(ACK_ERROR_NO_EXIST, "no such sticker");
|
r.Error(ACK_ERROR_NO_EXIST, "no such sticker");
|
||||||
return CommandResult::ERROR;
|
return CommandResult::ERROR;
|
||||||
@ -138,7 +144,7 @@ handle_sticker_song(Response &r, Partition &partition, Request args)
|
|||||||
args[3],
|
args[3],
|
||||||
};
|
};
|
||||||
|
|
||||||
sticker_song_find(db, base_uri, data.name,
|
sticker_song_find(sticker_database, db, base_uri, data.name,
|
||||||
op, value,
|
op, value,
|
||||||
sticker_song_find_print_cb, &data);
|
sticker_song_find_print_cb, &data);
|
||||||
|
|
||||||
@ -154,13 +160,18 @@ handle_sticker(Client &client, Request args, Response &r)
|
|||||||
{
|
{
|
||||||
assert(args.size >= 3);
|
assert(args.size >= 3);
|
||||||
|
|
||||||
if (!sticker_enabled()) {
|
auto &instance = client.GetInstance();
|
||||||
|
if (!instance.HasStickerDatabase()) {
|
||||||
r.Error(ACK_ERROR_UNKNOWN, "sticker database is disabled");
|
r.Error(ACK_ERROR_UNKNOWN, "sticker database is disabled");
|
||||||
return CommandResult::ERROR;
|
return CommandResult::ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto &sticker_database = *instance.sticker_database;
|
||||||
|
|
||||||
if (StringIsEqual(args[1], "song"))
|
if (StringIsEqual(args[1], "song"))
|
||||||
return handle_sticker_song(r, client.GetPartition(), args);
|
return handle_sticker_song(r, client.GetPartition(),
|
||||||
|
sticker_database,
|
||||||
|
args);
|
||||||
else {
|
else {
|
||||||
r.Error(ACK_ERROR_ARG, "unknown sticker domain");
|
r.Error(ACK_ERROR_ARG, "unknown sticker domain");
|
||||||
return CommandResult::ERROR;
|
return CommandResult::ERROR;
|
||||||
|
@ -41,6 +41,7 @@ enum sticker_sql {
|
|||||||
STICKER_SQL_FIND_VALUE,
|
STICKER_SQL_FIND_VALUE,
|
||||||
STICKER_SQL_FIND_LT,
|
STICKER_SQL_FIND_LT,
|
||||||
STICKER_SQL_FIND_GT,
|
STICKER_SQL_FIND_GT,
|
||||||
|
STICKER_SQL_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *const sticker_sql[] = {
|
static const char *const sticker_sql[] = {
|
||||||
@ -80,11 +81,7 @@ static const char sticker_sql_create[] =
|
|||||||
" sticker_value ON sticker(type, uri, name);"
|
" sticker_value ON sticker(type, uri, name);"
|
||||||
"";
|
"";
|
||||||
|
|
||||||
static sqlite3 *sticker_db;
|
StickerDatabase::StickerDatabase(Path path)
|
||||||
static sqlite3_stmt *sticker_stmt[ARRAY_SIZE(sticker_sql)];
|
|
||||||
|
|
||||||
void
|
|
||||||
sticker_global_init(Path path)
|
|
||||||
{
|
{
|
||||||
assert(!path.IsNull());
|
assert(!path.IsNull());
|
||||||
|
|
||||||
@ -92,20 +89,20 @@ sticker_global_init(Path path)
|
|||||||
|
|
||||||
/* open/create the sqlite database */
|
/* open/create the sqlite database */
|
||||||
|
|
||||||
ret = sqlite3_open(path.c_str(), &sticker_db);
|
ret = sqlite3_open(path.c_str(), &db);
|
||||||
if (ret != SQLITE_OK) {
|
if (ret != SQLITE_OK) {
|
||||||
const std::string utf8 = path.ToUTF8();
|
const std::string utf8 = path.ToUTF8();
|
||||||
throw SqliteError(sticker_db, ret,
|
throw SqliteError(db, ret,
|
||||||
("Failed to open sqlite database '" +
|
("Failed to open sqlite database '" +
|
||||||
utf8 + "'").c_str());
|
utf8 + "'").c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create the table and index */
|
/* create the table and index */
|
||||||
|
|
||||||
ret = sqlite3_exec(sticker_db, sticker_sql_create,
|
ret = sqlite3_exec(db, sticker_sql_create,
|
||||||
nullptr, nullptr, nullptr);
|
nullptr, nullptr, nullptr);
|
||||||
if (ret != SQLITE_OK)
|
if (ret != SQLITE_OK)
|
||||||
throw SqliteError(sticker_db, ret,
|
throw SqliteError(db, ret,
|
||||||
"Failed to create sticker table");
|
"Failed to create sticker table");
|
||||||
|
|
||||||
/* prepare the statements we're going to use */
|
/* prepare the statements we're going to use */
|
||||||
@ -113,38 +110,28 @@ sticker_global_init(Path path)
|
|||||||
for (unsigned i = 0; i < ARRAY_SIZE(sticker_sql); ++i) {
|
for (unsigned i = 0; i < ARRAY_SIZE(sticker_sql); ++i) {
|
||||||
assert(sticker_sql[i] != nullptr);
|
assert(sticker_sql[i] != nullptr);
|
||||||
|
|
||||||
sticker_stmt[i] = Prepare(sticker_db, sticker_sql[i]);
|
stmt[i] = Prepare(db, sticker_sql[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
StickerDatabase::~StickerDatabase() noexcept
|
||||||
sticker_global_finish() noexcept
|
|
||||||
{
|
{
|
||||||
if (sticker_db == nullptr)
|
assert(db != nullptr);
|
||||||
/* not configured */
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < ARRAY_SIZE(sticker_stmt); ++i) {
|
for (unsigned i = 0; i < ARRAY_SIZE(stmt); ++i) {
|
||||||
assert(sticker_stmt[i] != nullptr);
|
assert(stmt[i] != nullptr);
|
||||||
|
|
||||||
sqlite3_finalize(sticker_stmt[i]);
|
sqlite3_finalize(stmt[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3_close(sticker_db);
|
sqlite3_close(db);
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
sticker_enabled() noexcept
|
|
||||||
{
|
|
||||||
return sticker_db != nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
sticker_load_value(const char *type, const char *uri, const char *name)
|
StickerDatabase::LoadValue(const char *type, const char *uri, const char *name)
|
||||||
{
|
{
|
||||||
sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_GET];
|
sqlite3_stmt *const s = stmt[STICKER_SQL_GET];
|
||||||
|
|
||||||
assert(sticker_enabled());
|
|
||||||
assert(type != nullptr);
|
assert(type != nullptr);
|
||||||
assert(uri != nullptr);
|
assert(uri != nullptr);
|
||||||
assert(name != nullptr);
|
assert(name != nullptr);
|
||||||
@ -152,49 +139,48 @@ sticker_load_value(const char *type, const char *uri, const char *name)
|
|||||||
if (StringIsEmpty(name))
|
if (StringIsEmpty(name))
|
||||||
return std::string();
|
return std::string();
|
||||||
|
|
||||||
BindAll(stmt, type, uri, name);
|
BindAll(s, type, uri, name);
|
||||||
|
|
||||||
AtScopeExit(stmt) {
|
AtScopeExit(s) {
|
||||||
sqlite3_reset(stmt);
|
sqlite3_reset(s);
|
||||||
sqlite3_clear_bindings(stmt);
|
sqlite3_clear_bindings(s);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string value;
|
std::string value;
|
||||||
if (ExecuteRow(stmt))
|
if (ExecuteRow(s))
|
||||||
value = (const char*)sqlite3_column_text(stmt, 0);
|
value = (const char*)sqlite3_column_text(s, 0);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
sticker_list_values(std::map<std::string, std::string> &table,
|
StickerDatabase::ListValues(std::map<std::string, std::string> &table,
|
||||||
const char *type, const char *uri)
|
const char *type, const char *uri)
|
||||||
{
|
{
|
||||||
sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_LIST];
|
sqlite3_stmt *const s = stmt[STICKER_SQL_LIST];
|
||||||
|
|
||||||
assert(type != nullptr);
|
assert(type != nullptr);
|
||||||
assert(uri != nullptr);
|
assert(uri != nullptr);
|
||||||
assert(sticker_enabled());
|
|
||||||
|
|
||||||
BindAll(stmt, type, uri);
|
BindAll(s, type, uri);
|
||||||
|
|
||||||
AtScopeExit(stmt) {
|
AtScopeExit(s) {
|
||||||
sqlite3_reset(stmt);
|
sqlite3_reset(s);
|
||||||
sqlite3_clear_bindings(stmt);
|
sqlite3_clear_bindings(s);
|
||||||
};
|
};
|
||||||
|
|
||||||
ExecuteForEach(stmt, [stmt, &table](){
|
ExecuteForEach(s, [s, &table](){
|
||||||
const char *name = (const char *)sqlite3_column_text(stmt, 0);
|
const char *name = (const char *)sqlite3_column_text(s, 0);
|
||||||
const char *value = (const char *)sqlite3_column_text(stmt, 1);
|
const char *value = (const char *)sqlite3_column_text(s, 1);
|
||||||
table.insert(std::make_pair(name, value));
|
table.insert(std::make_pair(name, value));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
bool
|
||||||
sticker_update_value(const char *type, const char *uri,
|
StickerDatabase::UpdateValue(const char *type, const char *uri,
|
||||||
const char *name, const char *value)
|
const char *name, const char *value)
|
||||||
{
|
{
|
||||||
sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_UPDATE];
|
sqlite3_stmt *const s = stmt[STICKER_SQL_UPDATE];
|
||||||
|
|
||||||
assert(type != nullptr);
|
assert(type != nullptr);
|
||||||
assert(uri != nullptr);
|
assert(uri != nullptr);
|
||||||
@ -202,27 +188,25 @@ sticker_update_value(const char *type, const char *uri,
|
|||||||
assert(*name != 0);
|
assert(*name != 0);
|
||||||
assert(value != nullptr);
|
assert(value != nullptr);
|
||||||
|
|
||||||
assert(sticker_enabled());
|
BindAll(s, value, type, uri, name);
|
||||||
|
|
||||||
BindAll(stmt, value, type, uri, name);
|
AtScopeExit(s) {
|
||||||
|
sqlite3_reset(s);
|
||||||
AtScopeExit(stmt) {
|
sqlite3_clear_bindings(s);
|
||||||
sqlite3_reset(stmt);
|
|
||||||
sqlite3_clear_bindings(stmt);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool modified = ExecuteModified(stmt);
|
bool modified = ExecuteModified(s);
|
||||||
|
|
||||||
if (modified)
|
if (modified)
|
||||||
idle_add(IDLE_STICKER);
|
idle_add(IDLE_STICKER);
|
||||||
return modified;
|
return modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
sticker_insert_value(const char *type, const char *uri,
|
StickerDatabase::InsertValue(const char *type, const char *uri,
|
||||||
const char *name, const char *value)
|
const char *name, const char *value)
|
||||||
{
|
{
|
||||||
sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_INSERT];
|
sqlite3_stmt *const s = stmt[STICKER_SQL_INSERT];
|
||||||
|
|
||||||
assert(type != nullptr);
|
assert(type != nullptr);
|
||||||
assert(uri != nullptr);
|
assert(uri != nullptr);
|
||||||
@ -230,24 +214,21 @@ sticker_insert_value(const char *type, const char *uri,
|
|||||||
assert(*name != 0);
|
assert(*name != 0);
|
||||||
assert(value != nullptr);
|
assert(value != nullptr);
|
||||||
|
|
||||||
assert(sticker_enabled());
|
BindAll(s, type, uri, name, value);
|
||||||
|
|
||||||
BindAll(stmt, type, uri, name, value);
|
AtScopeExit(s) {
|
||||||
|
sqlite3_reset(s);
|
||||||
AtScopeExit(stmt) {
|
sqlite3_clear_bindings(s);
|
||||||
sqlite3_reset(stmt);
|
|
||||||
sqlite3_clear_bindings(stmt);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ExecuteCommand(stmt);
|
ExecuteCommand(s);
|
||||||
idle_add(IDLE_STICKER);
|
idle_add(IDLE_STICKER);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sticker_store_value(const char *type, const char *uri,
|
StickerDatabase::StoreValue(const char *type, const char *uri,
|
||||||
const char *name, const char *value)
|
const char *name, const char *value)
|
||||||
{
|
{
|
||||||
assert(sticker_enabled());
|
|
||||||
assert(type != nullptr);
|
assert(type != nullptr);
|
||||||
assert(uri != nullptr);
|
assert(uri != nullptr);
|
||||||
assert(name != nullptr);
|
assert(name != nullptr);
|
||||||
@ -256,67 +237,67 @@ sticker_store_value(const char *type, const char *uri,
|
|||||||
if (StringIsEmpty(name))
|
if (StringIsEmpty(name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!sticker_update_value(type, uri, name, value))
|
if (!UpdateValue(type, uri, name, value))
|
||||||
sticker_insert_value(type, uri, name, value);
|
InsertValue(type, uri, name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sticker_delete(const char *type, const char *uri)
|
StickerDatabase::Delete(const char *type, const char *uri)
|
||||||
{
|
{
|
||||||
sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_DELETE];
|
sqlite3_stmt *const s = stmt[STICKER_SQL_DELETE];
|
||||||
|
|
||||||
assert(sticker_enabled());
|
|
||||||
assert(type != nullptr);
|
assert(type != nullptr);
|
||||||
assert(uri != nullptr);
|
assert(uri != nullptr);
|
||||||
|
|
||||||
BindAll(stmt, type, uri);
|
BindAll(s, type, uri);
|
||||||
|
|
||||||
AtScopeExit(stmt) {
|
AtScopeExit(s) {
|
||||||
sqlite3_reset(stmt);
|
sqlite3_reset(s);
|
||||||
sqlite3_clear_bindings(stmt);
|
sqlite3_clear_bindings(s);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool modified = ExecuteModified(stmt);
|
bool modified = ExecuteModified(s);
|
||||||
if (modified)
|
if (modified)
|
||||||
idle_add(IDLE_STICKER);
|
idle_add(IDLE_STICKER);
|
||||||
return modified;
|
return modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sticker_delete_value(const char *type, const char *uri, const char *name)
|
StickerDatabase::DeleteValue(const char *type, const char *uri,
|
||||||
|
const char *name)
|
||||||
{
|
{
|
||||||
sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_DELETE_VALUE];
|
sqlite3_stmt *const s = stmt[STICKER_SQL_DELETE_VALUE];
|
||||||
|
|
||||||
assert(sticker_enabled());
|
|
||||||
assert(type != nullptr);
|
assert(type != nullptr);
|
||||||
assert(uri != nullptr);
|
assert(uri != nullptr);
|
||||||
|
|
||||||
BindAll(stmt, type, uri, name);
|
BindAll(s, type, uri, name);
|
||||||
|
|
||||||
AtScopeExit(stmt) {
|
AtScopeExit(s) {
|
||||||
sqlite3_reset(stmt);
|
sqlite3_reset(s);
|
||||||
sqlite3_clear_bindings(stmt);
|
sqlite3_clear_bindings(s);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool modified = ExecuteModified(stmt);
|
bool modified = ExecuteModified(s);
|
||||||
if (modified)
|
if (modified)
|
||||||
idle_add(IDLE_STICKER);
|
idle_add(IDLE_STICKER);
|
||||||
return modified;
|
return modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sticker
|
Sticker
|
||||||
sticker_load(const char *type, const char *uri)
|
StickerDatabase::Load(const char *type, const char *uri)
|
||||||
{
|
{
|
||||||
Sticker s;
|
Sticker s;
|
||||||
|
|
||||||
sticker_list_values(s.table, type, uri);
|
ListValues(s.table, type, uri);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static sqlite3_stmt *
|
sqlite3_stmt *
|
||||||
BindFind(const char *type, const char *base_uri, const char *name,
|
StickerDatabase::BindFind(const char *type, const char *base_uri,
|
||||||
StickerOperator op, const char *value)
|
const char *name,
|
||||||
|
StickerOperator op, const char *value)
|
||||||
{
|
{
|
||||||
assert(type != nullptr);
|
assert(type != nullptr);
|
||||||
assert(name != nullptr);
|
assert(name != nullptr);
|
||||||
@ -326,23 +307,23 @@ BindFind(const char *type, const char *base_uri, const char *name,
|
|||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case StickerOperator::EXISTS:
|
case StickerOperator::EXISTS:
|
||||||
BindAll(sticker_stmt[STICKER_SQL_FIND], type, base_uri, name);
|
BindAll(stmt[STICKER_SQL_FIND], type, base_uri, name);
|
||||||
return sticker_stmt[STICKER_SQL_FIND];
|
return stmt[STICKER_SQL_FIND];
|
||||||
|
|
||||||
case StickerOperator::EQUALS:
|
case StickerOperator::EQUALS:
|
||||||
BindAll(sticker_stmt[STICKER_SQL_FIND_VALUE],
|
BindAll(stmt[STICKER_SQL_FIND_VALUE],
|
||||||
type, base_uri, name, value);
|
type, base_uri, name, value);
|
||||||
return sticker_stmt[STICKER_SQL_FIND_VALUE];
|
return stmt[STICKER_SQL_FIND_VALUE];
|
||||||
|
|
||||||
case StickerOperator::LESS_THAN:
|
case StickerOperator::LESS_THAN:
|
||||||
BindAll(sticker_stmt[STICKER_SQL_FIND_LT],
|
BindAll(stmt[STICKER_SQL_FIND_LT],
|
||||||
type, base_uri, name, value);
|
type, base_uri, name, value);
|
||||||
return sticker_stmt[STICKER_SQL_FIND_LT];
|
return stmt[STICKER_SQL_FIND_LT];
|
||||||
|
|
||||||
case StickerOperator::GREATER_THAN:
|
case StickerOperator::GREATER_THAN:
|
||||||
BindAll(sticker_stmt[STICKER_SQL_FIND_GT],
|
BindAll(stmt[STICKER_SQL_FIND_GT],
|
||||||
type, base_uri, name, value);
|
type, base_uri, name, value);
|
||||||
return sticker_stmt[STICKER_SQL_FIND_GT];
|
return stmt[STICKER_SQL_FIND_GT];
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false);
|
assert(false);
|
||||||
@ -350,26 +331,25 @@ BindFind(const char *type, const char *base_uri, const char *name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sticker_find(const char *type, const char *base_uri, const char *name,
|
StickerDatabase::Find(const char *type, const char *base_uri, const char *name,
|
||||||
StickerOperator op, const char *value,
|
StickerOperator op, const char *value,
|
||||||
void (*func)(const char *uri, const char *value,
|
void (*func)(const char *uri, const char *value,
|
||||||
void *user_data),
|
void *user_data),
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
assert(func != nullptr);
|
assert(func != nullptr);
|
||||||
assert(sticker_enabled());
|
|
||||||
|
|
||||||
sqlite3_stmt *const stmt = BindFind(type, base_uri, name, op, value);
|
sqlite3_stmt *const s = BindFind(type, base_uri, name, op, value);
|
||||||
assert(stmt != nullptr);
|
assert(s != nullptr);
|
||||||
|
|
||||||
AtScopeExit(stmt) {
|
AtScopeExit(s) {
|
||||||
sqlite3_reset(stmt);
|
sqlite3_reset(s);
|
||||||
sqlite3_clear_bindings(stmt);
|
sqlite3_clear_bindings(s);
|
||||||
};
|
};
|
||||||
|
|
||||||
ExecuteForEach(stmt, [stmt, func, user_data](){
|
ExecuteForEach(s, [s, func, user_data](){
|
||||||
func((const char*)sqlite3_column_text(stmt, 0),
|
func((const char*)sqlite3_column_text(s, 0),
|
||||||
(const char*)sqlite3_column_text(stmt, 1),
|
(const char*)sqlite3_column_text(s, 1),
|
||||||
user_data);
|
user_data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -45,96 +45,116 @@
|
|||||||
#include "Match.hxx"
|
#include "Match.hxx"
|
||||||
#include "util/Compiler.h"
|
#include "util/Compiler.h"
|
||||||
|
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class Path;
|
class Path;
|
||||||
struct Sticker;
|
struct Sticker;
|
||||||
|
|
||||||
/**
|
class StickerDatabase {
|
||||||
* Opens the sticker database.
|
enum SQL {
|
||||||
*
|
SQL_GET,
|
||||||
* Throws std::runtime_error on error.
|
SQL_LIST,
|
||||||
*/
|
SQL_UPDATE,
|
||||||
void
|
SQL_INSERT,
|
||||||
sticker_global_init(Path path);
|
SQL_DELETE,
|
||||||
|
SQL_DELETE_VALUE,
|
||||||
|
SQL_FIND,
|
||||||
|
SQL_FIND_VALUE,
|
||||||
|
SQL_FIND_LT,
|
||||||
|
SQL_FIND_GT,
|
||||||
|
|
||||||
/**
|
SQL_COUNT
|
||||||
* Close the sticker database.
|
};
|
||||||
*/
|
|
||||||
void
|
|
||||||
sticker_global_finish() noexcept;
|
|
||||||
|
|
||||||
/**
|
sqlite3 *db;
|
||||||
* Returns true if the sticker database is configured and available.
|
sqlite3_stmt *stmt[SQL_COUNT];
|
||||||
*/
|
|
||||||
gcc_const
|
|
||||||
bool
|
|
||||||
sticker_enabled() noexcept;
|
|
||||||
|
|
||||||
/**
|
public:
|
||||||
* Returns one value from an object's sticker record. Returns an
|
/**
|
||||||
* empty string if the value doesn't exist.
|
* Opens the sticker database.
|
||||||
*
|
*
|
||||||
* Throws #SqliteError on error.
|
* Throws on error.
|
||||||
*/
|
*/
|
||||||
std::string
|
StickerDatabase(Path path);
|
||||||
sticker_load_value(const char *type, const char *uri, const char *name);
|
~StickerDatabase() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a sticker value in the specified object. Overwrites existing
|
* Returns one value from an object's sticker record. Returns an
|
||||||
* values.
|
* empty string if the value doesn't exist.
|
||||||
*
|
*
|
||||||
* Throws #SqliteError on error.
|
* Throws #SqliteError on error.
|
||||||
*/
|
*/
|
||||||
void
|
std::string LoadValue(const char *type, const char *uri,
|
||||||
sticker_store_value(const char *type, const char *uri,
|
const char *name);
|
||||||
const char *name, const char *value);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a sticker from the database. All sticker values of the
|
* Sets a sticker value in the specified object. Overwrites existing
|
||||||
* specified object are deleted.
|
* values.
|
||||||
*
|
*
|
||||||
* Throws #SqliteError on error.
|
* Throws #SqliteError on error.
|
||||||
*/
|
*/
|
||||||
bool
|
void StoreValue(const char *type, const char *uri,
|
||||||
sticker_delete(const char *type, const char *uri);
|
const char *name, const char *value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a sticker value. Fails if no sticker with this name
|
* Deletes a sticker from the database. All sticker values of the
|
||||||
* exists.
|
* specified object are deleted.
|
||||||
*
|
*
|
||||||
* Throws #SqliteError on error.
|
* Throws #SqliteError on error.
|
||||||
*/
|
*/
|
||||||
bool
|
bool Delete(const char *type, const char *uri);
|
||||||
sticker_delete_value(const char *type, const char *uri, const char *name);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the sticker for the specified resource.
|
* Deletes a sticker value. Fails if no sticker with this name
|
||||||
*
|
* exists.
|
||||||
* Throws #SqliteError on error.
|
*
|
||||||
*
|
* Throws #SqliteError on error.
|
||||||
* @param type the resource type, e.g. "song"
|
*/
|
||||||
* @param uri the URI of the resource, e.g. the song path
|
bool DeleteValue(const char *type, const char *uri, const char *name);
|
||||||
* @return a sticker object
|
|
||||||
*/
|
|
||||||
Sticker
|
|
||||||
sticker_load(const char *type, const char *uri);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds stickers with the specified name below the specified URI.
|
* Loads the sticker for the specified resource.
|
||||||
*
|
*
|
||||||
* @param type the resource type, e.g. "song"
|
* Throws #SqliteError on error.
|
||||||
* @param base_uri the URI prefix of the resources, or nullptr if all
|
*
|
||||||
* resources should be searched
|
* @param type the resource type, e.g. "song"
|
||||||
* @param name the name of the sticker
|
* @param uri the URI of the resource, e.g. the song path
|
||||||
* @param op the comparison operator
|
* @return a sticker object
|
||||||
* @param value the operand
|
*/
|
||||||
*/
|
Sticker Load(const char *type, const char *uri);
|
||||||
void
|
|
||||||
sticker_find(const char *type, const char *base_uri, const char *name,
|
/**
|
||||||
StickerOperator op, const char *value,
|
* Finds stickers with the specified name below the specified URI.
|
||||||
void (*func)(const char *uri, const char *value,
|
*
|
||||||
void *user_data),
|
* @param type the resource type, e.g. "song"
|
||||||
void *user_data);
|
* @param base_uri the URI prefix of the resources, or nullptr if all
|
||||||
|
* resources should be searched
|
||||||
|
* @param name the name of the sticker
|
||||||
|
* @param op the comparison operator
|
||||||
|
* @param value the operand
|
||||||
|
*/
|
||||||
|
void Find(const char *type, const char *base_uri, const char *name,
|
||||||
|
StickerOperator op, const char *value,
|
||||||
|
void (*func)(const char *uri, const char *value,
|
||||||
|
void *user_data),
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ListValues(std::map<std::string, std::string> &table,
|
||||||
|
const char *type, const char *uri);
|
||||||
|
|
||||||
|
bool UpdateValue(const char *type, const char *uri,
|
||||||
|
const char *name, const char *value);
|
||||||
|
|
||||||
|
void InsertValue(const char *type, const char *uri,
|
||||||
|
const char *name, const char *value);
|
||||||
|
|
||||||
|
sqlite3_stmt *BindFind(const char *type, const char *base_uri,
|
||||||
|
const char *name,
|
||||||
|
StickerOperator op, const char *value);
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -29,44 +29,47 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
sticker_song_get_value(const LightSong &song, const char *name)
|
sticker_song_get_value(StickerDatabase &db,
|
||||||
|
const LightSong &song, const char *name)
|
||||||
{
|
{
|
||||||
const auto uri = song.GetURI();
|
const auto uri = song.GetURI();
|
||||||
return sticker_load_value("song", uri.c_str(), name);
|
return db.LoadValue("song", uri.c_str(), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sticker_song_set_value(const LightSong &song,
|
sticker_song_set_value(StickerDatabase &db,
|
||||||
|
const LightSong &song,
|
||||||
const char *name, const char *value)
|
const char *name, const char *value)
|
||||||
{
|
{
|
||||||
const auto uri = song.GetURI();
|
const auto uri = song.GetURI();
|
||||||
sticker_store_value("song", uri.c_str(), name, value);
|
db.StoreValue("song", uri.c_str(), name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sticker_song_delete(const char *uri)
|
sticker_song_delete(StickerDatabase &db, const char *uri)
|
||||||
{
|
{
|
||||||
return sticker_delete("song", uri);
|
return db.Delete("song", uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sticker_song_delete(const LightSong &song)
|
sticker_song_delete(StickerDatabase &db, const LightSong &song)
|
||||||
{
|
{
|
||||||
return sticker_song_delete(song.GetURI().c_str());
|
return sticker_song_delete(db, song.GetURI().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sticker_song_delete_value(const LightSong &song, const char *name)
|
sticker_song_delete_value(StickerDatabase &db,
|
||||||
|
const LightSong &song, const char *name)
|
||||||
{
|
{
|
||||||
const auto uri = song.GetURI();
|
const auto uri = song.GetURI();
|
||||||
return sticker_delete_value("song", uri.c_str(), name);
|
return db.DeleteValue("song", uri.c_str(), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sticker
|
Sticker
|
||||||
sticker_song_get(const LightSong &song)
|
sticker_song_get(StickerDatabase &db, const LightSong &song)
|
||||||
{
|
{
|
||||||
const auto uri = song.GetURI();
|
const auto uri = song.GetURI();
|
||||||
return sticker_load("song", uri.c_str());
|
return db.Load("song", uri.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -101,7 +104,8 @@ sticker_song_find_cb(const char *uri, const char *value, void *user_data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sticker_song_find(const Database &db, const char *base_uri, const char *name,
|
sticker_song_find(StickerDatabase &sticker_database, const Database &db,
|
||||||
|
const char *base_uri, const char *name,
|
||||||
StickerOperator op, const char *value,
|
StickerOperator op, const char *value,
|
||||||
void (*func)(const LightSong &song, const char *value,
|
void (*func)(const LightSong &song, const char *value,
|
||||||
void *user_data),
|
void *user_data),
|
||||||
@ -126,6 +130,6 @@ sticker_song_find(const Database &db, const char *base_uri, const char *name,
|
|||||||
|
|
||||||
data.base_uri_length = strlen(data.base_uri);
|
data.base_uri_length = strlen(data.base_uri);
|
||||||
|
|
||||||
sticker_find("song", data.base_uri, name, op, value,
|
sticker_database.Find("song", data.base_uri, name, op, value,
|
||||||
sticker_song_find_cb, &data);
|
sticker_song_find_cb, &data);
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
struct LightSong;
|
struct LightSong;
|
||||||
struct Sticker;
|
struct Sticker;
|
||||||
class Database;
|
class Database;
|
||||||
|
class StickerDatabase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns one value from a song's sticker record.
|
* Returns one value from a song's sticker record.
|
||||||
@ -34,7 +35,8 @@ class Database;
|
|||||||
* Throws #SqliteError on error.
|
* Throws #SqliteError on error.
|
||||||
*/
|
*/
|
||||||
std::string
|
std::string
|
||||||
sticker_song_get_value(const LightSong &song, const char *name);
|
sticker_song_get_value(StickerDatabase &db,
|
||||||
|
const LightSong &song, const char *name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a sticker value in the specified song. Overwrites existing
|
* Sets a sticker value in the specified song. Overwrites existing
|
||||||
@ -43,7 +45,8 @@ sticker_song_get_value(const LightSong &song, const char *name);
|
|||||||
* Throws #SqliteError on error.
|
* Throws #SqliteError on error.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
sticker_song_set_value(const LightSong &song,
|
sticker_song_set_value(StickerDatabase &db,
|
||||||
|
const LightSong &song,
|
||||||
const char *name, const char *value);
|
const char *name, const char *value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,10 +55,10 @@ sticker_song_set_value(const LightSong &song,
|
|||||||
* Throws #SqliteError on error.
|
* Throws #SqliteError on error.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
sticker_song_delete(const char *uri);
|
sticker_song_delete(StickerDatabase &db, const char *uri);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sticker_song_delete(const LightSong &song);
|
sticker_song_delete(StickerDatabase &db, const LightSong &song);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a sticker value. Does nothing if the sticker did not
|
* Deletes a sticker value. Does nothing if the sticker did not
|
||||||
@ -64,7 +67,8 @@ sticker_song_delete(const LightSong &song);
|
|||||||
* Throws #SqliteError on error.
|
* Throws #SqliteError on error.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
sticker_song_delete_value(const LightSong &song, const char *name);
|
sticker_song_delete_value(StickerDatabase &db,
|
||||||
|
const LightSong &song, const char *name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the sticker for the specified song.
|
* Loads the sticker for the specified song.
|
||||||
@ -75,7 +79,7 @@ sticker_song_delete_value(const LightSong &song, const char *name);
|
|||||||
* @return a sticker object
|
* @return a sticker object
|
||||||
*/
|
*/
|
||||||
Sticker
|
Sticker
|
||||||
sticker_song_get(const LightSong &song);
|
sticker_song_get(StickerDatabase &db, const LightSong &song);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds stickers with the specified name below the specified
|
* Finds stickers with the specified name below the specified
|
||||||
@ -89,7 +93,8 @@ sticker_song_get(const LightSong &song);
|
|||||||
* @param name the name of the sticker
|
* @param name the name of the sticker
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
sticker_song_find(const Database &db, const char *base_uri, const char *name,
|
sticker_song_find(StickerDatabase &sticker_database, const Database &db,
|
||||||
|
const char *base_uri, const char *name,
|
||||||
StickerOperator op, const char *value,
|
StickerOperator op, const char *value,
|
||||||
void (*func)(const LightSong &song, const char *value,
|
void (*func)(const LightSong &song, const char *value,
|
||||||
void *user_data),
|
void *user_data),
|
||||||
|
Loading…
Reference in New Issue
Block a user