From 03a60d9efcd03948ac0cd108f3e44a487daeefd0 Mon Sep 17 00:00:00 2001 From: Kubat <mael.martin31@gmail.com> Date: Fri, 10 Apr 2020 16:08:11 +0200 Subject: [PATCH] Adding functions to manipulate stickers in DB --- inc/lektor/database.h | 11 ++ meson.build | 1 + src/commands.c | 3 +- src/database/stickers.c | 232 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 src/database/stickers.c diff --git a/inc/lektor/database.h b/inc/lektor/database.h index 26cda41e..d5632e3c 100644 --- a/inc/lektor/database.h +++ b/inc/lektor/database.h @@ -124,3 +124,14 @@ bool database_plt_add_uri(sqlite3 *db, const char *name, struct lkt_uri_t *uri); /* User control, yeah, MPD authentification sucks. */ bool database_user_authentificate(sqlite3 *db, const char *password); bool database_user_add(sqlite3 *db, const char *username, const char *password); + +/* Stickers manipulations. */ +typedef bool (*database_sticker_callback_t)(void *args, const char *sticker, const char *type, + int uri, int value); + +bool database_sticker_create(sqlite3 *db, const char *name); +bool database_sticker_delete(sqlite3 *db, const char *name); +bool database_sticker_list(sqlite3 *db, const char *type, void *args, database_sticker_callback_t call); +bool database_sticker_set(sqlite3 *db, const char *type, const char *name, int uri, int value); +bool database_sticker_get(sqlite3 *db, const char *type, const char *name, int uri, void *args, + database_sticker_callback_t call); diff --git a/meson.build b/meson.build index bf5f440b..d2a9b131 100644 --- a/meson.build +++ b/meson.build @@ -26,6 +26,7 @@ dep_mpv = dependency('mpv', required : false) core_sources = [ 'src/mkv/bufferfd.c' , 'src/mkv/write.c' , 'src/commands.c' + , 'src/database/stickers.c' , 'src/database/open.c' , 'src/database/queue.c' , 'src/database/update.c' diff --git a/src/commands.c b/src/commands.c index 9ba427ff..23792ffc 100644 --- a/src/commands.c +++ b/src/commands.c @@ -251,7 +251,8 @@ command_stop(sqlite3 *db, struct lkt_win *win, enum mpd_idle_flag *watch_mask_pt } bool -command_add(sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], enum mpd_idle_flag *watch_mask_ptr) +command_add(sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], + enum mpd_idle_flag *watch_mask_ptr) { if (args == NULL) { fprintf(stderr, " ! command_add: invalid NULL arguments\n"); diff --git a/src/database/stickers.c b/src/database/stickers.c new file mode 100644 index 00000000..0100955c --- /dev/null +++ b/src/database/stickers.c @@ -0,0 +1,232 @@ +#define _POSIX_C_SOURCE 200809L + +#include <lektor/macro.h> +#include <lektor/database.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <stdio.h> + +bool +database_sticker_create(sqlite3 *db, const char *name) +{ + static const char *INSERT = + "WITH id_max (id) AS (SELECT MAX(id) FROM 'stickers')" + "INSERT INTO 'stickers' (id, name)" + " SELECT" + " CASE WHEN id_max.id IS NULL THEN 1 ELSE id_max.id + 1 END," + " ?" + " FROM id_max" + "WHERE NOT EXISTS (SELECT 1 FROM 'stickers' WHERE name = ?);"; + sqlite3_stmt *stmt; + int ret = false; + + if (strlen(name) == 0) { + fprintf(stderr, " ! database_sticker_create: A sticker name must be at least one character long\n"); + return ret; + } + + SQLITE_PREPARE(db, stmt, INSERT, error); + SQLITE_BIND_TEXT(db, stmt, 1, name, error); + SQLITE_BIND_TEXT(db, stmt, 2, name, error); + + if (sqlite3_step(stmt) != SQLITE_OK) { + fprintf(stderr, " ! database_sticker_create: Failed to create sticker '%s': %s\n", + name, sqlite3_errmsg(db)); + goto error; + } + + ret = true; +error: + sqlite3_finalize(stmt); + return ret; +} + +bool +database_sticker_delete(sqlite3 *db, const char *name) +{ + static const char *INSERT = + "DELETE FROM 'stickers' WHERE name = ?;"; + sqlite3_stmt *stmt; + int ret = false; + + if (strlen(name) == 0) { + fprintf(stderr, " ! database_sticker_delete: A sticker name must be at least one character long\n"); + return ret; + } + + SQLITE_PREPARE(db, stmt, INSERT, error); + SQLITE_BIND_TEXT(db, stmt, 1, name, error); + + if (sqlite3_step(stmt) != SQLITE_OK) { + fprintf(stderr, " ! database_sticker_delete: Failed to delete sticker '%s': %s\n", + name, sqlite3_errmsg(db)); + goto error; + } + + ret = true; +error: + sqlite3_finalize(stmt); + return ret; +} + +bool +database_sticker_list(sqlite3 *db, const char *type, void *args, + database_sticker_callback_t call) +{ + const char *SQL = NULL; + int ret = false, uri, value; + sqlite3_stmt *stmt; + const char *sticker; + + if (type == NULL) + SQL = + "SELECT name, sts.id, value FROM 'stickers' LEFT OUTER JOIN " + "( SELECT id, sticker, value FROM 'stickers.song'" + " UNION" + " SELECT id, sticker, value FROM 'stickers.plt'" + ") AS sts" + "ON sts.sticker = 'stickers'.id;"; + else if (!strcasecmp(type, "plt")) + SQL = + "SELECT name, 'stickers.plt'.id, value " + "FROM 'stickers' " + "LEFT OUTER JOIN 'stickers' " + "ON 'stickers'.id = 'stickers.plt'.sticker;"; + else if (!strcasecmp(type, "song")) + SQL = + "SELECT name, 'stickers.song'.id, value " + "FROM 'stickers' " + "LEFT OUTER JOIN 'stickers' " + "ON 'stickers'.id = 'stickers.song'.sticker;"; + else { + fprintf(stderr, " . database_sticker_list: type '%s' is invalid\n", type); + return false; + } + + SQLITE_PREPARE(db, stmt, SQL, error); + + for (;;) { + switch (sqlite3_step(stmt)) { + case SQLITE_ROW: + sticker = (const char *) sqlite3_column_text(stmt, 0); + uri = sqlite3_column_int(stmt, 1); + value = sqlite3_column_int(stmt, 2); + if (!call(args, sticker, type, uri, value)) + goto error; + continue; + + case SQLITE_DONE: + goto end_loop; + + default: + goto error; + } + } + +end_loop: + ret = true; +error: + sqlite3_finalize(stmt); + return ret; +} + +bool +database_sticker_set(sqlite3 *db, const char *type, const char *name, int uri, int value) +{ + const char *SQL = NULL; + sqlite3_stmt *stmt; + int ret = false; + + /* Bindings: + * 1 -> the uri of the plalist or kara + * 2 -> the value of the sticker + * 3 -> the name of the sticker + */ + + if (!strcasecmp(type, "song")) + SQL = + "INSERT OR REPLACE INTO 'stickers.song' (id, sticker, value) " + "SELECT ?, 'stickers'.id, ? " + "FROM 'stickers'" + "WHERE 'stickers'.id = ?;\n"; + else if (!strcasecmp(type, "song")) + SQL = + "INSERT OR REPLACE INTO 'stickers.plt' (id, sticker, value) " + "SELECT ?, 'stickers'.id, ? " + "FROM 'stickers'" + "WHERE 'stickers'.id = ?;\n"; + else { + fprintf(stderr, " . database_sticker_set: Type '%s' is invalid\n", type); + return false; + } + + SQLITE_PREPARE(db, stmt, SQL, error); + SQLITE_BIND_INT(db, stmt, 1, uri, error); + SQLITE_BIND_INT(db, stmt, 2, value, error); + SQLITE_BIND_TEXT(db, stmt, 3, name, error); + + if (sqlite3_step(stmt) != SQLITE_OK) { + fprintf(stderr, " ! database_sticker_set: Failed to update or set sticker '%s' for " + "'%s' %d: %s\n", name, type, uri, sqlite3_errmsg(db)); + goto error; + } + + ret = true; +error: + sqlite3_finalize(stmt); + return ret; +} + +bool +database_sticker_get(sqlite3 *db, const char *type, const char *name, int uri, void *args, + database_sticker_callback_t call) +{ + const char *SQL = NULL; + sqlite3_stmt *stmt; + int ret = false, value; + + if (!strcasecmp(type, "song")) + SQL = + "SELECT value " + "FROM 'stickers' " + "JOIN 'stickers.song'" + " ON 'stickers'.id = 'stickers.song'.sticker" + " AND 'stickers'.name = ?;\n"; + else if (!strcasecmp(type, "song")) + SQL = + "SELECT value " + "FROM 'stickers' " + "JOIN 'stickers.song'" + " ON 'stickers'.id = 'stickers.song'.sticker" + " AND 'stickers'.name = ?;\n"; + else { + fprintf(stderr, " . database_sticker_get: Type '%s' is invalid\n", type); + return false; + } + + SQLITE_PREPARE(db, stmt, SQL, error); + SQLITE_BIND_TEXT(db, stmt, 1, name, error); + + for (;;) { + switch (sqlite3_step(stmt)) { + case SQLITE_ROW: + value = sqlite3_column_int(stmt, 1); + if (!call(args, name, type, uri, value)) + goto error; + continue; + + case SQLITE_DONE: + goto end_loop; + + default: + goto error; + } + } + +end_loop: + ret = true; +error: + sqlite3_finalize(stmt); + return ret; +} -- GitLab