diff --git a/inc/lektor/database.h b/inc/lektor/database.h index afeb3466582317adb50a478896eeb20a0831f3a6..b12c6d85a30d0e53073effa7417da0ac22a624bd 100644 --- a/inc/lektor/database.h +++ b/inc/lektor/database.h @@ -103,6 +103,14 @@ bool database_queue_shuffle(lkt_db *db); bool database_queue_seekid (lkt_db *db, int id, int *out_pos); bool database_queue_dump (lkt_db *db, const char *plt_name); +/* Add multiple IDs at once to the queue. The `int *` is the pointy thing that + * STB returns to you. Be warned that all the queries will be done 10 per 10, + * so if you do an add with 100 items, it will do 10 requests. + * The function returns `true` if the adds where successfull, `false` if any + * error occured. + * TODO: Add a way to manually set the step count. */ +bool database_queue_multi_add_id(lkt_db *, size_t *ids_stb_list, int priority); + /* Control the playing state of the queue. */ bool database_queue_toggle_pause(lkt_db *db); bool database_queue_play (lkt_db *db, int pos); diff --git a/src/database/queue.c b/src/database/queue.c index 37752828f019a3b129ce90e9e64809b46f71e5d4..7597775e5fe0246319b5c8fca4c25eca3dd68653 100644 --- a/src/database/queue.c +++ b/src/database/queue.c @@ -1,6 +1,7 @@ #include <lektor/common.h> #include <lektor/database.h> #include <lektor/internal/dbmacro.h> +#include <lektor/stb/ds.h> #define sqlite_just_exec(func, query) \ bool func(lkt_db *db) \ @@ -1089,3 +1090,67 @@ error: sqlite3_finalize(stmt); return ret; } + +bool +database_queue_multi_add_id(lkt_db *db, size_t *ids, int priority) +{ + if (ids == NULL) { + LOG_ERROR("DB", "Can't add a list of IDs to the queue when the list's pointer is NULL"); + return false; + } + if ((priority < 1) || (priority > 5)) { + LOG_ERROR("DB", "The priority must be between 1 and 5, here it is %d", priority); + return false; + } + + static const int ADD_STEP = 10; /* TODO: Let the user specify that thing */ + static const char *SQL_STMT_TEMPLATE = + "INSERT INTO queue (kara_id, priority)" + " SELECT kara.id, %d" /* The priority */ + " FROM kara WHERE kara.id IN (%s)" /* The list of ids, comma-separated */ + ";"; + + const size_t ids_len = arrlenu(ids); + size_t id_index = 0; + char SQL_STMT[LKT_MAX_SQLITE_STATEMENT]; /* The formated query to add things to the queue */ + char IDS_LIST[LKT_LINE_MAX]; /* The thing that will hold the formated comma-separated list of ids */ + + SQLITE_BEGIN_TRANSATION(db, error); + + while (id_index < ids_len) { + const size_t remaining = MAX(ids_len - id_index, ADD_STEP); + size_t index_in_id_string = 0; + + /* We should not enter in here, but it's fine if we do... */ + if (remaining == 0) { + LOG_WARN("DB", "Don't add any more IDs because none are remaining"); + break; + } + + for (/* Nothing */; id_index < (id_index + remaining); ++id_index) { + void *const addr = &(IDS_LIST[index_in_id_string]); + const size_t max_size = LKT_LINE_MAX - 1 - index_in_id_string; + const int added = safe_snprintf(addr, max_size, "%zu,", ids[id_index]); + if (added <= 0) { + /* Ouups... */ + LOG_FATAL("Failed to concatenate something to the list string, " + "partial state is: %s", + IDS_LIST); + } + index_in_id_string += (size_t)added; + } + + /* Delete the last comma */ + IDS_LIST[index_in_id_string - 1] = '\0'; + safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL_STMT_TEMPLATE, priority, IDS_LIST); + SQLITE_EXEC(db, SQL_STMT, error); + } + + reorder(db, priority, error); + SQLITE_END_TRANSATION(db, error); + return true; + +error: + SQLITE_DO_ROLLBACK(db); + return false; +}