#pragma once #include #include #include #include #include #include using namespace std::string_literals; template std::string ToSQLType(DatabaseEngine& db) { if (std::is_same::value) return db.id_column_type(); else if (std::is_same::value) return "TEXT"; else return "INTEGER"; } template void add_column_to_table(DatabaseEngine& db, const std::string& table_name) { const std::string name = ColumnType::name; std::string query{"ALTER TABLE " + table_name + " ADD " + ColumnType::name + " " + ToSQLType(db)}; auto res = db.raw_exec(query); if (std::get<0>(res) == false) log_error("Error adding column ", name, " to table ", table_name, ": ", std::get<1>(res)); } template void append_option(std::string& s) { s += " "s + ColumnType::options; } template void append_option(Args&& ...) { } template class Table { static_assert(sizeof...(T) > 0, "Table cannot be empty"); using ColumnTypes = std::tuple; public: using RowType = Row; Table(std::string name): name(std::move(name)) {} void upgrade(DatabaseEngine& db) { const auto existing_columns = db.get_all_columns_from_table(this->name); add_column_if_not_exists(db, existing_columns); } void create(DatabaseEngine& db) { std::string query{"CREATE TABLE IF NOT EXISTS "}; query += this->name; query += " ("; this->add_column_create(db, query); query += ")"; auto result = db.raw_exec(query); if (std::get<0>(result) == false) log_error("Error executing query: ", std::get<1>(result)); } RowType row() { return {this->name}; } auto del() { DeleteQuery query(this->name); return query; } const std::string& get_name() const { return this->name; } const std::string name; private: template typename std::enable_if::type add_column_if_not_exists(DatabaseEngine& db, const std::set& existing_columns) { using ColumnType = typename std::remove_reference(std::declval()))>::type; if (existing_columns.count(ColumnType::name) == 0) add_column_to_table(db, this->name); add_column_if_not_exists(db, existing_columns); } template typename std::enable_if::type add_column_if_not_exists(DatabaseEngine&, const std::set&) {} template typename std::enable_if::type add_column_create(DatabaseEngine& db, std::string& str) { using ColumnType = typename std::remove_reference(std::declval()))>::type; str += ColumnType::name; str += " "; str += ToSQLType(db); if (N != sizeof...(T) - 1) str += ","; add_column_create(db, str); } template typename std::enable_if::type add_column_create(DatabaseEngine&, std::string&) { } };