summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2025-10-10 17:07:45 -0400
committerJonathan Bradley <jcb@pikum.xyz>2025-10-10 17:07:45 -0400
commit62dae6011db94dd52c3ac0fce517c6e9cc0abcf6 (patch)
tree1700442c9b6648af7ec8781af0ec92856a93cecd
parentcc8653536c499df4b85aae423ad6b27bb74544be (diff)
pke-at: first-pass storage interface
-rw-r--r--.gitignore1
-rw-r--r--Makefile51
-rw-r--r--config.mk3
-rw-r--r--src/embedded-file.hpp14
-rw-r--r--src/embedded-sql.cpp32
-rw-r--r--src/embedded-sql.hpp10
-rw-r--r--src/pke-at-setlist-types.hpp64
-rw-r--r--src/pke-at-settings.cpp11
-rw-r--r--src/pke-at-settings.hpp7
-rw-r--r--src/pke-at-storage-interface.hpp50
-rw-r--r--src/pke-at-storage-sql.cpp220
-rw-r--r--src/pke-at-storage-sql.hpp23
-rw-r--r--src/pke-at.cpp23
-rw-r--r--src/sql/schema-000-000.sql48
-rw-r--r--src/sql/section_delete.sql3
-rw-r--r--src/sql/section_get.sql1
-rw-r--r--src/sql/section_upsert.sql10
-rw-r--r--src/sql/setlist_delete.sql3
-rw-r--r--src/sql/setlist_get.sql1
-rw-r--r--src/sql/setlist_song_delete.sql3
-rw-r--r--src/sql/setlist_song_get.sql1
-rw-r--r--src/sql/setlist_song_upsert.sql6
-rw-r--r--src/sql/setlist_upsert.sql7
-rw-r--r--src/sql/song_delete.sql3
-rw-r--r--src/sql/song_get.sql1
-rw-r--r--src/sql/song_upsert.sql10
26 files changed, 597 insertions, 9 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2fc1402
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+src/sql/*sql.h
diff --git a/Makefile b/Makefile
index a111866..ac18f45 100644
--- a/Makefile
+++ b/Makefile
@@ -17,6 +17,47 @@ define cxx-command
$(CXX) -std=c++23 -c -o $@ $(BUILD_MODE_FLAGS) $(CXXFLAGS) $(INCS) $<
endef
+define cc-encode-binary-command
+$(1): $(2)
+ xxd -i $$< | sed -e 's/^unsigned /const unsigned /' > $$@
+endef
+
+define cc-pre-compile-header-command
+$(1): $(2)
+ $(CC) -std=c2x -O3 -c $$< -o $$@
+endef
+
+FILES_BIN = \
+ src/sql/schema-000-000.sql \
+ src/sql/section_delete.sql \
+ src/sql/section_get.sql \
+ src/sql/section_upsert.sql \
+ src/sql/setlist_delete.sql \
+ src/sql/setlist_get.sql \
+ src/sql/setlist_upsert.sql \
+ src/sql/setlist_song_delete.sql \
+ src/sql/setlist_song_get.sql \
+ src/sql/setlist_song_upsert.sql \
+ src/sql/song_delete.sql \
+ src/sql/song_get.sql \
+ src/sql/song_upsert.sql \
+
+FILES_BIN_SAFE = $(subst -,_,$(subst .,_,$(FILES_BIN)))
+FILES_BIN_H = $(FILES_BIN_SAFE:%=%.h)
+FILES_BIN_GCH = $(FILES_BIN_SAFE:%=%.gch)
+
+# I don't like foreach but this works
+$(foreach f,$(FILES_BIN), \
+ $(eval \
+ $(call cc-encode-binary-command,$(subst -,_,$(subst .,_,$f)).h,$(f)) \
+ ) \
+)
+$(foreach f,$(FILES_BIN_SAFE), \
+ $(eval \
+ $(call cc-pre-compile-header-command,$(f).gch,$(f).h) \
+ ) \
+)
+
.PHONY: default
default: options .WAIT bin/pke-at
@@ -35,18 +76,21 @@ options: prepare .WAIT
@echo "CC = $(CC)"
@echo "CXX = $(CXX)"
+obj/embedded-sql.o : $(FILES_BIN_GCH)
obj/%.o : src/%.c | prepare
$(cc-command)
obj/%.o : src/%.cpp | prepare
$(cxx-command)
bin/pke-at: ## Builds the pke-at executable
+bin/pke-at: obj/embedded-sql.o
+bin/pke-at: obj/level-main.o
+bin/pke-at: obj/level-init.o
bin/pke-at: obj/main.o
-bin/pke-at: obj/pke-at-settings.o
bin/pke-at: obj/pke-at-common.o
+bin/pke-at: obj/pke-at-settings.o
+bin/pke-at: obj/pke-at-storage-sql.o
bin/pke-at: obj/pke-at.o
-bin/pke-at: obj/level-main.o
-bin/pke-at: obj/level-init.o
$(CXX) -v -std=c++23 $(BUILD_MODE_FLAGS) $(INCS) -Wl,--whole-archive $^ $(LDFLAGS) -Wl,--no-whole-archive $(CXXFLAGS) -o $@
.PHONY: clean
@@ -54,6 +98,7 @@ clean:
rm -rf bin
rm -rf obj
rm -rf *.plist
+ rm -f $(FILES_BIN_H)
.PHONY: help
help: ## Prints help for targets with comments
diff --git a/config.mk b/config.mk
index 34122a9..c3a5794 100644
--- a/config.mk
+++ b/config.mk
@@ -20,7 +20,8 @@ GLSLC = /usr/bin/glslc
# libpipewire-0.3 \
# libspa-0.2 \
-USED_STATIC_LIBS = pke
+USED_STATIC_LIBS = pke \
+ sqlite3
USED_LIBS =
diff --git a/src/embedded-file.hpp b/src/embedded-file.hpp
new file mode 100644
index 0000000..0a86b10
--- /dev/null
+++ b/src/embedded-file.hpp
@@ -0,0 +1,14 @@
+#ifndef PKE_AT_EMBEDDED_FILE_HPP
+#define PKE_AT_EMBEDDED_FILE_HPP
+
+#include <pke/asset-manager.hpp>
+#include <pke/asset-types.h>
+
+struct embedded_file {
+ AssetKey key;
+ const unsigned char *data;
+ const unsigned int size;
+ AssetHandle handle = AssetHandle_MAX;
+};
+
+#endif /* PKE_AT_EMBEDDED_FILE_HPP */
diff --git a/src/embedded-sql.cpp b/src/embedded-sql.cpp
new file mode 100644
index 0000000..16593c4
--- /dev/null
+++ b/src/embedded-sql.cpp
@@ -0,0 +1,32 @@
+
+#include "embedded-sql.hpp"
+
+#include "sql/schema_000_000_sql.h"
+#include "sql/section_delete_sql.h"
+#include "sql/section_get_sql.h"
+#include "sql/section_upsert_sql.h"
+#include "sql/setlist_delete_sql.h"
+#include "sql/setlist_get_sql.h"
+#include "sql/setlist_upsert_sql.h"
+#include "sql/setlist_song_delete_sql.h"
+#include "sql/setlist_song_get_sql.h"
+#include "sql/setlist_song_upsert_sql.h"
+#include "sql/song_delete_sql.h"
+#include "sql/song_get_sql.h"
+#include "sql/song_upsert_sql.h"
+
+struct embedded_file embedded_sql[] = {
+ { "sql_scm_000_000", src_sql_schema_000_000_sql, src_sql_schema_000_000_sql_len },
+ { "sql_sect_del\0\0\0", src_sql_section_delete_sql, src_sql_section_delete_sql_len },
+ { "sql_sect_get\0\0\0", src_sql_section_get_sql, src_sql_section_get_sql_len },
+ { "sql_sect_upsrt\0", src_sql_section_upsert_sql, src_sql_section_upsert_sql_len },
+ { "sql_setl_del\0\0\0", src_sql_setlist_delete_sql, src_sql_setlist_delete_sql_len },
+ { "sql_setl_get\0\0\0", src_sql_setlist_get_sql, src_sql_setlist_get_sql_len },
+ { "sql_setl_upsrt\0", src_sql_setlist_upsert_sql, src_sql_setlist_upsert_sql_len },
+ { "sql_ssng_del\0\0\0", src_sql_setlist_song_delete_sql, src_sql_setlist_song_delete_sql_len },
+ { "sql_ssng_get\0\0\0", src_sql_setlist_song_get_sql, src_sql_setlist_song_get_sql_len },
+ { "sql_ssng_upsrt\0", src_sql_setlist_song_upsert_sql, src_sql_setlist_song_upsert_sql_len },
+ { "sql_song_del\0\0\0", src_sql_song_delete_sql, src_sql_song_delete_sql_len },
+ { "sql_song_get\0\0\0", src_sql_song_get_sql, src_sql_song_get_sql_len },
+ { "sql_song_upsrt\0", src_sql_song_upsert_sql, src_sql_song_upsert_sql_len },
+};
diff --git a/src/embedded-sql.hpp b/src/embedded-sql.hpp
new file mode 100644
index 0000000..af08435
--- /dev/null
+++ b/src/embedded-sql.hpp
@@ -0,0 +1,10 @@
+#ifndef PKE_AT_EMBEDDED_SQL_HPP
+#define PKE_AT_EMBEDDED_SQL_HPP
+
+#include "embedded-file.hpp"
+
+const unsigned long embedded_sql_count = 13;
+
+extern struct embedded_file embedded_sql[];
+
+#endif /* PKE_AT_EMBEDDED_SQL_HPP */
diff --git a/src/pke-at-setlist-types.hpp b/src/pke-at-setlist-types.hpp
new file mode 100644
index 0000000..bea7b18
--- /dev/null
+++ b/src/pke-at-setlist-types.hpp
@@ -0,0 +1,64 @@
+#ifndef PKE_AT_PKE_AT_SETLIST_TYPES_HPP
+#define PKE_AT_PKE_AT_SETLIST_TYPES_HPP
+
+#include <pke/pke.hpp>
+
+enum PKE_AT_SECTION_TYPE_INDEX {
+ PKE_AT_SECTION_TYPE_INDEX_NONE,
+ PKE_AT_SECTION_TYPE_INDEX_VERSE,
+ PKE_AT_SECTION_TYPE_INDEX_CHORUS,
+ PKE_AT_SECTION_TYPE_INDEX_BRIDGE,
+ PKE_AT_SECTION_TYPE_INDEX_INTRO,
+ PKE_AT_SECTION_TYPE_INDEX_OUTRO,
+ PKE_AT_SECTION_TYPE_INDEX_INSTRUMENTAL,
+ PKE_AT_SECTION_TYPE_INDEX_INTERLUDE,
+ PKE_AT_SECTION_TYPE_INDEX_COUNT,
+};
+
+struct pke_at_section_type {
+ enum PKE_AT_SECTION_TYPE_INDEX section_type_index = PKE_AT_SECTION_TYPE_INDEX_NONE;
+ AssetKey title_key;
+ AssetHandle title_handle = AssetHandle_MAX;
+};
+
+struct pke_at_section_details {
+ pk_uuid song_uuid;
+ enum PKE_AT_SECTION_TYPE_INDEX section_type_index = PKE_AT_SECTION_TYPE_INDEX_NONE;
+ uint8_t sequence;
+ uint8_t beats_per_bar = 0;
+ uint8_t bar_count = 0;
+};
+struct pke_at_section {
+ pke_at_section_details details{};
+};
+
+struct pke_at_song_details {
+ pk_uuid uuid;
+ long ccli;
+ pk_cstr title;
+ pk_cstr arrangement;
+ uint8_t bpm;
+};
+struct pke_at_song {
+ struct pke_at_song_details details{};
+ float calculated_delta = 0.f;
+ pk_arr_t<pke_at_section> sections;
+};
+
+struct pke_at_setlist_details {
+ pk_cstr title;
+};
+struct pke_at_setlist {
+ struct pke_at_setlist_details details{};
+ pk_arr_t<pke_at_song> tracks;
+};
+
+struct pke_at_setlist_song_details {
+ pk_uuid setlist_uuid;
+ pk_uuid song_uuid;
+};
+struct pke_at_setlist_song {
+ struct pke_at_setlist_song_details details{};
+};
+
+#endif /* PKE_AT_PKE_AT_SETLIST_TYPES_HPP */
diff --git a/src/pke-at-settings.cpp b/src/pke-at-settings.cpp
index 0f25589..c467a50 100644
--- a/src/pke-at-settings.cpp
+++ b/src/pke-at-settings.cpp
@@ -2,3 +2,14 @@
#include "pke-at-settings.hpp"
struct pke_at_global_settings g_at{};
+
+struct pke_at_section_type g_section_types[] = {
+{ PKE_AT_SECTION_TYPE_INDEX_NONE, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" },
+{ PKE_AT_SECTION_TYPE_INDEX_VERSE, "sectype-verse\0\0" },
+{ PKE_AT_SECTION_TYPE_INDEX_CHORUS, "sectype-chrus\0\0" },
+{ PKE_AT_SECTION_TYPE_INDEX_BRIDGE, "sectype-brdge\0\0" },
+{ PKE_AT_SECTION_TYPE_INDEX_INTRO, "sectype-intro\0\0" },
+{ PKE_AT_SECTION_TYPE_INDEX_OUTRO, "sectype-outro\0\0" },
+{ PKE_AT_SECTION_TYPE_INDEX_INSTRUMENTAL, "sectype-instr\0\0" },
+{ PKE_AT_SECTION_TYPE_INDEX_INTERLUDE, "sectype-intrl\0\0" },
+};
diff --git a/src/pke-at-settings.hpp b/src/pke-at-settings.hpp
index fe4ee1c..dd50532 100644
--- a/src/pke-at-settings.hpp
+++ b/src/pke-at-settings.hpp
@@ -1,8 +1,9 @@
#ifndef PKE_AT_PKE_AT_SETTINGS_HPP
#define PKE_AT_PKE_AT_SETTINGS_HPP
-#include "pke/asset-manager.hpp"
-#include "pke/pk.h"
+#include "pke-at-setlist-types.hpp"
+
+#include <pke/pke.hpp>
#define BEEP_IMMEDIATELY_VAL 99999999.f
@@ -17,6 +18,7 @@ struct pke_at_global_settings {
pk_membucket *bkt;
pk_membucket *bkt_transient;
} mem;
+ struct pke_at_storage_interface *storage;
struct pke_at_global_settings_bpm {
float last;
float target;
@@ -38,5 +40,6 @@ struct pke_at_global_settings {
};
extern struct pke_at_global_settings g_at;
+extern struct pke_at_section_type g_section_types[];
#endif /* PKE_AT_PKE_AT_SETTINGS_HPP */
diff --git a/src/pke-at-storage-interface.hpp b/src/pke-at-storage-interface.hpp
new file mode 100644
index 0000000..f240974
--- /dev/null
+++ b/src/pke-at-storage-interface.hpp
@@ -0,0 +1,50 @@
+#ifndef PKE_AT_PKE_AT_STORAGE_INTERFACE_HPP
+#define PKE_AT_PKE_AT_STORAGE_INTERFACE_HPP
+
+#include "pke-at-setlist-types.hpp"
+
+#include <pke/pke.hpp>
+
+enum pke_at_storage_interface_result_code {
+ pke_at_storage_interface_result_code_success = 0,
+ pke_at_storage_interface_result_code_err = 1,
+};
+
+struct pke_at_storage_interface_response {
+ enum pke_at_storage_interface_result_code result_code;
+};
+
+template <typename T>
+struct pke_at_storage_interface_response_t {
+ enum pke_at_storage_interface_result_code result_code;
+ T *value;
+};
+
+/* 2025-10-09 JCB Why do you do this to yourself */
+
+#define PASI(type,func) pke_at_storage_interface_##type##_##func
+
+#define PASIR_DEL(type) pke_at_storage_interface_response PASI(type,delete)(pk_uuid uuid)
+#define PASIR_GET(type,T) pke_at_storage_interface_response_t<T> PASI(type,get)(pk_uuid uuid)
+#define PASIR_UPS(type,T) pke_at_storage_interface_response PASI(type,upsert)(const T &val)
+
+struct pke_at_storage_interface {
+ pke_at_storage_interface() = default;
+ virtual ~pke_at_storage_interface() = default;
+ virtual void init() const = 0;
+ virtual void teardown() const = 0;
+ virtual PASIR_DEL(section) const = 0;
+ virtual PASIR_GET(section, pke_at_section_details) const = 0;
+ virtual PASIR_UPS(section, pke_at_section_details) const = 0;
+ virtual PASIR_DEL(setlist) const = 0;
+ virtual PASIR_GET(setlist, pke_at_setlist_details) const = 0;
+ virtual PASIR_UPS(setlist, pke_at_setlist_details) const = 0;
+ virtual PASIR_DEL(setlist_song) const = 0;
+ virtual PASIR_GET(setlist_song, pke_at_setlist_song_details) const = 0;
+ virtual PASIR_UPS(setlist_song, pke_at_setlist_song_details) const = 0;
+ virtual PASIR_DEL(song) const = 0;
+ virtual PASIR_GET(song, pke_at_song_details) const = 0;
+ virtual PASIR_UPS(song, pke_at_song_details) const = 0;
+};
+
+#endif /* PKE_AT_PKE_AT_STORAGE_INTERFACE_HPP */
diff --git a/src/pke-at-storage-sql.cpp b/src/pke-at-storage-sql.cpp
new file mode 100644
index 0000000..e028ff5
--- /dev/null
+++ b/src/pke-at-storage-sql.cpp
@@ -0,0 +1,220 @@
+
+#include "pke-at-storage-sql.hpp"
+#include "pke/asset-types.h"
+
+#include <sqlite3.h>
+
+#define PASIS_RES(R) { .result_code = pke_at_storage_interface_result_code(R) }
+#define PASIS_REST(R,V) { .result_code = pke_at_storage_interface_result_code(R), .value = V }
+
+constexpr unsigned long query_text_length = 1024;
+
+static struct pke_at_storage_sql_master {
+ sqlite3 *db = nullptr;
+ char query_text[query_text_length];
+} sql_mstr;
+
+void pke_at_storage_sql::init() const {
+ char *sql_err_string = nullptr;
+ int res, null_count;
+ AssetKey asset_key;
+ AssetHandle asset_handle;
+ struct db_version {
+ unsigned char maj = -1;
+ unsigned char min = -1;
+ } version;
+ const Asset *asset = nullptr;
+ db_version check_version;
+ assert(sql_mstr.db == nullptr);
+ res = sqlite3_open("pke-at.sqlite3", &sql_mstr.db);
+ if (res != SQLITE_OK) {
+ fprintf(stderr, "[pke_at_storage_sql::init] Failed to open database, sqlite err: %i, %s\n", res, sqlite3_errmsg(sql_mstr.db));
+ goto cleanup;
+ }
+
+ // check db version table exists
+ {
+ const char *query = "SELECT name from sqlite_schema WHERE type='table' AND name='db_version'";
+ auto fn = [](void *user_data, int column_count, char **argv, char **colname) -> int {
+ (void)argv;
+ (void)colname;
+ db_version *version = reinterpret_cast<db_version*>(user_data);
+ if (column_count != 0) {
+ version->maj = 0;
+ }
+ return SQLITE_OK;
+ };
+ res = sqlite3_exec(sql_mstr.db, query, fn, &version, &sql_err_string);
+ if (res != SQLITE_OK) {
+ fprintf(stderr, "[pke_at_storage_sql::init] Failed to query db schema, sqlite err: %i, %s\n", res, sql_err_string);
+ goto cleanup;
+ }
+ }
+
+ // check db version
+ if (version.maj == 0) {
+ const char *query = "SELECT version_maj,version_min from [db_version] WHERE id='0'";
+ auto fn = [](void *user_data, int column_count, char **argv, char **colname) -> int {
+ (void)colname;
+ PK_STN_RES stn_res;
+ db_version *version = reinterpret_cast<db_version*>(user_data);
+ for (int i = 0; i < column_count; ++i) {
+ if (i == 0) {
+ stn_res = pk_stn(&version->maj, argv[i], nullptr);
+ if (stn_res != PK_STN_RES_SUCCESS) {
+ fprintf(stderr, "[pke_at_storage_sql::init] err parsing database version maj.\n");
+ return SQLITE_ERROR;
+ }
+ }
+ if (i == 1) {
+ stn_res = pk_stn(&version->min, argv[i], nullptr);
+ if (stn_res != PK_STN_RES_SUCCESS) {
+ fprintf(stderr, "[pke_at_storage_sql::init] err parsing database version min.\n");
+ return SQLITE_ERROR;
+ }
+ }
+ }
+ return SQLITE_OK;
+ };
+ res = sqlite3_exec(sql_mstr.db, query, fn, &version, &sql_err_string);
+ if (res != SQLITE_OK) {
+ fprintf(stderr, "[pke_at_storage_sql::init] Failed to query [db_version], sqlite err: %i, %s\n", res, sql_err_string);
+ goto cleanup;
+ }
+ }
+
+ // dynamically update db
+ null_count = 0;
+ check_version = version;
+ check_version.min += 1;
+ while (true) {
+ snprintf(asset_key, AssetKeyLength, "sql_scm_%03i_%03i", check_version.maj, check_version.min);
+ asset_handle = AM_GetHandle(asset_key);
+ if (asset_handle == AssetHandle_MAX) {
+ null_count += 1;
+ check_version.maj += 1;
+ check_version.min = 0;
+ if (null_count > 1) break;
+ continue;
+ }
+ asset = AM_Get(asset_handle);
+ null_count = 0;
+ auto fn = [](void *user_data, int column_count, char **argv, char **colname) -> int {
+ (void)user_data; (void)column_count; (void)argv; (void)colname;
+ return SQLITE_OK;
+ };
+ res = sqlite3_exec(sql_mstr.db, (char*)asset->ptr, fn, nullptr, &sql_err_string);
+ if (res != SQLITE_OK) {
+ fprintf(stderr, "[pke_at_storage_sql::init] failed updating database at step %03i_%03i: %i, %s\n", check_version.maj, check_version.min, res, sql_err_string);
+ goto cleanup;
+ }
+ check_version.min += 1;
+ }
+
+cleanup:
+ if (sql_mstr.db != nullptr) sqlite3_close(sql_mstr.db);
+ fflush(stderr);
+ if (res != SQLITE_OK) exit(1);
+}
+
+void
+pke_at_storage_sql::teardown()
+const {
+ /* TODO */
+}
+
+pke_at_storage_interface_response
+pke_at_storage_sql::pke_at_storage_interface_section_delete(pk_uuid uuid)
+const {
+ (void)uuid;
+ /* TODO */
+ return PASIS_RES(0);
+}
+
+pke_at_storage_interface_response_t<pke_at_section_details>
+pke_at_storage_sql::pke_at_storage_interface_section_get(pk_uuid uuid)
+const {
+ (void)uuid;
+ /* TODO */
+ return PASIS_REST(0, nullptr);
+}
+
+pke_at_storage_interface_response
+pke_at_storage_sql::pke_at_storage_interface_section_upsert(const pke_at_section_details &val)
+const {
+ (void)val;
+ /* TODO */
+ return PASIS_RES(0);
+}
+
+pke_at_storage_interface_response
+pke_at_storage_sql::pke_at_storage_interface_setlist_delete(pk_uuid uuid)
+const {
+ (void)uuid;
+ /* TODO */
+ return PASIS_RES(0);
+}
+
+pke_at_storage_interface_response_t<pke_at_setlist_details>
+pke_at_storage_sql::pke_at_storage_interface_setlist_get(pk_uuid uuid)
+const {
+ (void)uuid;
+ /* TODO */
+ return PASIS_REST(0, nullptr);
+}
+
+pke_at_storage_interface_response
+pke_at_storage_sql::pke_at_storage_interface_setlist_upsert(const pke_at_setlist_details &val)
+const {
+ (void)val;
+ /* TODO */
+ return PASIS_RES(0);
+}
+
+pke_at_storage_interface_response
+pke_at_storage_sql::pke_at_storage_interface_song_delete(pk_uuid uuid)
+const {
+ (void)uuid;
+ /* TODO */
+ return PASIS_RES(0);
+}
+
+pke_at_storage_interface_response_t<pke_at_song_details>
+pke_at_storage_sql::pke_at_storage_interface_song_get(pk_uuid uuid)
+const {
+ (void)uuid;
+ /* TODO */
+ return PASIS_REST(0, nullptr);
+}
+
+pke_at_storage_interface_response
+pke_at_storage_sql::pke_at_storage_interface_song_upsert(const pke_at_song_details &val)
+const {
+ (void)val;
+ /* TODO */
+ return PASIS_RES(0);
+}
+
+pke_at_storage_interface_response
+pke_at_storage_sql::pke_at_storage_interface_setlist_song_delete(pk_uuid uuid)
+const {
+ (void)uuid;
+ /* TODO */
+ return PASIS_RES(0);
+}
+
+pke_at_storage_interface_response_t<pke_at_setlist_song_details>
+pke_at_storage_sql::pke_at_storage_interface_setlist_song_get(pk_uuid uuid)
+const {
+ (void)uuid;
+ /* TODO */
+ return PASIS_REST(0, nullptr);
+}
+
+pke_at_storage_interface_response
+pke_at_storage_sql::pke_at_storage_interface_setlist_song_upsert(const pke_at_setlist_song_details &val)
+const {
+ (void)val;
+ /* TODO */
+ return PASIS_RES(0);
+}
diff --git a/src/pke-at-storage-sql.hpp b/src/pke-at-storage-sql.hpp
new file mode 100644
index 0000000..39c8ed8
--- /dev/null
+++ b/src/pke-at-storage-sql.hpp
@@ -0,0 +1,23 @@
+#ifndef PKE_AT_PKE_AT_STORAGE_SQL_HPP
+#define PKE_AT_PKE_AT_STORAGE_SQL_HPP
+
+#include "pke-at-storage-interface.hpp"
+
+struct pke_at_storage_sql : public pke_at_storage_interface {
+ void init() const override;
+ void teardown() const override;
+ PASIR_DEL(section) const override;
+ PASIR_GET(section, pke_at_section_details) const override;
+ PASIR_UPS(section, pke_at_section_details) const override;
+ PASIR_DEL(setlist) const override;
+ PASIR_GET(setlist, pke_at_setlist_details) const override;
+ PASIR_UPS(setlist, pke_at_setlist_details) const override;
+ PASIR_DEL(setlist_song) const override;
+ PASIR_GET(setlist_song, pke_at_setlist_song_details) const override;
+ PASIR_UPS(setlist_song, pke_at_setlist_song_details) const override;
+ PASIR_DEL(song) const override;
+ PASIR_GET(song, pke_at_song_details) const override;
+ PASIR_UPS(song, pke_at_song_details) const override;
+};
+
+#endif /* PKE_AT_PKE_AT_STORAGE_SQL_HPP */
diff --git a/src/pke-at.cpp b/src/pke-at.cpp
index 70625ba..65acedf 100644
--- a/src/pke-at.cpp
+++ b/src/pke-at.cpp
@@ -1,8 +1,12 @@
-#include <pke/pke.hpp>
-
-#include "pke-at.hpp"
+#include "embedded-sql.hpp"
#include "level-init.hpp"
+#include "pke-at-setlist-types.hpp"
+#include "pke-at-settings.hpp"
+#include "pke-at-storage-sql.hpp"
+#include "pke-at.hpp"
+
+#include <pke/pke.hpp>
struct pke_at_master {
struct pke_at_master_states {
@@ -14,7 +18,20 @@ void pke_at_tick(double delta) {
}
void pke_at_init() {
+ uint64_t i;
pkeSettings.rt.nextLevel = pke_at_level_init_create();
+
+ for (i = 0; i < embedded_sql_count; ++i) {
+ embedded_sql[i].handle = AM_Register_Static(embedded_sql[i].key, PKE_ASSET_TYPE_UNSET, embedded_sql[i].data, embedded_sql[i].size);
+ }
+
+ for (i = 0; i < PKE_AT_SECTION_TYPE_INDEX_COUNT; ++i) {
+ if (g_section_types[i].title_key[0] == '\0') continue;
+ g_section_types[i].title_handle = AM_GetHandle(g_section_types[i].title_key);
+ }
+
+ g_at.storage = pk_new<pke_at_storage_sql>();
+ g_at.storage->init();
}
void pke_at_teardown() {
diff --git a/src/sql/schema-000-000.sql b/src/sql/schema-000-000.sql
new file mode 100644
index 0000000..f80977f
--- /dev/null
+++ b/src/sql/schema-000-000.sql
@@ -0,0 +1,48 @@
+CREATE TABLE [db_version] (
+ id INTEGER PRIMARY KEY
+ ,version_maj INTEGER NOT NULL
+ ,version_min INTEGER NOT NULL
+ ,is_deleted INTEGER NOT NULL DEFAULT 0
+ ,creation_dt INTEGER DEFAULT (unixepoch('now'))
+ ,modification_dt INTEGER DEFAULT (unixepoch('now'))
+);
+
+CREATE TABLE [at_setlist] (
+ uuid BLOB PRIMARY KEY
+ ,title nvarchar(128) DEFAULT ''
+ ,is_deleted INTEGER NOT NULL DEFAULT 0
+ ,creation_dt INTEGER DEFAULT (unixepoch('now'))
+ ,modification_dt INTEGER DEFAULT (unixepoch('now'))
+);
+
+CREATE TABLE [at_song] (
+ uuid BLOB PRIMARY KEY
+ ,ccli INTEGER
+ ,title nvarchar(128) DEFAULT ''
+ ,arrangement nvarchar(128) DEFAULT ''
+ ,beats_per_minute INTEGER
+ ,is_deleted INTEGER NOT NULL DEFAULT 0
+ ,creation_dt INTEGER DEFAULT (unixepoch('now'))
+ ,modification_dt INTEGER DEFAULT (unixepoch('now'))
+);
+
+CREATE TABLE [at_setlist_song] (
+ setlist_uuid BLOB
+ ,song_uuid BLOB
+ ,is_deleted INTEGER NOT NULL DEFAULT 0
+ ,creation_dt INTEGER DEFAULT (unixepoch('now'))
+ ,modification_dt INTEGER DEFAULT (unixepoch('now'))
+);
+
+CREATE TABLE [at_section] (
+ song_uuid BLOB
+ ,section_type INTEGER
+ ,sequence INTEGER
+ ,beats_per_bar INTEGER
+ ,bar_count INTEGER
+ ,is_deleted INTEGER NOT NULL DEFAULT 0
+ ,creation_dt INTEGER DEFAULT (unixepoch('now'))
+ ,modification_dt INTEGER DEFAULT (unixepoch('now'))
+);
+
+INSERT INTO [db_version](id,version_maj,version_min) VALUES(0,1,0);
diff --git a/src/sql/section_delete.sql b/src/sql/section_delete.sql
new file mode 100644
index 0000000..7668cfd
--- /dev/null
+++ b/src/sql/section_delete.sql
@@ -0,0 +1,3 @@
+UPDATE [at_section] SET
+ is_deleted = 1
+ ,modification_dt = unixepoch('now')
diff --git a/src/sql/section_get.sql b/src/sql/section_get.sql
new file mode 100644
index 0000000..bbd0a73
--- /dev/null
+++ b/src/sql/section_get.sql
@@ -0,0 +1 @@
+SELECT uuid,section_type,sequence,beats_per_bar,bar_count FROM [at_setlist]
diff --git a/src/sql/section_upsert.sql b/src/sql/section_upsert.sql
new file mode 100644
index 0000000..4ca1025
--- /dev/null
+++ b/src/sql/section_upsert.sql
@@ -0,0 +1,10 @@
+INSERT INTO [at_section] (uuid,section_type,sequence,beats_per_bar,bar_count)
+ VALUES('%s','%s','%s','%s','%s')
+ ON CONFLICT(uuid) DO UPDATE SET
+ section_type=excluded.section_type
+ ,sequence=excluded.sequence
+ ,beats_per_bar=excluded.beats_per_bar
+ ,bar_count=excluded.bar_count
+ ,is_deleted=0
+ ,modification_dt=unixepoch('now')
+ WHERE uuid=excluded.uuid;
diff --git a/src/sql/setlist_delete.sql b/src/sql/setlist_delete.sql
new file mode 100644
index 0000000..d77dc3f
--- /dev/null
+++ b/src/sql/setlist_delete.sql
@@ -0,0 +1,3 @@
+UPDATE [at_setlist] SET
+ is_deleted = 1
+ ,modification_dt = unixepoch('now')
diff --git a/src/sql/setlist_get.sql b/src/sql/setlist_get.sql
new file mode 100644
index 0000000..917df25
--- /dev/null
+++ b/src/sql/setlist_get.sql
@@ -0,0 +1 @@
+SELECT uuid,title FROM [at_setlist]
diff --git a/src/sql/setlist_song_delete.sql b/src/sql/setlist_song_delete.sql
new file mode 100644
index 0000000..51e9284
--- /dev/null
+++ b/src/sql/setlist_song_delete.sql
@@ -0,0 +1,3 @@
+UPDATE [at_setlist_song] SET
+ is_deleted = 1
+ ,modification_dt = unixepoch('now')
diff --git a/src/sql/setlist_song_get.sql b/src/sql/setlist_song_get.sql
new file mode 100644
index 0000000..1278ff7
--- /dev/null
+++ b/src/sql/setlist_song_get.sql
@@ -0,0 +1 @@
+SELECT setlist_uuid,song_uuid FROM [at_setlist_song]
diff --git a/src/sql/setlist_song_upsert.sql b/src/sql/setlist_song_upsert.sql
new file mode 100644
index 0000000..ec0682e
--- /dev/null
+++ b/src/sql/setlist_song_upsert.sql
@@ -0,0 +1,6 @@
+INSERT INTO [at_setlist_song] (setlist_uuid,song_uuid)
+ VALUES('%s','%s')
+ ON CONFLICT(setlist_uuid,song_uuid) DO UPDATE SET
+ is_deleted=0
+ ,modification_dt=unixepoch('now')
+ WHERE setlist_uuid=excluded.setlist_uuid AND song_uuid=excluded.song_uuid;
diff --git a/src/sql/setlist_upsert.sql b/src/sql/setlist_upsert.sql
new file mode 100644
index 0000000..b10f783
--- /dev/null
+++ b/src/sql/setlist_upsert.sql
@@ -0,0 +1,7 @@
+INSERT INTO [at_setlist] (uuid,title)
+ VALUES('%s','%s')
+ ON CONFLICT(uuid) DO UPDATE SET
+ title=excluded.title
+ ,is_deleted=0
+ ,modification_dt=unixepoch('now')
+ WHERE uuid=excluded.uuid;
diff --git a/src/sql/song_delete.sql b/src/sql/song_delete.sql
new file mode 100644
index 0000000..5ddea19
--- /dev/null
+++ b/src/sql/song_delete.sql
@@ -0,0 +1,3 @@
+UPDATE [at_song] SET
+ is_deleted = 1
+ ,modification_dt = unixepoch('now')
diff --git a/src/sql/song_get.sql b/src/sql/song_get.sql
new file mode 100644
index 0000000..c03a59f
--- /dev/null
+++ b/src/sql/song_get.sql
@@ -0,0 +1 @@
+SELECT uuid,ccli,title,arrangement,beats_per_minute FROM [at_song]
diff --git a/src/sql/song_upsert.sql b/src/sql/song_upsert.sql
new file mode 100644
index 0000000..d0e4fcc
--- /dev/null
+++ b/src/sql/song_upsert.sql
@@ -0,0 +1,10 @@
+INSERT INTO [at_song] (uuid,ccli,title,arrangement,beats_per_minute)
+ VALUES('%s','%s','%s','%s','%s')
+ ON CONFLICT(uuid) DO UPDATE SET
+ ccli=excluded.ccli
+ ,title=excluded.title
+ ,arrangement=excluded.arrangement
+ ,beats_per_minute=excluded.beats_per_minute
+ ,is_deleted=0
+ ,modification_dt=unixepoch('now')
+ WHERE uuid=excluded.uuid;