From 96ed6f8f349274d9b5c20af546ca4023d4f20293 Mon Sep 17 00:00:00 2001
From: Kubat <mael.martin31@gmail.com>
Date: Sat, 13 Nov 2021 17:02:19 +0100
Subject: [PATCH] DB: first implementation of the database_queue_multi_add_id
 function

---
 inc/lektor/database.h |  8 ++++++
 src/database/queue.c  | 65 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+)

diff --git a/inc/lektor/database.h b/inc/lektor/database.h
index afeb3466..b12c6d85 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 37752828..7597775e 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;
+}
-- 
GitLab