diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-10-10 17:07:45 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-10-10 17:07:45 -0400 |
| commit | 62dae6011db94dd52c3ac0fce517c6e9cc0abcf6 (patch) | |
| tree | 1700442c9b6648af7ec8781af0ec92856a93cecd | |
| parent | cc8653536c499df4b85aae423ad6b27bb74544be (diff) | |
pke-at: first-pass storage interface
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 51 | ||||
| -rw-r--r-- | config.mk | 3 | ||||
| -rw-r--r-- | src/embedded-file.hpp | 14 | ||||
| -rw-r--r-- | src/embedded-sql.cpp | 32 | ||||
| -rw-r--r-- | src/embedded-sql.hpp | 10 | ||||
| -rw-r--r-- | src/pke-at-setlist-types.hpp | 64 | ||||
| -rw-r--r-- | src/pke-at-settings.cpp | 11 | ||||
| -rw-r--r-- | src/pke-at-settings.hpp | 7 | ||||
| -rw-r--r-- | src/pke-at-storage-interface.hpp | 50 | ||||
| -rw-r--r-- | src/pke-at-storage-sql.cpp | 220 | ||||
| -rw-r--r-- | src/pke-at-storage-sql.hpp | 23 | ||||
| -rw-r--r-- | src/pke-at.cpp | 23 | ||||
| -rw-r--r-- | src/sql/schema-000-000.sql | 48 | ||||
| -rw-r--r-- | src/sql/section_delete.sql | 3 | ||||
| -rw-r--r-- | src/sql/section_get.sql | 1 | ||||
| -rw-r--r-- | src/sql/section_upsert.sql | 10 | ||||
| -rw-r--r-- | src/sql/setlist_delete.sql | 3 | ||||
| -rw-r--r-- | src/sql/setlist_get.sql | 1 | ||||
| -rw-r--r-- | src/sql/setlist_song_delete.sql | 3 | ||||
| -rw-r--r-- | src/sql/setlist_song_get.sql | 1 | ||||
| -rw-r--r-- | src/sql/setlist_song_upsert.sql | 6 | ||||
| -rw-r--r-- | src/sql/setlist_upsert.sql | 7 | ||||
| -rw-r--r-- | src/sql/song_delete.sql | 3 | ||||
| -rw-r--r-- | src/sql/song_get.sql | 1 | ||||
| -rw-r--r-- | src/sql/song_upsert.sql | 10 |
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 @@ -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 @@ -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; |
