diff --git a/db/Schema.cpp b/db/Schema.cpp new file mode 100644 index 0000000..9b06de0 --- /dev/null +++ b/db/Schema.cpp @@ -0,0 +1,62 @@ +#include "Schema.h" +#include + +#include "migrations/1624829187_create_events.h" + + +namespace db { + namespace db_builder = db::migrations::builder; + + Schema::Schema(sql::Database* db) : m_db(db) { + } + + uint32_t Schema::get_user_version() const { + try { + int user_version = m_db->execAndGet("PRAGMA user_version;"); + return user_version; + } catch (std::exception& e) { + std::cout << "Exception: " << e.what() << std::endl; + return -1; + } + } + + void Schema::set_user_version(uint32_t version) { + try { + m_db->exec("PRAGMA user_version = " + std::to_string(version) + ";"); + } catch (std::exception& e) { + std::cout << "Exception: " << e.what() << std::endl; + } + } + + void Schema::run_migrations() { + assemble_migrations(); + if(migrations.begin() == migrations.end()) { + DEBUG << "No migrations found..."; + return; + } + // TODO try and catch block + // migration should stop on error and restore old schema + + uint32_t user_version = get_user_version(); + for(auto const& [epoch, migration] : migrations) { + if(epoch <= user_version) { + DEBUG << "Skipping: " << migration->get_migration_name(); + continue; + } + DEBUG << "migrating: " << migration->get_migration_name(); + try { + m_db->exec(migration->get_statement()); + } catch (std::exception& e) { + std::cout << "Exception: " << e.what() << std::endl; + } + } + DEBUG << migrations.rbegin()->first; + set_user_version(migrations.rbegin()->first); + user_version = get_user_version(); + DEBUG << user_version; + } + + void Schema::assemble_migrations() { + migrations.emplace(1624829187, new db::migrations::m1624829187_create_events()); + } +} diff --git a/db/Schema.h b/db/Schema.h new file mode 100644 index 0000000..d545fdc --- /dev/null +++ b/db/Schema.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include +#include + +namespace db { + class Schema { + public: + Schema(sql::Database* db); + void run_migrations(); + + private: + uint32_t get_user_version() const; + void set_user_version(uint32_t user_version); + void assemble_migrations(); + + sql::Database* m_db; + std::map migrations; + }; +} diff --git a/db/db.h b/db/db.h index e118d8e..cf1ab3a 100644 --- a/db/db.h +++ b/db/db.h @@ -5,8 +5,7 @@ namespace sql = SQLite; -#include -#include +#include #include #include diff --git a/db/migrations/Migration.cpp b/db/migrations/Migration.cpp index e69de29..743fdf3 100644 --- a/db/migrations/Migration.cpp +++ b/db/migrations/Migration.cpp @@ -0,0 +1,16 @@ +#include "Migration.h" + +#include + +namespace db { + namespace migrations { + namespace db_builder = db::migrations::builder; + + std::string Migration::get_migration_name() const { + return std::string(boost::core::demangled_name(BOOST_CORE_TYPEID(*this))); + } + std::string Migration::get_statement() const { + return m_statement; + } + } +} diff --git a/db/migrations/Migration.h b/db/migrations/Migration.h index 9e02be7..69bdeec 100644 --- a/db/migrations/Migration.h +++ b/db/migrations/Migration.h @@ -1,11 +1,19 @@ #pragma once -#include +#include +#include +#include namespace db { namespace migrations { class Migration { + public: + Migration() = default; - } + std::string get_statement() const; + virtual std::string get_migration_name() const; + protected: + std::string m_statement = ""; + }; } }