diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp --- a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp +++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp @@ -486,6 +486,15 @@ return create_table(db, query, "keyservers"); } +bool create_communities_table(sqlite3 *db) { + std::string query = + "CREATE TABLE IF NOT EXISTS communities (" + " id TEXT UNIQUE PRIMARY KEY NOT NULL," + " community_info TEXT NOT NULL" + ");"; + return create_table(db, query, "communities"); +} + bool enable_rollback_journal_mode(sqlite3 *db) { char *error; sqlite3_exec(db, "PRAGMA journal_mode=DELETE;", nullptr, nullptr, &error); @@ -589,6 +598,11 @@ " keyserver_info TEXT NOT NULL" ");" + "CREATE TABLE IF NOT EXISTS communities (" + " id TEXT UNIQUE PRIMARY KEY NOT NULL," + " community_info TEXT NOT NULL" + ");" + "CREATE INDEX IF NOT EXISTS media_idx_container" " ON media (container);" @@ -804,1104 +818,1135 @@ typedef bool ShouldBeInTransaction; typedef std::function MigrateFunction; typedef std::pair SQLiteMigration; -std::vector> migrations{ - {{1, {create_drafts_table, true}}, - {2, {rename_threadID_to_key, true}}, - {4, {create_persist_account_table, true}}, - {5, {create_persist_sessions_table, true}}, - {15, {create_media_table, true}}, - {16, {drop_messages_table, true}}, - {17, {recreate_messages_table, true}}, - {18, {create_messages_idx_thread_time, true}}, - {19, {create_media_idx_container, true}}, - {20, {create_threads_table, true}}, - {21, {update_threadID_for_pending_threads_in_drafts, true}}, - {22, {enable_write_ahead_logging_mode, false}}, - {23, {create_metadata_table, true}}, - {24, {add_not_null_constraint_to_drafts, true}}, - {25, {add_not_null_constraint_to_metadata, true}}, - {26, {add_avatar_column_to_threads_table, true}}, - {27, {add_pinned_count_column_to_threads, true}}, - {28, {create_message_store_threads_table, true}}, - {29, {create_reports_table, true}}, - {30, {create_persist_storage_table, true}}, - {31, {recreate_message_store_threads_table, true}}, - {32, {create_users_table, true}}, - {33, {create_keyservers_table, true}}, - {34, {enable_rollback_journal_mode, false}}}}; - -enum class MigrationResult { SUCCESS, FAILURE, NOT_APPLIED }; - -MigrationResult applyMigrationWithTransaction( - sqlite3 *db, - const MigrateFunction &migrate, - int index) { - sqlite3_exec(db, "BEGIN TRANSACTION;", nullptr, nullptr, nullptr); - auto db_version = get_database_version(db); - if (index <= db_version) { - sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr); - return MigrationResult::NOT_APPLIED; - } - auto rc = migrate(db); - if (!rc) { - sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr); - return MigrationResult::FAILURE; - } - auto database_version_set = set_database_version(db, index); - if (!database_version_set) { - sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr); - return MigrationResult::FAILURE; - } - sqlite3_exec(db, "END TRANSACTION;", nullptr, nullptr, nullptr); - return MigrationResult::SUCCESS; -} +std::vector> migrations { + { + {1, {create_drafts_table, true}}, {2, {rename_threadID_to_key, true}}, + {4, {create_persist_account_table, true}}, + {5, {create_persist_sessions_table, true}}, + {15, {create_media_table, true}}, {16, {drop_messages_table, true}}, + {17, {recreate_messages_table, true}}, + {18, {create_messages_idx_thread_time, true}}, + {19, {create_media_idx_container, true}}, + {20, {create_threads_table, true}}, + {21, {update_threadID_for_pending_threads_in_drafts, true}}, + {22, {enable_write_ahead_logging_mode, false}}, + {23, {create_metadata_table, true}}, + {24, {add_not_null_constraint_to_drafts, true}}, + {25, {add_not_null_constraint_to_metadata, true}}, + {26, {add_avatar_column_to_threads_table, true}}, + {27, {add_pinned_count_column_to_threads, true}}, + {28, {create_message_store_threads_table, true}}, + {29, {create_reports_table, true}}, + {30, {create_persist_storage_table, true}}, + {31, {recreate_message_store_threads_table, true}}, + {32, {create_users_table, true}}, {33, {create_keyservers_table, true}}, + {34, {enable_rollback_journal_mode, false}}, + {35, {create_communities_table, true}}; + + enum class MigrationResult { SUCCESS, FAILURE, NOT_APPLIED }; + + MigrationResult applyMigrationWithTransaction( + sqlite3 * db, const MigrateFunction &migrate, int index) { + sqlite3_exec(db, "BEGIN TRANSACTION;", nullptr, nullptr, nullptr); + auto db_version = get_database_version(db); + if (index <= db_version) { + sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr); + return MigrationResult::NOT_APPLIED; + } + auto rc = migrate(db); + if (!rc) { + sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr); + return MigrationResult::FAILURE; + } + auto database_version_set = set_database_version(db, index); + if (!database_version_set) { + sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr); + return MigrationResult::FAILURE; + } + sqlite3_exec(db, "END TRANSACTION;", nullptr, nullptr, nullptr); + return MigrationResult::SUCCESS; + } -MigrationResult applyMigrationWithoutTransaction( - sqlite3 *db, - const MigrateFunction &migrate, - int index) { - auto db_version = get_database_version(db); - if (index <= db_version) { - return MigrationResult::NOT_APPLIED; - } - auto rc = migrate(db); - if (!rc) { - return MigrationResult::FAILURE; - } - sqlite3_exec(db, "BEGIN TRANSACTION;", nullptr, nullptr, nullptr); - auto inner_db_version = get_database_version(db); - if (index <= inner_db_version) { - sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr); - return MigrationResult::NOT_APPLIED; - } - auto database_version_set = set_database_version(db, index); - if (!database_version_set) { - sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr); - return MigrationResult::FAILURE; - } - sqlite3_exec(db, "END TRANSACTION;", nullptr, nullptr, nullptr); - return MigrationResult::SUCCESS; -} + MigrationResult applyMigrationWithoutTransaction( + sqlite3 * db, const MigrateFunction &migrate, int index) { + auto db_version = get_database_version(db); + if (index <= db_version) { + return MigrationResult::NOT_APPLIED; + } + auto rc = migrate(db); + if (!rc) { + return MigrationResult::FAILURE; + } + sqlite3_exec(db, "BEGIN TRANSACTION;", nullptr, nullptr, nullptr); + auto inner_db_version = get_database_version(db); + if (index <= inner_db_version) { + sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr); + return MigrationResult::NOT_APPLIED; + } + auto database_version_set = set_database_version(db, index); + if (!database_version_set) { + sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr); + return MigrationResult::FAILURE; + } + sqlite3_exec(db, "END TRANSACTION;", nullptr, nullptr, nullptr); + return MigrationResult::SUCCESS; + } -bool set_up_database(sqlite3 *db) { - sqlite3_exec(db, "BEGIN TRANSACTION;", nullptr, nullptr, nullptr); - auto db_version = get_database_version(db); - auto latest_version = migrations.back().first; - if (db_version == latest_version) { - sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr); - return true; - } - if (db_version != 0 || !create_schema(db) || - !set_database_version(db, latest_version)) { - sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr); - return false; - } - sqlite3_exec(db, "END TRANSACTION;", nullptr, nullptr, nullptr); - return true; -} + bool set_up_database(sqlite3 * db) { + sqlite3_exec(db, "BEGIN TRANSACTION;", nullptr, nullptr, nullptr); + auto db_version = get_database_version(db); + auto latest_version = migrations.back().first; + if (db_version == latest_version) { + sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr); + return true; + } + if (db_version != 0 || !create_schema(db) || + !set_database_version(db, latest_version)) { + sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr); + return false; + } + sqlite3_exec(db, "END TRANSACTION;", nullptr, nullptr, nullptr); + return true; + } -void SQLiteQueryExecutor::migrate() { + void SQLiteQueryExecutor::migrate() { // We don't want to run `PRAGMA key = ...;` // on main web database. The context is here: // https://linear.app/comm/issue/ENG-6398/issues-with-sqlcipher-on-web #ifndef EMSCRIPTEN - validate_encryption(); + validate_encryption(); #endif - sqlite3 *db; - sqlite3_open(SQLiteQueryExecutor::sqliteFilePath.c_str(), &db); - default_on_db_open_callback(db); - - std::stringstream db_path; - db_path << "db path: " << SQLiteQueryExecutor::sqliteFilePath.c_str() - << std::endl; - Logger::log(db_path.str()); + sqlite3 *db; + sqlite3_open(SQLiteQueryExecutor::sqliteFilePath.c_str(), &db); + default_on_db_open_callback(db); + + std::stringstream db_path; + db_path << "db path: " << SQLiteQueryExecutor::sqliteFilePath.c_str() + << std::endl; + Logger::log(db_path.str()); + + auto db_version = get_database_version(db); + std::stringstream version_msg; + version_msg << "db version: " << db_version << std::endl; + Logger::log(version_msg.str()); + + if (db_version == 0) { + auto db_created = set_up_database(db); + if (!db_created) { + sqlite3_close(db); + Logger::log("Database structure creation error."); + throw std::runtime_error("Database structure creation error"); + } + Logger::log("Database structure created."); + + sqlite3_close(db); + return; + } - auto db_version = get_database_version(db); - std::stringstream version_msg; - version_msg << "db version: " << db_version << std::endl; - Logger::log(version_msg.str()); + for (const auto &[idx, migration] : migrations) { + const auto &[applyMigration, shouldBeInTransaction] = migration; + + MigrationResult migrationResult; + if (shouldBeInTransaction) { + migrationResult = + applyMigrationWithTransaction(db, applyMigration, idx); + } else { + migrationResult = + applyMigrationWithoutTransaction(db, applyMigration, idx); + } + + if (migrationResult == MigrationResult::NOT_APPLIED) { + continue; + } + + std::stringstream migration_msg; + if (migrationResult == MigrationResult::FAILURE) { + migration_msg << "migration " << idx << " failed." << std::endl; + Logger::log(migration_msg.str()); + sqlite3_close(db); + throw std::runtime_error(migration_msg.str()); + } + if (migrationResult == MigrationResult::SUCCESS) { + migration_msg << "migration " << idx << " succeeded." << std::endl; + Logger::log(migration_msg.str()); + } + } - if (db_version == 0) { - auto db_created = set_up_database(db); - if (!db_created) { sqlite3_close(db); - Logger::log("Database structure creation error."); - throw std::runtime_error("Database structure creation error"); } - Logger::log("Database structure created."); - - sqlite3_close(db); - return; - } - for (const auto &[idx, migration] : migrations) { - const auto &[applyMigration, shouldBeInTransaction] = migration; - - MigrationResult migrationResult; - if (shouldBeInTransaction) { - migrationResult = applyMigrationWithTransaction(db, applyMigration, idx); - } else { - migrationResult = - applyMigrationWithoutTransaction(db, applyMigration, idx); + SQLiteQueryExecutor::SQLiteQueryExecutor() { + SQLiteQueryExecutor::migrate(); +#ifndef EMSCRIPTEN + std::string currentBackupID = this->getMetadata("backupID"); + if (!StaffUtils::isStaffRelease() || !currentBackupID.size()) { + return; + } + SQLiteQueryExecutor::connectionManager.setLogsMonitoring(true); +#endif } - if (migrationResult == MigrationResult::NOT_APPLIED) { - continue; + SQLiteQueryExecutor::SQLiteQueryExecutor(std::string sqliteFilePath) { + SQLiteQueryExecutor::sqliteFilePath = sqliteFilePath; + SQLiteQueryExecutor::migrate(); } - std::stringstream migration_msg; - if (migrationResult == MigrationResult::FAILURE) { - migration_msg << "migration " << idx << " failed." << std::endl; - Logger::log(migration_msg.str()); - sqlite3_close(db); - throw std::runtime_error(migration_msg.str()); - } - if (migrationResult == MigrationResult::SUCCESS) { - migration_msg << "migration " << idx << " succeeded." << std::endl; - Logger::log(migration_msg.str()); + sqlite3 *SQLiteQueryExecutor::getConnection() { + if (SQLiteQueryExecutor::connectionManager.getConnection()) { + return SQLiteQueryExecutor::connectionManager.getConnection(); + } + SQLiteQueryExecutor::connectionManager.initializeConnection( + SQLiteQueryExecutor::sqliteFilePath, default_on_db_open_callback); + return SQLiteQueryExecutor::connectionManager.getConnection(); } - } - sqlite3_close(db); -} - -SQLiteQueryExecutor::SQLiteQueryExecutor() { - SQLiteQueryExecutor::migrate(); -#ifndef EMSCRIPTEN - std::string currentBackupID = this->getMetadata("backupID"); - if (!StaffUtils::isStaffRelease() || !currentBackupID.size()) { - return; - } - SQLiteQueryExecutor::connectionManager.setLogsMonitoring(true); -#endif -} - -SQLiteQueryExecutor::SQLiteQueryExecutor(std::string sqliteFilePath) { - SQLiteQueryExecutor::sqliteFilePath = sqliteFilePath; - SQLiteQueryExecutor::migrate(); -} - -sqlite3 *SQLiteQueryExecutor::getConnection() { - if (SQLiteQueryExecutor::connectionManager.getConnection()) { - return SQLiteQueryExecutor::connectionManager.getConnection(); - } - SQLiteQueryExecutor::connectionManager.initializeConnection( - SQLiteQueryExecutor::sqliteFilePath, default_on_db_open_callback); - return SQLiteQueryExecutor::connectionManager.getConnection(); -} - -void SQLiteQueryExecutor::closeConnection() { - SQLiteQueryExecutor::connectionManager.closeConnection(); -} + void SQLiteQueryExecutor::closeConnection() { + SQLiteQueryExecutor::connectionManager.closeConnection(); + } -SQLiteQueryExecutor::~SQLiteQueryExecutor() { - SQLiteQueryExecutor::closeConnection(); -} + SQLiteQueryExecutor::~SQLiteQueryExecutor() { + SQLiteQueryExecutor::closeConnection(); + } -std::string SQLiteQueryExecutor::getDraft(std::string key) const { - static std::string getDraftByPrimaryKeySQL = - "SELECT * " - "FROM drafts " - "WHERE key = ?;"; - std::unique_ptr draft = getEntityByPrimaryKey( - SQLiteQueryExecutor::getConnection(), getDraftByPrimaryKeySQL, key); - return (draft == nullptr) ? "" : draft->text; -} + std::string SQLiteQueryExecutor::getDraft(std::string key) const { + static std::string getDraftByPrimaryKeySQL = + "SELECT * " + "FROM drafts " + "WHERE key = ?;"; + std::unique_ptr draft = getEntityByPrimaryKey( + SQLiteQueryExecutor::getConnection(), getDraftByPrimaryKeySQL, key); + return (draft == nullptr) ? "" : draft->text; + } -std::unique_ptr -SQLiteQueryExecutor::getThread(std::string threadID) const { - static std::string getThreadByPrimaryKeySQL = - "SELECT * " - "FROM threads " - "WHERE id = ?;"; - return getEntityByPrimaryKey( - SQLiteQueryExecutor::getConnection(), getThreadByPrimaryKeySQL, threadID); -} + std::unique_ptr SQLiteQueryExecutor::getThread(std::string threadID) + const { + static std::string getThreadByPrimaryKeySQL = + "SELECT * " + "FROM threads " + "WHERE id = ?;"; + return getEntityByPrimaryKey( + SQLiteQueryExecutor::getConnection(), + getThreadByPrimaryKeySQL, + threadID); + } -void SQLiteQueryExecutor::updateDraft(std::string key, std::string text) const { - static std::string replaceDraftSQL = - "REPLACE INTO drafts (key, text) " - "VALUES (?, ?);"; - Draft draft = {key, text}; - replaceEntity( - SQLiteQueryExecutor::getConnection(), replaceDraftSQL, draft); -} + void SQLiteQueryExecutor::updateDraft(std::string key, std::string text) + const { + static std::string replaceDraftSQL = + "REPLACE INTO drafts (key, text) " + "VALUES (?, ?);"; + Draft draft = {key, text}; + replaceEntity( + SQLiteQueryExecutor::getConnection(), replaceDraftSQL, draft); + } -bool SQLiteQueryExecutor::moveDraft(std::string oldKey, std::string newKey) - const { - std::string draftText = this->getDraft(oldKey); - if (!draftText.size()) { - return false; - } - static std::string rekeyDraftSQL = - "UPDATE OR REPLACE drafts " - "SET key = ? " - "WHERE key = ?;"; - rekeyAllEntities( - SQLiteQueryExecutor::getConnection(), rekeyDraftSQL, oldKey, newKey); - return true; -} + bool SQLiteQueryExecutor::moveDraft(std::string oldKey, std::string newKey) + const { + std::string draftText = this->getDraft(oldKey); + if (!draftText.size()) { + return false; + } + static std::string rekeyDraftSQL = + "UPDATE OR REPLACE drafts " + "SET key = ? " + "WHERE key = ?;"; + rekeyAllEntities( + SQLiteQueryExecutor::getConnection(), rekeyDraftSQL, oldKey, newKey); + return true; + } -std::vector SQLiteQueryExecutor::getAllDrafts() const { - static std::string getAllDraftsSQL = - "SELECT * " - "FROM drafts;"; - return getAllEntities( - SQLiteQueryExecutor::getConnection(), getAllDraftsSQL); -} + std::vector SQLiteQueryExecutor::getAllDrafts() const { + static std::string getAllDraftsSQL = + "SELECT * " + "FROM drafts;"; + return getAllEntities( + SQLiteQueryExecutor::getConnection(), getAllDraftsSQL); + } -void SQLiteQueryExecutor::removeAllDrafts() const { - static std::string removeAllDraftsSQL = "DELETE FROM drafts;"; - removeAllEntities(SQLiteQueryExecutor::getConnection(), removeAllDraftsSQL); -} + void SQLiteQueryExecutor::removeAllDrafts() const { + static std::string removeAllDraftsSQL = "DELETE FROM drafts;"; + removeAllEntities( + SQLiteQueryExecutor::getConnection(), removeAllDraftsSQL); + } -void SQLiteQueryExecutor::removeDrafts( - const std::vector &ids) const { - if (!ids.size()) { - return; - } + void SQLiteQueryExecutor::removeDrafts(const std::vector &ids) + const { + if (!ids.size()) { + return; + } - std::stringstream removeDraftsByKeysSQLStream; - removeDraftsByKeysSQLStream << "DELETE FROM drafts " - "WHERE key IN " - << getSQLStatementArray(ids.size()) << ";"; + std::stringstream removeDraftsByKeysSQLStream; + removeDraftsByKeysSQLStream << "DELETE FROM drafts " + "WHERE key IN " + << getSQLStatementArray(ids.size()) << ";"; - removeEntitiesByKeys( - SQLiteQueryExecutor::getConnection(), - removeDraftsByKeysSQLStream.str(), - ids); -} + removeEntitiesByKeys( + SQLiteQueryExecutor::getConnection(), + removeDraftsByKeysSQLStream.str(), + ids); + } -void SQLiteQueryExecutor::removeAllMessages() const { - static std::string removeAllMessagesSQL = "DELETE FROM messages;"; - removeAllEntities(SQLiteQueryExecutor::getConnection(), removeAllMessagesSQL); -} + void SQLiteQueryExecutor::removeAllMessages() const { + static std::string removeAllMessagesSQL = "DELETE FROM messages;"; + removeAllEntities( + SQLiteQueryExecutor::getConnection(), removeAllMessagesSQL); + } -std::vector>> -SQLiteQueryExecutor::getAllMessages() const { - static std::string getAllMessagesSQL = - "SELECT * " - "FROM messages " - "LEFT JOIN media " - " ON messages.id = media.container " - "ORDER BY messages.id;"; - SQLiteStatementWrapper preparedSQL( - SQLiteQueryExecutor::getConnection(), - getAllMessagesSQL, - "Failed to retrieve all messages."); - - std::string prevMsgIdx{}; - std::vector>> allMessages; - - for (int stepResult = sqlite3_step(preparedSQL); stepResult == SQLITE_ROW; - stepResult = sqlite3_step(preparedSQL)) { - Message message = Message::fromSQLResult(preparedSQL, 0); - if (message.id == prevMsgIdx) { - allMessages.back().second.push_back(Media::fromSQLResult(preparedSQL, 8)); - } else { - prevMsgIdx = message.id; - std::vector mediaForMsg; - if (sqlite3_column_type(preparedSQL, 8) != SQLITE_NULL) { - mediaForMsg.push_back(Media::fromSQLResult(preparedSQL, 8)); + std::vector>> + SQLiteQueryExecutor::getAllMessages() const { + static std::string getAllMessagesSQL = + "SELECT * " + "FROM messages " + "LEFT JOIN media " + " ON messages.id = media.container " + "ORDER BY messages.id;"; + SQLiteStatementWrapper preparedSQL( + SQLiteQueryExecutor::getConnection(), + getAllMessagesSQL, + "Failed to retrieve all messages."); + + std::string prevMsgIdx{}; + std::vector>> allMessages; + + for (int stepResult = sqlite3_step(preparedSQL); stepResult == SQLITE_ROW; + stepResult = sqlite3_step(preparedSQL)) { + Message message = Message::fromSQLResult(preparedSQL, 0); + if (message.id == prevMsgIdx) { + allMessages.back().second.push_back( + Media::fromSQLResult(preparedSQL, 8)); + } else { + prevMsgIdx = message.id; + std::vector mediaForMsg; + if (sqlite3_column_type(preparedSQL, 8) != SQLITE_NULL) { + mediaForMsg.push_back(Media::fromSQLResult(preparedSQL, 8)); + } + allMessages.push_back( + std::make_pair(std::move(message), mediaForMsg)); + } } - allMessages.push_back(std::make_pair(std::move(message), mediaForMsg)); + return allMessages; } - } - return allMessages; -} -void SQLiteQueryExecutor::removeMessages( - const std::vector &ids) const { - if (!ids.size()) { - return; - } + void SQLiteQueryExecutor::removeMessages( + const std::vector &ids) const { + if (!ids.size()) { + return; + } - std::stringstream removeMessagesByKeysSQLStream; - removeMessagesByKeysSQLStream << "DELETE FROM messages " - "WHERE id IN " - << getSQLStatementArray(ids.size()) << ";"; - removeEntitiesByKeys( - SQLiteQueryExecutor::getConnection(), - removeMessagesByKeysSQLStream.str(), - ids); -} + std::stringstream removeMessagesByKeysSQLStream; + removeMessagesByKeysSQLStream << "DELETE FROM messages " + "WHERE id IN " + << getSQLStatementArray(ids.size()) << ";"; + removeEntitiesByKeys( + SQLiteQueryExecutor::getConnection(), + removeMessagesByKeysSQLStream.str(), + ids); + } -void SQLiteQueryExecutor::removeMessagesForThreads( - const std::vector &threadIDs) const { - if (!threadIDs.size()) { - return; - } + void SQLiteQueryExecutor::removeMessagesForThreads( + const std::vector &threadIDs) const { + if (!threadIDs.size()) { + return; + } - std::stringstream removeMessagesByKeysSQLStream; - removeMessagesByKeysSQLStream << "DELETE FROM messages " - "WHERE thread IN " - << getSQLStatementArray(threadIDs.size()) - << ";"; + std::stringstream removeMessagesByKeysSQLStream; + removeMessagesByKeysSQLStream << "DELETE FROM messages " + "WHERE thread IN " + << getSQLStatementArray(threadIDs.size()) + << ";"; - removeEntitiesByKeys( - SQLiteQueryExecutor::getConnection(), - removeMessagesByKeysSQLStream.str(), - threadIDs); -} - -void SQLiteQueryExecutor::replaceMessage(const Message &message) const { - static std::string replaceMessageSQL = - "REPLACE INTO messages " - "(id, local_id, thread, user, type, future_type, content, time) " - "VALUES (?, ?, ?, ?, ?, ?, ?, ?);"; + removeEntitiesByKeys( + SQLiteQueryExecutor::getConnection(), + removeMessagesByKeysSQLStream.str(), + threadIDs); + } - replaceEntity( - SQLiteQueryExecutor::getConnection(), replaceMessageSQL, message); -} + void SQLiteQueryExecutor::replaceMessage(const Message &message) const { + static std::string replaceMessageSQL = + "REPLACE INTO messages " + "(id, local_id, thread, user, type, future_type, content, time) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?);"; -void SQLiteQueryExecutor::rekeyMessage(std::string from, std::string to) const { - static std::string rekeyMessageSQL = - "UPDATE OR REPLACE messages " - "SET id = ? " - "WHERE id = ?"; - rekeyAllEntities( - SQLiteQueryExecutor::getConnection(), rekeyMessageSQL, from, to); -} + replaceEntity( + SQLiteQueryExecutor::getConnection(), replaceMessageSQL, message); + } -void SQLiteQueryExecutor::removeAllMedia() const { - static std::string removeAllMediaSQL = "DELETE FROM media;"; - removeAllEntities(SQLiteQueryExecutor::getConnection(), removeAllMediaSQL); -} + void SQLiteQueryExecutor::rekeyMessage(std::string from, std::string to) + const { + static std::string rekeyMessageSQL = + "UPDATE OR REPLACE messages " + "SET id = ? " + "WHERE id = ?"; + rekeyAllEntities( + SQLiteQueryExecutor::getConnection(), rekeyMessageSQL, from, to); + } -void SQLiteQueryExecutor::removeMediaForMessages( - const std::vector &msg_ids) const { - if (!msg_ids.size()) { - return; - } + void SQLiteQueryExecutor::removeAllMedia() const { + static std::string removeAllMediaSQL = "DELETE FROM media;"; + removeAllEntities( + SQLiteQueryExecutor::getConnection(), removeAllMediaSQL); + } - std::stringstream removeMediaByKeysSQLStream; - removeMediaByKeysSQLStream << "DELETE FROM media " - "WHERE container IN " - << getSQLStatementArray(msg_ids.size()) << ";"; + void SQLiteQueryExecutor::removeMediaForMessages( + const std::vector &msg_ids) const { + if (!msg_ids.size()) { + return; + } - removeEntitiesByKeys( - SQLiteQueryExecutor::getConnection(), - removeMediaByKeysSQLStream.str(), - msg_ids); -} + std::stringstream removeMediaByKeysSQLStream; + removeMediaByKeysSQLStream << "DELETE FROM media " + "WHERE container IN " + << getSQLStatementArray(msg_ids.size()) << ";"; -void SQLiteQueryExecutor::removeMediaForMessage(std::string msg_id) const { - static std::string removeMediaByKeySQL = - "DELETE FROM media " - "WHERE container IN (?);"; - std::vector keys = {msg_id}; - removeEntitiesByKeys( - SQLiteQueryExecutor::getConnection(), removeMediaByKeySQL, keys); -} + removeEntitiesByKeys( + SQLiteQueryExecutor::getConnection(), + removeMediaByKeysSQLStream.str(), + msg_ids); + } -void SQLiteQueryExecutor::removeMediaForThreads( - const std::vector &thread_ids) const { - if (!thread_ids.size()) { - return; - } + void SQLiteQueryExecutor::removeMediaForMessage(std::string msg_id) const { + static std::string removeMediaByKeySQL = + "DELETE FROM media " + "WHERE container IN (?);"; + std::vector keys = {msg_id}; + removeEntitiesByKeys( + SQLiteQueryExecutor::getConnection(), removeMediaByKeySQL, keys); + } - std::stringstream removeMediaByKeysSQLStream; - removeMediaByKeysSQLStream << "DELETE FROM media " - "WHERE thread IN " - << getSQLStatementArray(thread_ids.size()) << ";"; + void SQLiteQueryExecutor::removeMediaForThreads( + const std::vector &thread_ids) const { + if (!thread_ids.size()) { + return; + } - removeEntitiesByKeys( - SQLiteQueryExecutor::getConnection(), - removeMediaByKeysSQLStream.str(), - thread_ids); -} + std::stringstream removeMediaByKeysSQLStream; + removeMediaByKeysSQLStream << "DELETE FROM media " + "WHERE thread IN " + << getSQLStatementArray(thread_ids.size()) + << ";"; -void SQLiteQueryExecutor::replaceMedia(const Media &media) const { - static std::string replaceMediaSQL = - "REPLACE INTO media " - "(id, container, thread, uri, type, extras) " - "VALUES (?, ?, ?, ?, ?, ?)"; - replaceEntity( - SQLiteQueryExecutor::getConnection(), replaceMediaSQL, media); -} + removeEntitiesByKeys( + SQLiteQueryExecutor::getConnection(), + removeMediaByKeysSQLStream.str(), + thread_ids); + } -void SQLiteQueryExecutor::rekeyMediaContainers(std::string from, std::string to) - const { - static std::string rekeyMediaContainersSQL = - "UPDATE media SET container = ? WHERE container = ?;"; - rekeyAllEntities( - SQLiteQueryExecutor::getConnection(), rekeyMediaContainersSQL, from, to); -} + void SQLiteQueryExecutor::replaceMedia(const Media &media) const { + static std::string replaceMediaSQL = + "REPLACE INTO media " + "(id, container, thread, uri, type, extras) " + "VALUES (?, ?, ?, ?, ?, ?)"; + replaceEntity( + SQLiteQueryExecutor::getConnection(), replaceMediaSQL, media); + } -void SQLiteQueryExecutor::replaceMessageStoreThreads( - const std::vector &threads) const { - static std::string replaceMessageStoreThreadSQL = - "REPLACE INTO message_store_threads " - "(id, start_reached) " - "VALUES (?, ?);"; - - for (auto &thread : threads) { - replaceEntity( - SQLiteQueryExecutor::getConnection(), - replaceMessageStoreThreadSQL, - thread); - } -} + void SQLiteQueryExecutor::rekeyMediaContainers( + std::string from, std::string to) const { + static std::string rekeyMediaContainersSQL = + "UPDATE media SET container = ? WHERE container = ?;"; + rekeyAllEntities( + SQLiteQueryExecutor::getConnection(), + rekeyMediaContainersSQL, + from, + to); + } -void SQLiteQueryExecutor::removeAllMessageStoreThreads() const { - static std::string removeAllMessageStoreThreadsSQL = - "DELETE FROM message_store_threads;"; - removeAllEntities( - SQLiteQueryExecutor::getConnection(), removeAllMessageStoreThreadsSQL); -} + void SQLiteQueryExecutor::replaceMessageStoreThreads( + const std::vector &threads) const { + static std::string replaceMessageStoreThreadSQL = + "REPLACE INTO message_store_threads " + "(id, start_reached) " + "VALUES (?, ?);"; + + for (auto &thread : threads) { + replaceEntity( + SQLiteQueryExecutor::getConnection(), + replaceMessageStoreThreadSQL, + thread); + } + } -void SQLiteQueryExecutor::removeMessageStoreThreads( - const std::vector &ids) const { - if (!ids.size()) { - return; - } + void SQLiteQueryExecutor::removeAllMessageStoreThreads() const { + static std::string removeAllMessageStoreThreadsSQL = + "DELETE FROM message_store_threads;"; + removeAllEntities( + SQLiteQueryExecutor::getConnection(), + removeAllMessageStoreThreadsSQL); + } - std::stringstream removeMessageStoreThreadsByKeysSQLStream; - removeMessageStoreThreadsByKeysSQLStream - << "DELETE FROM message_store_threads " - "WHERE id IN " - << getSQLStatementArray(ids.size()) << ";"; + void SQLiteQueryExecutor::removeMessageStoreThreads( + const std::vector &ids) const { + if (!ids.size()) { + return; + } - removeEntitiesByKeys( - SQLiteQueryExecutor::getConnection(), - removeMessageStoreThreadsByKeysSQLStream.str(), - ids); -} + std::stringstream removeMessageStoreThreadsByKeysSQLStream; + removeMessageStoreThreadsByKeysSQLStream + << "DELETE FROM message_store_threads " + "WHERE id IN " + << getSQLStatementArray(ids.size()) << ";"; -std::vector -SQLiteQueryExecutor::getAllMessageStoreThreads() const { - static std::string getAllMessageStoreThreadsSQL = - "SELECT * " - "FROM message_store_threads;"; - return getAllEntities( - SQLiteQueryExecutor::getConnection(), getAllMessageStoreThreadsSQL); -} + removeEntitiesByKeys( + SQLiteQueryExecutor::getConnection(), + removeMessageStoreThreadsByKeysSQLStream.str(), + ids); + } -std::vector SQLiteQueryExecutor::getAllThreads() const { - static std::string getAllThreadsSQL = - "SELECT * " - "FROM threads;"; - return getAllEntities( - SQLiteQueryExecutor::getConnection(), getAllThreadsSQL); -}; + std::vector + SQLiteQueryExecutor::getAllMessageStoreThreads() const { + static std::string getAllMessageStoreThreadsSQL = + "SELECT * " + "FROM message_store_threads;"; + return getAllEntities( + SQLiteQueryExecutor::getConnection(), getAllMessageStoreThreadsSQL); + } -void SQLiteQueryExecutor::removeThreads(std::vector ids) const { - if (!ids.size()) { - return; - } + std::vector SQLiteQueryExecutor::getAllThreads() const { + static std::string getAllThreadsSQL = + "SELECT * " + "FROM threads;"; + return getAllEntities( + SQLiteQueryExecutor::getConnection(), getAllThreadsSQL); + }; + + void SQLiteQueryExecutor::removeThreads(std::vector ids) + const { + if (!ids.size()) { + return; + } - std::stringstream removeThreadsByKeysSQLStream; - removeThreadsByKeysSQLStream << "DELETE FROM threads " - "WHERE id IN " - << getSQLStatementArray(ids.size()) << ";"; - - removeEntitiesByKeys( - SQLiteQueryExecutor::getConnection(), - removeThreadsByKeysSQLStream.str(), - ids); -}; - -void SQLiteQueryExecutor::replaceThread(const Thread &thread) const { - static std::string replaceThreadSQL = - "REPLACE INTO threads (" - " id, type, name, description, color, creation_time, parent_thread_id," - " containing_thread_id, community, members, roles, current_user," - " source_message_id, replies_count, avatar, pinned_count) " - "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"; - - replaceEntity( - SQLiteQueryExecutor::getConnection(), replaceThreadSQL, thread); -}; - -void SQLiteQueryExecutor::removeAllThreads() const { - static std::string removeAllThreadsSQL = "DELETE FROM threads;"; - removeAllEntities(SQLiteQueryExecutor::getConnection(), removeAllThreadsSQL); -}; - -void SQLiteQueryExecutor::replaceReport(const Report &report) const { - static std::string replaceReportSQL = - "REPLACE INTO reports (id, report) " - "VALUES (?, ?);"; - - replaceEntity( - SQLiteQueryExecutor::getConnection(), replaceReportSQL, report); -} + std::stringstream removeThreadsByKeysSQLStream; + removeThreadsByKeysSQLStream << "DELETE FROM threads " + "WHERE id IN " + << getSQLStatementArray(ids.size()) << ";"; + + removeEntitiesByKeys( + SQLiteQueryExecutor::getConnection(), + removeThreadsByKeysSQLStream.str(), + ids); + }; + + void SQLiteQueryExecutor::replaceThread(const Thread &thread) const { + static std::string replaceThreadSQL = + "REPLACE INTO threads (" + " id, type, name, description, color, creation_time, " + "parent_thread_id," + " containing_thread_id, community, members, roles, current_user," + " source_message_id, replies_count, avatar, pinned_count) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"; + + replaceEntity( + SQLiteQueryExecutor::getConnection(), replaceThreadSQL, thread); + }; + + void SQLiteQueryExecutor::removeAllThreads() const { + static std::string removeAllThreadsSQL = "DELETE FROM threads;"; + removeAllEntities( + SQLiteQueryExecutor::getConnection(), removeAllThreadsSQL); + }; + + void SQLiteQueryExecutor::replaceReport(const Report &report) const { + static std::string replaceReportSQL = + "REPLACE INTO reports (id, report) " + "VALUES (?, ?);"; + + replaceEntity( + SQLiteQueryExecutor::getConnection(), replaceReportSQL, report); + } -void SQLiteQueryExecutor::removeAllReports() const { - static std::string removeAllReportsSQL = "DELETE FROM reports;"; - removeAllEntities(SQLiteQueryExecutor::getConnection(), removeAllReportsSQL); -} + void SQLiteQueryExecutor::removeAllReports() const { + static std::string removeAllReportsSQL = "DELETE FROM reports;"; + removeAllEntities( + SQLiteQueryExecutor::getConnection(), removeAllReportsSQL); + } -void SQLiteQueryExecutor::removeReports( - const std::vector &ids) const { - if (!ids.size()) { - return; - } + void SQLiteQueryExecutor::removeReports(const std::vector &ids) + const { + if (!ids.size()) { + return; + } - std::stringstream removeReportsByKeysSQLStream; - removeReportsByKeysSQLStream << "DELETE FROM reports " - "WHERE id IN " - << getSQLStatementArray(ids.size()) << ";"; - removeEntitiesByKeys( - SQLiteQueryExecutor::getConnection(), - removeReportsByKeysSQLStream.str(), - ids); -} + std::stringstream removeReportsByKeysSQLStream; + removeReportsByKeysSQLStream << "DELETE FROM reports " + "WHERE id IN " + << getSQLStatementArray(ids.size()) << ";"; + removeEntitiesByKeys( + SQLiteQueryExecutor::getConnection(), + removeReportsByKeysSQLStream.str(), + ids); + } -std::vector SQLiteQueryExecutor::getAllReports() const { - static std::string getAllReportsSQL = - "SELECT * " - "FROM reports;"; - return getAllEntities( - SQLiteQueryExecutor::getConnection(), getAllReportsSQL); -} + std::vector SQLiteQueryExecutor::getAllReports() const { + static std::string getAllReportsSQL = + "SELECT * " + "FROM reports;"; + return getAllEntities( + SQLiteQueryExecutor::getConnection(), getAllReportsSQL); + } -void SQLiteQueryExecutor::setPersistStorageItem( - std::string key, - std::string item) const { - static std::string replacePersistStorageItemSQL = - "REPLACE INTO persist_storage (key, item) " - "VALUES (?, ?);"; - PersistItem entry{ - key, - item, - }; - replaceEntity( - SQLiteQueryExecutor::getConnection(), - replacePersistStorageItemSQL, - entry); -} + void SQLiteQueryExecutor::setPersistStorageItem( + std::string key, std::string item) const { + static std::string replacePersistStorageItemSQL = + "REPLACE INTO persist_storage (key, item) " + "VALUES (?, ?);"; + PersistItem entry{ + key, + item, + }; + replaceEntity( + SQLiteQueryExecutor::getConnection(), + replacePersistStorageItemSQL, + entry); + } -void SQLiteQueryExecutor::removePersistStorageItem(std::string key) const { - static std::string removePersistStorageItemByKeySQL = - "DELETE FROM persist_storage " - "WHERE key IN (?);"; - std::vector keys = {key}; - removeEntitiesByKeys( - SQLiteQueryExecutor::getConnection(), - removePersistStorageItemByKeySQL, - keys); -} + void SQLiteQueryExecutor::removePersistStorageItem(std::string key) const { + static std::string removePersistStorageItemByKeySQL = + "DELETE FROM persist_storage " + "WHERE key IN (?);"; + std::vector keys = {key}; + removeEntitiesByKeys( + SQLiteQueryExecutor::getConnection(), + removePersistStorageItemByKeySQL, + keys); + } -std::string SQLiteQueryExecutor::getPersistStorageItem(std::string key) const { - static std::string getPersistStorageItemByPrimaryKeySQL = - "SELECT * " - "FROM persist_storage " - "WHERE key = ?;"; - std::unique_ptr entry = getEntityByPrimaryKey( - SQLiteQueryExecutor::getConnection(), - getPersistStorageItemByPrimaryKeySQL, - key); - return (entry == nullptr) ? "" : entry->item; -} + std::string SQLiteQueryExecutor::getPersistStorageItem(std::string key) + const { + static std::string getPersistStorageItemByPrimaryKeySQL = + "SELECT * " + "FROM persist_storage " + "WHERE key = ?;"; + std::unique_ptr entry = getEntityByPrimaryKey( + SQLiteQueryExecutor::getConnection(), + getPersistStorageItemByPrimaryKeySQL, + key); + return (entry == nullptr) ? "" : entry->item; + } -void SQLiteQueryExecutor::replaceUser(const UserInfo &user_info) const { - static std::string replaceUserSQL = - "REPLACE INTO users (id, user_info) " - "VALUES (?, ?);"; - replaceEntity( - SQLiteQueryExecutor::getConnection(), replaceUserSQL, user_info); -} + void SQLiteQueryExecutor::replaceUser(const UserInfo &user_info) const { + static std::string replaceUserSQL = + "REPLACE INTO users (id, user_info) " + "VALUES (?, ?);"; + replaceEntity( + SQLiteQueryExecutor::getConnection(), replaceUserSQL, user_info); + } -void SQLiteQueryExecutor::removeAllUsers() const { - static std::string removeAllUsersSQL = "DELETE FROM users;"; - removeAllEntities(SQLiteQueryExecutor::getConnection(), removeAllUsersSQL); -} + void SQLiteQueryExecutor::removeAllUsers() const { + static std::string removeAllUsersSQL = "DELETE FROM users;"; + removeAllEntities( + SQLiteQueryExecutor::getConnection(), removeAllUsersSQL); + } -void SQLiteQueryExecutor::removeUsers( - const std::vector &ids) const { - if (!ids.size()) { - return; - } + void SQLiteQueryExecutor::removeUsers(const std::vector &ids) + const { + if (!ids.size()) { + return; + } - std::stringstream removeUsersByKeysSQLStream; - removeUsersByKeysSQLStream << "DELETE FROM users " - "WHERE id IN " - << getSQLStatementArray(ids.size()) << ";"; - removeEntitiesByKeys( - SQLiteQueryExecutor::getConnection(), - removeUsersByKeysSQLStream.str(), - ids); -} + std::stringstream removeUsersByKeysSQLStream; + removeUsersByKeysSQLStream << "DELETE FROM users " + "WHERE id IN " + << getSQLStatementArray(ids.size()) << ";"; + removeEntitiesByKeys( + SQLiteQueryExecutor::getConnection(), + removeUsersByKeysSQLStream.str(), + ids); + } -void SQLiteQueryExecutor::replaceKeyserver( - const KeyserverInfo &keyserver_info) const { - static std::string replaceKeyserverSQL = - "REPLACE INTO keyservers (id, keyserver_info) " - "VALUES (?, ?);"; - replaceEntity( - SQLiteQueryExecutor::getConnection(), - replaceKeyserverSQL, - keyserver_info); -} + void SQLiteQueryExecutor::replaceKeyserver( + const KeyserverInfo &keyserver_info) const { + static std::string replaceKeyserverSQL = + "REPLACE INTO keyservers (id, keyserver_info) " + "VALUES (?, ?);"; + replaceEntity( + SQLiteQueryExecutor::getConnection(), + replaceKeyserverSQL, + keyserver_info); + } -void SQLiteQueryExecutor::removeAllKeyservers() const { - static std::string removeAllKeyserversSQL = "DELETE FROM keyservers;"; - removeAllEntities( - SQLiteQueryExecutor::getConnection(), removeAllKeyserversSQL); -} + void SQLiteQueryExecutor::removeAllKeyservers() const { + static std::string removeAllKeyserversSQL = "DELETE FROM keyservers;"; + removeAllEntities( + SQLiteQueryExecutor::getConnection(), removeAllKeyserversSQL); + } -void SQLiteQueryExecutor::removeKeyservers( - const std::vector &ids) const { - if (!ids.size()) { - return; - } + void SQLiteQueryExecutor::removeKeyservers( + const std::vector &ids) const { + if (!ids.size()) { + return; + } - std::stringstream removeKeyserversByKeysSQLStream; - removeKeyserversByKeysSQLStream << "DELETE FROM keyservers " - "WHERE id IN " - << getSQLStatementArray(ids.size()) << ";"; + std::stringstream removeKeyserversByKeysSQLStream; + removeKeyserversByKeysSQLStream << "DELETE FROM keyservers " + "WHERE id IN " + << getSQLStatementArray(ids.size()) + << ";"; - removeEntitiesByKeys( - SQLiteQueryExecutor::getConnection(), - removeKeyserversByKeysSQLStream.str(), - ids); -} + removeEntitiesByKeys( + SQLiteQueryExecutor::getConnection(), + removeKeyserversByKeysSQLStream.str(), + ids); + } -std::vector SQLiteQueryExecutor::getAllKeyservers() const { - static std::string getAllKeyserversSQL = - "SELECT * " - "FROM keyservers;"; - return getAllEntities( - SQLiteQueryExecutor::getConnection(), getAllKeyserversSQL); -} + std::vector SQLiteQueryExecutor::getAllKeyservers() const { + static std::string getAllKeyserversSQL = + "SELECT * " + "FROM keyservers;"; + return getAllEntities( + SQLiteQueryExecutor::getConnection(), getAllKeyserversSQL); + } -std::vector SQLiteQueryExecutor::getAllUsers() const { - static std::string getAllUsersSQL = - "SELECT * " - "FROM users;"; - return getAllEntities( - SQLiteQueryExecutor::getConnection(), getAllUsersSQL); -} + std::vector SQLiteQueryExecutor::getAllUsers() const { + static std::string getAllUsersSQL = + "SELECT * " + "FROM users;"; + return getAllEntities( + SQLiteQueryExecutor::getConnection(), getAllUsersSQL); + } -void SQLiteQueryExecutor::beginTransaction() const { - executeQuery(SQLiteQueryExecutor::getConnection(), "BEGIN TRANSACTION;"); -} + void SQLiteQueryExecutor::beginTransaction() const { + executeQuery(SQLiteQueryExecutor::getConnection(), "BEGIN TRANSACTION;"); + } -void SQLiteQueryExecutor::commitTransaction() const { - executeQuery(SQLiteQueryExecutor::getConnection(), "COMMIT;"); -} + void SQLiteQueryExecutor::commitTransaction() const { + executeQuery(SQLiteQueryExecutor::getConnection(), "COMMIT;"); + } -void SQLiteQueryExecutor::rollbackTransaction() const { - executeQuery(SQLiteQueryExecutor::getConnection(), "ROLLBACK;"); -} + void SQLiteQueryExecutor::rollbackTransaction() const { + executeQuery(SQLiteQueryExecutor::getConnection(), "ROLLBACK;"); + } -std::vector -SQLiteQueryExecutor::getOlmPersistSessionsData() const { - static std::string getAllOlmPersistSessionsSQL = - "SELECT * " - "FROM olm_persist_sessions;"; - return getAllEntities( - SQLiteQueryExecutor::getConnection(), getAllOlmPersistSessionsSQL); -} + std::vector + SQLiteQueryExecutor::getOlmPersistSessionsData() const { + static std::string getAllOlmPersistSessionsSQL = + "SELECT * " + "FROM olm_persist_sessions;"; + return getAllEntities( + SQLiteQueryExecutor::getConnection(), getAllOlmPersistSessionsSQL); + } -std::optional -SQLiteQueryExecutor::getOlmPersistAccountData() const { - static std::string getAllOlmPersistAccountSQL = - "SELECT * " - "FROM olm_persist_account;"; - std::vector result = getAllEntities( - SQLiteQueryExecutor::getConnection(), getAllOlmPersistAccountSQL); - if (result.size() > 1) { - throw std::system_error( - ECANCELED, - std::generic_category(), - "Multiple records found for the olm_persist_account table"); - } - return (result.size() == 0) - ? std::nullopt - : std::optional(result[0].account_data); -} + std::optional SQLiteQueryExecutor::getOlmPersistAccountData() + const { + static std::string getAllOlmPersistAccountSQL = + "SELECT * " + "FROM olm_persist_account;"; + std::vector result = getAllEntities( + SQLiteQueryExecutor::getConnection(), getAllOlmPersistAccountSQL); + if (result.size() > 1) { + throw std::system_error( + ECANCELED, + std::generic_category(), + "Multiple records found for the olm_persist_account table"); + } + return (result.size() == 0) + ? std::nullopt + : std::optional(result[0].account_data); + } -void SQLiteQueryExecutor::storeOlmPersistAccount( - const std::string &accountData) const { - static std::string replaceOlmPersistAccountSQL = - "REPLACE INTO olm_persist_account (id, account_data) " - "VALUES (?, ?);"; + void SQLiteQueryExecutor::storeOlmPersistAccount( + const std::string &accountData) const { + static std::string replaceOlmPersistAccountSQL = + "REPLACE INTO olm_persist_account (id, account_data) " + "VALUES (?, ?);"; - OlmPersistAccount persistAccount = {ACCOUNT_ID, accountData}; + OlmPersistAccount persistAccount = {ACCOUNT_ID, accountData}; - replaceEntity( - SQLiteQueryExecutor::getConnection(), - replaceOlmPersistAccountSQL, - persistAccount); -} + replaceEntity( + SQLiteQueryExecutor::getConnection(), + replaceOlmPersistAccountSQL, + persistAccount); + } -void SQLiteQueryExecutor::storeOlmPersistSession( - const OlmPersistSession &session) const { - static std::string replaceOlmPersistSessionSQL = - "REPLACE INTO olm_persist_sessions (target_user_id, session_data) " - "VALUES (?, ?);"; + void SQLiteQueryExecutor::storeOlmPersistSession( + const OlmPersistSession &session) const { + static std::string replaceOlmPersistSessionSQL = + "REPLACE INTO olm_persist_sessions (target_user_id, session_data) " + "VALUES (?, ?);"; - replaceEntity( - SQLiteQueryExecutor::getConnection(), - replaceOlmPersistSessionSQL, - session); -} + replaceEntity( + SQLiteQueryExecutor::getConnection(), + replaceOlmPersistSessionSQL, + session); + } -void SQLiteQueryExecutor::storeOlmPersistData(crypto::Persist persist) const { - std::string accountData = - std::string(persist.account.begin(), persist.account.end()); + void SQLiteQueryExecutor::storeOlmPersistData(crypto::Persist persist) + const { + std::string accountData = + std::string(persist.account.begin(), persist.account.end()); - for (auto it = persist.sessions.begin(); it != persist.sessions.end(); it++) { - OlmPersistSession persistSession = { - it->first, std::string(it->second.begin(), it->second.end())}; - this->storeOlmPersistSession(persistSession); - } -} + for (auto it = persist.sessions.begin(); it != persist.sessions.end(); + it++) { + OlmPersistSession persistSession = { + it->first, std::string(it->second.begin(), it->second.end())}; + this->storeOlmPersistSession(persistSession); + } + } -void SQLiteQueryExecutor::setNotifyToken(std::string token) const { - this->setMetadata("notify_token", token); -} + void SQLiteQueryExecutor::setNotifyToken(std::string token) const { + this->setMetadata("notify_token", token); + } -void SQLiteQueryExecutor::clearNotifyToken() const { - this->clearMetadata("notify_token"); -} + void SQLiteQueryExecutor::clearNotifyToken() const { + this->clearMetadata("notify_token"); + } -void SQLiteQueryExecutor::setCurrentUserID(std::string userID) const { - this->setMetadata("current_user_id", userID); -} + void SQLiteQueryExecutor::setCurrentUserID(std::string userID) const { + this->setMetadata("current_user_id", userID); + } -std::string SQLiteQueryExecutor::getCurrentUserID() const { - return this->getMetadata("current_user_id"); -} + std::string SQLiteQueryExecutor::getCurrentUserID() const { + return this->getMetadata("current_user_id"); + } -void SQLiteQueryExecutor::setMetadata(std::string entry_name, std::string data) - const { - std::string replaceMetadataSQL = - "REPLACE INTO metadata (name, data) " - "VALUES (?, ?);"; - Metadata entry{ - entry_name, - data, - }; - replaceEntity( - SQLiteQueryExecutor::getConnection(), replaceMetadataSQL, entry); -} + void SQLiteQueryExecutor::setMetadata( + std::string entry_name, std::string data) const { + std::string replaceMetadataSQL = + "REPLACE INTO metadata (name, data) " + "VALUES (?, ?);"; + Metadata entry{ + entry_name, + data, + }; + replaceEntity( + SQLiteQueryExecutor::getConnection(), replaceMetadataSQL, entry); + } -void SQLiteQueryExecutor::clearMetadata(std::string entry_name) const { - static std::string removeMetadataByKeySQL = - "DELETE FROM metadata " - "WHERE name IN (?);"; - std::vector keys = {entry_name}; - removeEntitiesByKeys( - SQLiteQueryExecutor::getConnection(), removeMetadataByKeySQL, keys); -} + void SQLiteQueryExecutor::clearMetadata(std::string entry_name) const { + static std::string removeMetadataByKeySQL = + "DELETE FROM metadata " + "WHERE name IN (?);"; + std::vector keys = {entry_name}; + removeEntitiesByKeys( + SQLiteQueryExecutor::getConnection(), removeMetadataByKeySQL, keys); + } -std::string SQLiteQueryExecutor::getMetadata(std::string entry_name) const { - std::string getMetadataByPrimaryKeySQL = - "SELECT * " - "FROM metadata " - "WHERE name = ?;"; - std::unique_ptr entry = getEntityByPrimaryKey( - SQLiteQueryExecutor::getConnection(), - getMetadataByPrimaryKeySQL, - entry_name); - return (entry == nullptr) ? "" : entry->data; -} + std::string SQLiteQueryExecutor::getMetadata(std::string entry_name) const { + std::string getMetadataByPrimaryKeySQL = + "SELECT * " + "FROM metadata " + "WHERE name = ?;"; + std::unique_ptr entry = getEntityByPrimaryKey( + SQLiteQueryExecutor::getConnection(), + getMetadataByPrimaryKeySQL, + entry_name); + return (entry == nullptr) ? "" : entry->data; + } #ifdef EMSCRIPTEN -std::vector SQLiteQueryExecutor::getAllThreadsWeb() const { - auto threads = this->getAllThreads(); - std::vector webThreads; - webThreads.reserve(threads.size()); - for (const auto &thread : threads) { - webThreads.emplace_back(thread); - } - return webThreads; -}; + std::vector SQLiteQueryExecutor::getAllThreadsWeb() const { + auto threads = this->getAllThreads(); + std::vector webThreads; + webThreads.reserve(threads.size()); + for (const auto &thread : threads) { + webThreads.emplace_back(thread); + } + return webThreads; + }; -void SQLiteQueryExecutor::replaceThreadWeb(const WebThread &thread) const { - this->replaceThread(thread.toThread()); -}; + void SQLiteQueryExecutor::replaceThreadWeb(const WebThread &thread) const { + this->replaceThread(thread.toThread()); + }; -std::vector SQLiteQueryExecutor::getAllMessagesWeb() const { - auto allMessages = this->getAllMessages(); + std::vector SQLiteQueryExecutor::getAllMessagesWeb() + const { + auto allMessages = this->getAllMessages(); - std::vector allMessageWithMedias; - for (auto &messageWitMedia : allMessages) { - allMessageWithMedias.push_back( - {std::move(messageWitMedia.first), messageWitMedia.second}); - } + std::vector allMessageWithMedias; + for (auto &messageWitMedia : allMessages) { + allMessageWithMedias.push_back( + {std::move(messageWitMedia.first), messageWitMedia.second}); + } - return allMessageWithMedias; -} + return allMessageWithMedias; + } -void SQLiteQueryExecutor::replaceMessageWeb(const WebMessage &message) const { - this->replaceMessage(message.toMessage()); -}; + void SQLiteQueryExecutor::replaceMessageWeb(const WebMessage &message) + const { + this->replaceMessage(message.toMessage()); + }; -NullableString SQLiteQueryExecutor::getOlmPersistAccountDataWeb() const { - std::optional accountData = this->getOlmPersistAccountData(); - if (!accountData.has_value()) { - return NullableString(); - } - return std::make_unique(accountData.value()); -} + NullableString SQLiteQueryExecutor::getOlmPersistAccountDataWeb() const { + std::optional accountData = this->getOlmPersistAccountData(); + if (!accountData.has_value()) { + return NullableString(); + } + return std::make_unique(accountData.value()); + } #else -void SQLiteQueryExecutor::clearSensitiveData() { - SQLiteQueryExecutor::closeConnection(); - if (file_exists(SQLiteQueryExecutor::sqliteFilePath) && - std::remove(SQLiteQueryExecutor::sqliteFilePath.c_str())) { - std::ostringstream errorStream; - errorStream << "Failed to delete database file. Details: " - << strerror(errno); - throw std::system_error(errno, std::generic_category(), errorStream.str()); - } - SQLiteQueryExecutor::assign_encryption_key(); - SQLiteQueryExecutor::migrate(); -} - -void SQLiteQueryExecutor::initialize(std::string &databasePath) { - std::call_once(SQLiteQueryExecutor::initialized, [&databasePath]() { - SQLiteQueryExecutor::sqliteFilePath = databasePath; - folly::Optional maybeEncryptionKey = - CommSecureStore::get(SQLiteQueryExecutor::secureStoreEncryptionKeyID); - folly::Optional maybeBackupLogsEncryptionKey = - CommSecureStore::get( - SQLiteQueryExecutor::secureStoreBackupLogsEncryptionKeyID); - - if (file_exists(databasePath) && maybeEncryptionKey && - maybeBackupLogsEncryptionKey) { - SQLiteQueryExecutor::encryptionKey = maybeEncryptionKey.value(); - SQLiteQueryExecutor::backupLogsEncryptionKey = - maybeBackupLogsEncryptionKey.value(); - return; - } - SQLiteQueryExecutor::assign_encryption_key(); - }); -} - -void SQLiteQueryExecutor::createMainCompaction(std::string backupID) const { - std::string finalBackupPath = - PlatformSpecificTools::getBackupFilePath(backupID, false); - std::string finalAttachmentsPath = - PlatformSpecificTools::getBackupFilePath(backupID, true); - - std::string tempBackupPath = finalBackupPath + "_tmp"; - std::string tempAttachmentsPath = finalAttachmentsPath + "_tmp"; - - if (file_exists(tempBackupPath)) { - Logger::log( - "Attempting to delete temporary backup file from previous backup " - "attempt."); - attempt_delete_file( - tempBackupPath, - "Failed to delete temporary backup file from previous backup attempt."); - } + void SQLiteQueryExecutor::clearSensitiveData() { + SQLiteQueryExecutor::closeConnection(); + if (file_exists(SQLiteQueryExecutor::sqliteFilePath) && + std::remove(SQLiteQueryExecutor::sqliteFilePath.c_str())) { + std::ostringstream errorStream; + errorStream << "Failed to delete database file. Details: " + << strerror(errno); + throw std::system_error( + errno, std::generic_category(), errorStream.str()); + } + SQLiteQueryExecutor::assign_encryption_key(); + SQLiteQueryExecutor::migrate(); + } - if (file_exists(tempAttachmentsPath)) { - Logger::log( - "Attempting to delete temporary attachments file from previous backup " - "attempt."); - attempt_delete_file( - tempAttachmentsPath, - "Failed to delete temporary attachments file from previous backup " - "attempt."); - } + void SQLiteQueryExecutor::initialize(std::string & databasePath) { + std::call_once(SQLiteQueryExecutor::initialized, [&databasePath]() { + SQLiteQueryExecutor::sqliteFilePath = databasePath; + folly::Optional maybeEncryptionKey = CommSecureStore::get( + SQLiteQueryExecutor::secureStoreEncryptionKeyID); + folly::Optional maybeBackupLogsEncryptionKey = + CommSecureStore::get( + SQLiteQueryExecutor::secureStoreBackupLogsEncryptionKeyID); + + if (file_exists(databasePath) && maybeEncryptionKey && + maybeBackupLogsEncryptionKey) { + SQLiteQueryExecutor::encryptionKey = maybeEncryptionKey.value(); + SQLiteQueryExecutor::backupLogsEncryptionKey = + maybeBackupLogsEncryptionKey.value(); + return; + } + SQLiteQueryExecutor::assign_encryption_key(); + }); + } - sqlite3 *backupDB; - sqlite3_open(tempBackupPath.c_str(), &backupDB); - set_encryption_key(backupDB); - - sqlite3_backup *backupObj = sqlite3_backup_init( - backupDB, "main", SQLiteQueryExecutor::getConnection(), "main"); - if (!backupObj) { - std::stringstream error_message; - error_message << "Failed to init backup for main compaction. Details: " - << sqlite3_errmsg(backupDB) << std::endl; - sqlite3_close(backupDB); - throw std::runtime_error(error_message.str()); - } + void SQLiteQueryExecutor::createMainCompaction(std::string backupID) const { + std::string finalBackupPath = + PlatformSpecificTools::getBackupFilePath(backupID, false); + std::string finalAttachmentsPath = + PlatformSpecificTools::getBackupFilePath(backupID, true); + + std::string tempBackupPath = finalBackupPath + "_tmp"; + std::string tempAttachmentsPath = finalAttachmentsPath + "_tmp"; + + if (file_exists(tempBackupPath)) { + Logger::log( + "Attempting to delete temporary backup file from previous backup " + "attempt."); + attempt_delete_file( + tempBackupPath, + "Failed to delete temporary backup file from previous backup " + "attempt."); + } - int backupResult = sqlite3_backup_step(backupObj, -1); - sqlite3_backup_finish(backupObj); - if (backupResult == SQLITE_BUSY || backupResult == SQLITE_LOCKED) { - sqlite3_close(backupDB); - throw std::runtime_error( - "Programmer error. Database in transaction during backup attempt."); - } else if (backupResult != SQLITE_DONE) { - sqlite3_close(backupDB); - std::stringstream error_message; - error_message << "Failed to create database backup. Details: " - << sqlite3_errstr(backupResult); - throw std::runtime_error(error_message.str()); - } - executeQuery(backupDB, "VACUUM;"); - sqlite3_close(backupDB); + if (file_exists(tempAttachmentsPath)) { + Logger::log( + "Attempting to delete temporary attachments file from previous " + "backup " + "attempt."); + attempt_delete_file( + tempAttachmentsPath, + "Failed to delete temporary attachments file from previous backup " + "attempt."); + } - attempt_rename_file( - tempBackupPath, - finalBackupPath, - "Failed to rename complete temporary backup file to final backup file."); - - std::ofstream tempAttachmentsFile(tempAttachmentsPath); - if (!tempAttachmentsFile.is_open()) { - throw std::runtime_error( - "Unable to create attachments file for backup id: " + backupID); - } + sqlite3 *backupDB; + sqlite3_open(tempBackupPath.c_str(), &backupDB); + set_encryption_key(backupDB); + + sqlite3_backup *backupObj = sqlite3_backup_init( + backupDB, "main", SQLiteQueryExecutor::getConnection(), "main"); + if (!backupObj) { + std::stringstream error_message; + error_message << "Failed to init backup for main compaction. Details: " + << sqlite3_errmsg(backupDB) << std::endl; + sqlite3_close(backupDB); + throw std::runtime_error(error_message.str()); + } - std::string getAllBlobServiceMediaSQL = - "SELECT * FROM media WHERE uri LIKE 'comm-blob-service://%';"; - std::vector blobServiceMedia = getAllEntities( - SQLiteQueryExecutor::getConnection(), getAllBlobServiceMediaSQL); + int backupResult = sqlite3_backup_step(backupObj, -1); + sqlite3_backup_finish(backupObj); + if (backupResult == SQLITE_BUSY || backupResult == SQLITE_LOCKED) { + sqlite3_close(backupDB); + throw std::runtime_error( + "Programmer error. Database in transaction during backup attempt."); + } else if (backupResult != SQLITE_DONE) { + sqlite3_close(backupDB); + std::stringstream error_message; + error_message << "Failed to create database backup. Details: " + << sqlite3_errstr(backupResult); + throw std::runtime_error(error_message.str()); + } + executeQuery(backupDB, "VACUUM;"); + sqlite3_close(backupDB); + + attempt_rename_file( + tempBackupPath, + finalBackupPath, + "Failed to rename complete temporary backup file to final backup " + "file."); + + std::ofstream tempAttachmentsFile(tempAttachmentsPath); + if (!tempAttachmentsFile.is_open()) { + throw std::runtime_error( + "Unable to create attachments file for backup id: " + backupID); + } - for (const auto &media : blobServiceMedia) { - std::string blobServiceURI = media.uri; - std::string blobHash = blob_hash_from_blob_service_uri(blobServiceURI); - tempAttachmentsFile << blobHash << "\n"; - } - tempAttachmentsFile.close(); + std::string getAllBlobServiceMediaSQL = + "SELECT * FROM media WHERE uri LIKE 'comm-blob-service://%';"; + std::vector blobServiceMedia = getAllEntities( + SQLiteQueryExecutor::getConnection(), getAllBlobServiceMediaSQL); - attempt_rename_file( - tempAttachmentsPath, - finalAttachmentsPath, - "Failed to rename complete temporary attachments file to final " - "attachments file."); - - this->setMetadata("backupID", backupID); - this->clearMetadata("logID"); - if (StaffUtils::isStaffRelease()) { - SQLiteQueryExecutor::connectionManager.setLogsMonitoring(true); - } -} + for (const auto &media : blobServiceMedia) { + std::string blobServiceURI = media.uri; + std::string blobHash = blob_hash_from_blob_service_uri(blobServiceURI); + tempAttachmentsFile << blobHash << "\n"; + } + tempAttachmentsFile.close(); + + attempt_rename_file( + tempAttachmentsPath, + finalAttachmentsPath, + "Failed to rename complete temporary attachments file to final " + "attachments file."); + + this->setMetadata("backupID", backupID); + this->clearMetadata("logID"); + if (StaffUtils::isStaffRelease()) { + SQLiteQueryExecutor::connectionManager.setLogsMonitoring(true); + } + } -void SQLiteQueryExecutor::assign_encryption_key() { - std::string encryptionKey = comm::crypto::Tools::generateRandomHexString( - SQLiteQueryExecutor::sqlcipherEncryptionKeySize); - std::string backupLogsEncryptionKey = - comm::crypto::Tools::generateRandomHexString( - SQLiteQueryExecutor::backupLogsEncryptionKeySize); - CommSecureStore::set( - SQLiteQueryExecutor::secureStoreEncryptionKeyID, encryptionKey); - CommSecureStore::set( - SQLiteQueryExecutor::secureStoreBackupLogsEncryptionKeyID, - backupLogsEncryptionKey); - SQLiteQueryExecutor::encryptionKey = encryptionKey; - SQLiteQueryExecutor::backupLogsEncryptionKey = backupLogsEncryptionKey; -} + void SQLiteQueryExecutor::assign_encryption_key() { + std::string encryptionKey = comm::crypto::Tools::generateRandomHexString( + SQLiteQueryExecutor::sqlcipherEncryptionKeySize); + std::string backupLogsEncryptionKey = + comm::crypto::Tools::generateRandomHexString( + SQLiteQueryExecutor::backupLogsEncryptionKeySize); + CommSecureStore::set( + SQLiteQueryExecutor::secureStoreEncryptionKeyID, encryptionKey); + CommSecureStore::set( + SQLiteQueryExecutor::secureStoreBackupLogsEncryptionKeyID, + backupLogsEncryptionKey); + SQLiteQueryExecutor::encryptionKey = encryptionKey; + SQLiteQueryExecutor::backupLogsEncryptionKey = backupLogsEncryptionKey; + } -void SQLiteQueryExecutor::captureBackupLogs() const { - std::string backupID = this->getMetadata("backupID"); - if (!backupID.size()) { - return; - } + void SQLiteQueryExecutor::captureBackupLogs() const { + std::string backupID = this->getMetadata("backupID"); + if (!backupID.size()) { + return; + } - std::string logID = this->getMetadata("logID"); - if (!logID.size()) { - logID = "0"; - } + std::string logID = this->getMetadata("logID"); + if (!logID.size()) { + logID = "0"; + } - bool newLogCreated = SQLiteQueryExecutor::connectionManager.captureLogs( - backupID, logID, SQLiteQueryExecutor::backupLogsEncryptionKey); - if (!newLogCreated) { - return; - } - this->setMetadata("logID", std::to_string(std::stoi(logID) + 1)); -} + bool newLogCreated = SQLiteQueryExecutor::connectionManager.captureLogs( + backupID, logID, SQLiteQueryExecutor::backupLogsEncryptionKey); + if (!newLogCreated) { + return; + } + this->setMetadata("logID", std::to_string(std::stoi(logID) + 1)); + } #endif -void SQLiteQueryExecutor::restoreFromMainCompaction( - std::string mainCompactionPath, - std::string mainCompactionEncryptionKey) const { + void SQLiteQueryExecutor::restoreFromMainCompaction( + std::string mainCompactionPath, std::string mainCompactionEncryptionKey) + const { - if (!file_exists(mainCompactionPath)) { - throw std::runtime_error("Restore attempt but backup file does not exist."); - } + if (!file_exists(mainCompactionPath)) { + throw std::runtime_error( + "Restore attempt but backup file does not exist."); + } - sqlite3 *backupDB; - if (!is_database_queryable( - backupDB, true, mainCompactionPath, mainCompactionEncryptionKey)) { - throw std::runtime_error("Backup file or encryption key corrupted."); - } + sqlite3 *backupDB; + if (!is_database_queryable( + backupDB, + true, + mainCompactionPath, + mainCompactionEncryptionKey)) { + throw std::runtime_error("Backup file or encryption key corrupted."); + } // We don't want to run `PRAGMA key = ...;` // on main web database. The context is here: // https://linear.app/comm/issue/ENG-6398/issues-with-sqlcipher-on-web #ifdef EMSCRIPTEN - std::string plaintextBackupPath = mainCompactionPath + "_plaintext"; - if (file_exists(plaintextBackupPath)) { - attempt_delete_file( - plaintextBackupPath, - "Failed to delete plaintext backup file from previous backup attempt."); - } - - std::string plaintextMigrationDBQuery = "PRAGMA key = \"x'" + - mainCompactionEncryptionKey + - "'\";" - "ATTACH DATABASE '" + - plaintextBackupPath + - "' AS plaintext KEY '';" - "SELECT sqlcipher_export('plaintext');" - "DETACH DATABASE plaintext;"; - - sqlite3_open(mainCompactionPath.c_str(), &backupDB); + std::string plaintextBackupPath = mainCompactionPath + "_plaintext"; + if (file_exists(plaintextBackupPath)) { + attempt_delete_file( + plaintextBackupPath, + "Failed to delete plaintext backup file from previous backup " + "attempt."); + } - char *plaintextMigrationErr; - sqlite3_exec( - backupDB, - plaintextMigrationDBQuery.c_str(), - nullptr, - nullptr, - &plaintextMigrationErr); - sqlite3_close(backupDB); - - if (plaintextMigrationErr) { - std::stringstream error_message; - error_message << "Failed to migrate backup SQLCipher file to plaintext " - "SQLite file. Details" - << plaintextMigrationErr << std::endl; - std::string error_message_str = error_message.str(); - sqlite3_free(plaintextMigrationErr); - - throw std::runtime_error(error_message_str); - } + std::string plaintextMigrationDBQuery = "PRAGMA key = \"x'" + + mainCompactionEncryptionKey + + "'\";" + "ATTACH DATABASE '" + + plaintextBackupPath + + "' AS plaintext KEY '';" + "SELECT sqlcipher_export('plaintext');" + "DETACH DATABASE plaintext;"; + + sqlite3_open(mainCompactionPath.c_str(), &backupDB); + + char *plaintextMigrationErr; + sqlite3_exec( + backupDB, + plaintextMigrationDBQuery.c_str(), + nullptr, + nullptr, + &plaintextMigrationErr); + sqlite3_close(backupDB); + + if (plaintextMigrationErr) { + std::stringstream error_message; + error_message << "Failed to migrate backup SQLCipher file to plaintext " + "SQLite file. Details" + << plaintextMigrationErr << std::endl; + std::string error_message_str = error_message.str(); + sqlite3_free(plaintextMigrationErr); + + throw std::runtime_error(error_message_str); + } - sqlite3_open(plaintextBackupPath.c_str(), &backupDB); + sqlite3_open(plaintextBackupPath.c_str(), &backupDB); #else - sqlite3_open(mainCompactionPath.c_str(), &backupDB); - set_encryption_key(backupDB, mainCompactionEncryptionKey); + sqlite3_open(mainCompactionPath.c_str(), &backupDB); + set_encryption_key(backupDB, mainCompactionEncryptionKey); #endif - sqlite3_backup *backupObj = sqlite3_backup_init( - SQLiteQueryExecutor::getConnection(), "main", backupDB, "main"); - if (!backupObj) { - std::stringstream error_message; - error_message << "Failed to init backup for main compaction. Details: " - << sqlite3_errmsg(SQLiteQueryExecutor::getConnection()) - << std::endl; - sqlite3_close(backupDB); - throw std::runtime_error(error_message.str()); - } + sqlite3_backup *backupObj = sqlite3_backup_init( + SQLiteQueryExecutor::getConnection(), "main", backupDB, "main"); + if (!backupObj) { + std::stringstream error_message; + error_message << "Failed to init backup for main compaction. Details: " + << sqlite3_errmsg(SQLiteQueryExecutor::getConnection()) + << std::endl; + sqlite3_close(backupDB); + throw std::runtime_error(error_message.str()); + } - int backupResult = sqlite3_backup_step(backupObj, -1); - sqlite3_backup_finish(backupObj); - sqlite3_close(backupDB); - if (backupResult == SQLITE_BUSY || backupResult == SQLITE_LOCKED) { - throw std::runtime_error( - "Programmer error. Database in transaction during restore attempt."); - } else if (backupResult != SQLITE_DONE) { - std::stringstream error_message; - error_message << "Failed to restore database from backup. Details: " - << sqlite3_errstr(backupResult); - throw std::runtime_error(error_message.str()); - } + int backupResult = sqlite3_backup_step(backupObj, -1); + sqlite3_backup_finish(backupObj); + sqlite3_close(backupDB); + if (backupResult == SQLITE_BUSY || backupResult == SQLITE_LOCKED) { + throw std::runtime_error( + "Programmer error. Database in transaction during restore " + "attempt."); + } else if (backupResult != SQLITE_DONE) { + std::stringstream error_message; + error_message << "Failed to restore database from backup. Details: " + << sqlite3_errstr(backupResult); + throw std::runtime_error(error_message.str()); + } #ifdef EMSCRIPTEN - attempt_delete_file( - plaintextBackupPath, - "Failed to delete plaintext compaction file after successful restore."); + attempt_delete_file( + plaintextBackupPath, + "Failed to delete plaintext compaction file after successful " + "restore."); #endif - attempt_delete_file( - mainCompactionPath, - "Failed to delete main compaction file after successful restore."); -} + attempt_delete_file( + mainCompactionPath, + "Failed to delete main compaction file after successful restore."); + } -void SQLiteQueryExecutor::restoreFromBackupLog( - const std::vector &backupLog) const { - SQLiteQueryExecutor::connectionManager.restoreFromBackupLog(backupLog); -} + void SQLiteQueryExecutor::restoreFromBackupLog( + const std::vector &backupLog) const { + SQLiteQueryExecutor::connectionManager.restoreFromBackupLog(backupLog); + } -} // namespace comm + } // namespace comm