diff --git a/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h b/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h --- a/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h +++ b/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h @@ -1,6 +1,7 @@ #pragma once #include "../CryptoTools/Persist.h" +#include "entities/AuxUserInfo.h" #include "entities/CommunityInfo.h" #include "entities/Draft.h" #include "entities/IntegrityThreadHash.h" @@ -93,6 +94,11 @@ removeSyncedMetadata(const std::vector &names) const = 0; virtual void removeAllSyncedMetadata() const = 0; virtual std::vector getAllSyncedMetadata() const = 0; + virtual void replaceAuxUserInfo(const AuxUserInfo &aux_user_info) const = 0; + virtual void + removeAuxUserInfos(const std::vector &ids) const = 0; + virtual void removeAllAuxUserInfos() const = 0; + virtual std::vector getAllAuxUserInfos() const = 0; virtual void beginTransaction() const = 0; virtual void commitTransaction() const = 0; virtual void rollbackTransaction() const = 0; diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h --- a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h +++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h @@ -3,6 +3,7 @@ #include "../CryptoTools/Persist.h" #include "DatabaseQueryExecutor.h" #include "NativeSQLiteConnectionManager.h" +#include "entities/AuxUserInfo.h" #include "entities/CommunityInfo.h" #include "entities/Draft.h" #include "entities/IntegrityThreadHash.h" @@ -108,6 +109,10 @@ removeSyncedMetadata(const std::vector &names) const override; void removeAllSyncedMetadata() const override; std::vector getAllSyncedMetadata() const override; + void replaceAuxUserInfo(const AuxUserInfo &aux_user_info) const override; + void removeAuxUserInfos(const std::vector &ids) const override; + void removeAllAuxUserInfos() const override; + virtual std::vector getAllAuxUserInfos() const override; void beginTransaction() const override; void commitTransaction() const override; void rollbackTransaction() const override; 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 @@ -1816,6 +1816,48 @@ SQLiteQueryExecutor::getConnection(), getAllSyncedMetadataSQL); } +void SQLiteQueryExecutor::replaceAuxUserInfo( + const AuxUserInfo &aux_user_info) const { + static std::string replaceAuxUserInfoSQL = + "REPLACE INTO aux_users (id, aux_user_info) " + "VALUES (?, ?);"; + replaceEntity( + SQLiteQueryExecutor::getConnection(), + replaceAuxUserInfoSQL, + aux_user_info); +} + +void SQLiteQueryExecutor::removeAllAuxUserInfos() const { + static std::string removeAllAuxUserInfosSQL = "DELETE FROM aux_users;"; + removeAllEntities( + SQLiteQueryExecutor::getConnection(), removeAllAuxUserInfosSQL); +} + +void SQLiteQueryExecutor::removeAuxUserInfos( + const std::vector &ids) const { + if (!ids.size()) { + return; + } + + std::stringstream removeAuxUserInfosByKeysSQLStream; + removeAuxUserInfosByKeysSQLStream << "DELETE FROM aux_users " + "WHERE id IN " + << getSQLStatementArray(ids.size()) << ";"; + + removeEntitiesByKeys( + SQLiteQueryExecutor::getConnection(), + removeAuxUserInfosByKeysSQLStream.str(), + ids); +} + +std::vector SQLiteQueryExecutor::getAllAuxUserInfos() const { + static std::string getAllAuxUserInfosSQL = + "SELECT * " + "FROM aux_users;"; + return getAllEntities( + SQLiteQueryExecutor::getConnection(), getAllAuxUserInfosSQL); +} + void SQLiteQueryExecutor::beginTransaction() const { executeQuery(SQLiteQueryExecutor::getConnection(), "BEGIN TRANSACTION;"); } diff --git a/native/cpp/CommonCpp/DatabaseManagers/entities/AuxUserInfo.h b/native/cpp/CommonCpp/DatabaseManagers/entities/AuxUserInfo.h new file mode 100644 --- /dev/null +++ b/native/cpp/CommonCpp/DatabaseManagers/entities/AuxUserInfo.h @@ -0,0 +1,24 @@ +#pragma once + +#include "SQLiteDataConverters.h" +#include +#include + +namespace comm { + +struct AuxUserInfo { + std::string id; + std::string aux_user_info; + + static AuxUserInfo fromSQLResult(sqlite3_stmt *sqlRow, int idx) { + return AuxUserInfo{ + getStringFromSQLRow(sqlRow, idx), getStringFromSQLRow(sqlRow, idx + 1)}; + } + + int bindToSQL(sqlite3_stmt *sql, int idx) const { + bindStringToSQL(id, sql, idx); + return bindStringToSQL(aux_user_info, sql, idx + 1); + } +}; + +} // namespace comm diff --git a/web/cpp/SQLiteQueryExecutorBindings.cpp b/web/cpp/SQLiteQueryExecutorBindings.cpp --- a/web/cpp/SQLiteQueryExecutorBindings.cpp +++ b/web/cpp/SQLiteQueryExecutorBindings.cpp @@ -59,6 +59,9 @@ value_object("SyncedMetadataEntry") .field("name", &SyncedMetadataEntry::name) .field("data", &SyncedMetadataEntry::data); + value_object("AuxUserInfo") + .field("id", &AuxUserInfo::id) + .field("auxUserInfo", &AuxUserInfo::aux_user_info); value_object("WebThread") .field("id", &WebThread::id) @@ -204,6 +207,11 @@ &SQLiteQueryExecutor::removeAllSyncedMetadata) .function( "getAllSyncedMetadata", &SQLiteQueryExecutor::getAllSyncedMetadata) + .function("replaceAuxUserInfo", &SQLiteQueryExecutor::replaceAuxUserInfo) + .function("removeAuxUserInfos", &SQLiteQueryExecutor::removeAuxUserInfos) + .function( + "removeAllAuxUserInfos", &SQLiteQueryExecutor::removeAllAuxUserInfos) + .function("getAllAuxUserInfos", &SQLiteQueryExecutor::getAllAuxUserInfos) .function("beginTransaction", &SQLiteQueryExecutor::beginTransaction) .function("commitTransaction", &SQLiteQueryExecutor::commitTransaction) .function( diff --git a/web/shared-worker/_generated/comm_query_executor.wasm b/web/shared-worker/_generated/comm_query_executor.wasm index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@ { + let queryExecutor: ?SQLiteQueryExecutor = null; + let dbModule: ?EmscriptenModule = null; + + beforeAll(async () => { + dbModule = getDatabaseModule(); + }); + + beforeEach(() => { + if (!dbModule) { + throw new Error('Database module is missing'); + } + queryExecutor = new dbModule.SQLiteQueryExecutor(FILE_PATH); + if (!queryExecutor) { + throw new Error('SQLiteQueryExecutor is missing'); + } + queryExecutor?.replaceAuxUserInfo({ + id: 'test_id_1', + auxUserInfo: JSON.stringify({ fid: 'test_aux_user_info_1' }), + }); + queryExecutor?.replaceAuxUserInfo({ + id: 'test_id_2', + auxUserInfo: JSON.stringify({ fid: 'test_aux_user_info_2' }), + }); + queryExecutor?.replaceAuxUserInfo({ + id: 'test_id_3', + auxUserInfo: JSON.stringify({ fid: 'test_aux_user_info_3' }), + }); + }); + + afterEach(() => { + if (!dbModule || !queryExecutor) { + return; + } + + clearSensitiveData(dbModule, FILE_PATH, queryExecutor); + }); + + it('should return all aux user infos', () => { + const auxUserInfos = queryExecutor?.getAllAuxUserInfos(); + + expect(auxUserInfos).toHaveLength(3); + }); + + it('should remove all aux user infos', () => { + queryExecutor?.removeAllAuxUserInfos(); + const auxUserInfos = queryExecutor?.getAllAuxUserInfos(); + + expect(auxUserInfos).toHaveLength(0); + }); + + it('should update aux user info test_id_2', () => { + queryExecutor?.replaceAuxUserInfo({ + id: 'test_id_2', + auxUserInfo: JSON.stringify({ fid: 'update_aux_user_info_2' }), + }); + + const auxUserInfos = queryExecutor?.getAllAuxUserInfos(); + if (!auxUserInfos) { + throw new Error('aux user infos not defined'); + } + + expect(auxUserInfos).toHaveLength(3); + + const auxUserInfosFromDB = + auxUserStoreOpsHandlers.translateClientDBData(auxUserInfos); + + expect(auxUserInfosFromDB['test_id_2']).toBeDefined(); + expect(auxUserInfosFromDB['test_id_2'].fid).toBe('update_aux_user_info_2'); + }); + + it('should remove aux user infos test_id_1 and test_id_3', () => { + queryExecutor?.removeAuxUserInfos(['test_id_1', 'test_id_3']); + + const auxUserInfos = queryExecutor?.getAllAuxUserInfos(); + if (!auxUserInfos) { + throw new Error('aux user infos not defined'); + } + + expect(auxUserInfos.length).toBe(1); + + const auxUserInfosFromDB = + auxUserStoreOpsHandlers.translateClientDBData(auxUserInfos); + + expect(auxUserInfosFromDB['test_id_2']).toBeDefined(); + }); +}); diff --git a/web/shared-worker/types/sqlite-query-executor.js b/web/shared-worker/types/sqlite-query-executor.js --- a/web/shared-worker/types/sqlite-query-executor.js +++ b/web/shared-worker/types/sqlite-query-executor.js @@ -1,5 +1,6 @@ // @flow +import type { ClientDBAuxUserInfo } from 'lib/ops/aux-user-store-ops.js'; import type { ClientDBCommunityInfo } from 'lib/ops/community-store-ops.js'; import type { ClientDBIntegrityThreadHash } from 'lib/ops/integrity-store-ops.js'; import type { ClientDBKeyserverInfo } from 'lib/ops/keyserver-store-ops.js'; @@ -129,6 +130,10 @@ removeSyncedMetadata(names: $ReadOnlyArray): void; removeAllSyncedMetadata(): void; getAllSyncedMetadata(): ClientDBSyncedMetadataEntry[]; + replaceAuxUserInfo(auxUserInfo: ClientDBAuxUserInfo): void; + removeAuxUserInfos(ids: $ReadOnlyArray): void; + removeAllAuxUserInfos(): void; + getAllAuxUserInfos(): ClientDBAuxUserInfo[]; beginTransaction(): void; commitTransaction(): void;