Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F32179166
D14974.1765072111.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D14974.1765072111.diff
View Options
diff --git a/lib/reducers/db-ops-reducer.js b/lib/reducers/db-ops-reducer.js
--- a/lib/reducers/db-ops-reducer.js
+++ b/lib/reducers/db-ops-reducer.js
@@ -22,6 +22,9 @@
return store;
}
+// There is a similar code for creating a search index after restore.
+// Before making any changes here, please reference
+// `copyContentFromDatabase` in `SQLiteQueryExecutor.cpp`.
function getMessageSearchStoreOps(
messageStoreOps: ?$ReadOnlyArray<MessageStoreOperation>,
): $ReadOnlyArray<MessageSearchStoreOperation> {
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
@@ -1714,6 +1714,49 @@
sql << "INSERT OR IGNORE INTO " << tableName << " SELECT *"
<< " FROM sourceDB." << tableName << ";" << std::endl;
}
+
+ // There is a similar code for "live" index processing. Before making any
+ // changes here, please reference `getMessageSearchStoreOps` in
+ // `lib/reducers/db-ops-reducer.js`.
+ int textTypeInt = static_cast<int>(MessageType::TEXT);
+ int editTypeInt = static_cast<int>(MessageType::EDIT_MESSAGE);
+ int deleteTypeInt = static_cast<int>(MessageType::DELETE_MESSAGE);
+
+ // Populate message_search table for copied TEXT messages
+ sql << "INSERT OR IGNORE INTO message_search ("
+ << " original_message_id, message_id, processed_content) "
+ << "SELECT id, id, content "
+ << "FROM sourceDB.backup_messages "
+ << "WHERE type = " << textTypeInt << ";" << std::endl;
+
+ // Update message_search table for EDIT_MESSAGE entries
+ sql << "UPDATE message_search "
+ << "SET "
+ << " message_id = b.id,"
+ << " processed_content = IIF("
+ << " JSON_VALID(b.content),"
+ << " JSON_EXTRACT(b.content, '$.text'),"
+ << " NULL"
+ << " )"
+ << "FROM sourceDB.backup_messages AS b "
+ << "WHERE message_search.original_message_id = IIF("
+ << " JSON_VALID(b.content),"
+ << " JSON_EXTRACT(b.content, '$.targetMessageID'),"
+ << " NULL"
+ << ") "
+ << " AND b.type = " << editTypeInt << ";" << std::endl;
+
+ // Delete message_search entries for DELETE_MESSAGE
+ sql << "DELETE FROM message_search "
+ << "WHERE original_message_id IN ("
+ << " SELECT IIF("
+ << " JSON_VALID(content),"
+ << " JSON_EXTRACT(content, '$.targetMessageID'),"
+ << " NULL"
+ << " ) "
+ << " FROM sourceDB.backup_messages "
+ << " WHERE type = " << deleteTypeInt << ");" << std::endl;
+
sql << "DETACH DATABASE sourceDB;";
executeQuery(this->getConnection(), sql.str());
}
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$@<O00001
literal 0
Hc$@<O00001
diff --git a/web/shared-worker/queries/multiple-databases.test.js b/web/shared-worker/queries/multiple-databases.test.js
--- a/web/shared-worker/queries/multiple-databases.test.js
+++ b/web/shared-worker/queries/multiple-databases.test.js
@@ -1,6 +1,10 @@
// @flow
+import { getProtocolByThreadID } from 'lib/shared/threads/protocols/thread-protocols.js';
+import { messageTypes } from 'lib/types/message-types-enum.js';
+
import { getDatabaseModule } from '../db-module.js';
+import type { WebMessage } from '../types/sqlite-query-executor.js';
import { clearSensitiveData } from '../utils/db-utils.js';
const MAIN_FILE_PATH = 'main.sqlite';
@@ -135,4 +139,243 @@
expect(notMigratedQueryExecutor.getDatabaseVersion()).toBe(0);
clearSensitiveData(dbModule, notMigratedFilePath, notMigratedQueryExecutor);
});
+
+ it('populates message_search table for TEXT messages during copy', () => {
+ const threadID = '40db5619-feb2-4e5f-bd0c-1f9a709d366e';
+ const messageID = 'test-message-id';
+ const messageContent = 'Hello world test message';
+
+ const message: WebMessage = {
+ id: messageID,
+ localID: null,
+ thread: threadID,
+ user: '111',
+ type: messageTypes.TEXT,
+ futureType: null,
+ content: messageContent,
+ time: BigInt(123),
+ };
+
+ // Add message to the backup database
+ backupQueryExecutor.replaceMessage(
+ message,
+ !!getProtocolByThreadID(threadID)?.dataIsBackedUp,
+ );
+
+ // Verify message is not searchable in main database before copy
+ let searchResults = mainQueryExecutor.searchMessages(
+ 'Hello',
+ threadID,
+ null,
+ null,
+ );
+ expect(searchResults.length).toBe(0);
+
+ // Copy content from backup to main
+ mainQueryExecutor.copyContentFromDatabase(BACKUP_FILE_PATH, null);
+
+ // Verify message is now searchable in main database
+ searchResults = mainQueryExecutor.searchMessages(
+ 'Hello',
+ threadID,
+ null,
+ null,
+ );
+ expect(searchResults.length).toBe(1);
+ expect(searchResults[0].message.id).toBe(messageID);
+ expect(searchResults[0].message.content).toBe(messageContent);
+ });
+
+ it('populates message_search table for EDIT_MESSAGE messages during copy', () => {
+ const threadID = '40db5619-feb2-4e5f-bd0c-1f9a709d366e';
+ const originalMessageID = 'original-message-id';
+ const editMessageID = 'edit-message-id';
+ const editContent = JSON.stringify({
+ targetMessageID: originalMessageID,
+ text: 'edited text',
+ });
+
+ const originalMessage: WebMessage = {
+ id: originalMessageID,
+ localID: null,
+ thread: threadID,
+ user: '111',
+ type: messageTypes.TEXT,
+ futureType: null,
+ content: 'Original content',
+ time: BigInt(100),
+ };
+
+ const editMessage: WebMessage = {
+ id: editMessageID,
+ localID: null,
+ thread: threadID,
+ user: '111',
+ type: messageTypes.EDIT_MESSAGE,
+ futureType: null,
+ content: editContent,
+ time: BigInt(200),
+ };
+
+ // Add messages to backup database
+ backupQueryExecutor.replaceMessage(
+ originalMessage,
+ !!getProtocolByThreadID(threadID)?.dataIsBackedUp,
+ );
+ backupQueryExecutor.replaceMessage(
+ editMessage,
+ !!getProtocolByThreadID(threadID)?.dataIsBackedUp,
+ );
+
+ // Copy content from backup to main
+ mainQueryExecutor.copyContentFromDatabase(BACKUP_FILE_PATH, null);
+
+ // Verify edit message is searchable
+ // Should find the edit and original message content
+ const searchResults = mainQueryExecutor.searchMessages(
+ 'edited',
+ threadID,
+ null,
+ null,
+ );
+ expect(searchResults.length).toBe(2);
+ expect(searchResults[0].message.id).toBe(originalMessageID);
+ expect(searchResults[1].message.id).toBe(editMessageID);
+ });
+
+ it('removes DELETE_MESSAGE entries from existing message_search during copy', () => {
+ const threadID = '40db5619-feb2-4e5f-bd0c-1f9a709d366e';
+ const messageID = 'message-to-delete';
+
+ // First, add a TEXT message that gets indexed
+ const textMessage: WebMessage = {
+ id: messageID,
+ localID: null,
+ thread: threadID,
+ user: '111',
+ type: messageTypes.TEXT,
+ futureType: null,
+ content: 'This message will be deleted',
+ time: BigInt(100),
+ };
+
+ mainQueryExecutor.replaceMessage(
+ textMessage,
+ !!getProtocolByThreadID(threadID)?.dataIsBackedUp,
+ );
+ mainQueryExecutor.updateMessageSearchIndex(
+ messageID,
+ messageID,
+ 'This message will be deleted',
+ );
+
+ // Verify message is searchable
+ let searchResults = mainQueryExecutor.searchMessages(
+ 'deleted',
+ threadID,
+ null,
+ null,
+ );
+ expect(searchResults.length).toBe(1);
+
+ const deleteMessage: WebMessage = {
+ id: 'delete-message-id',
+ localID: null,
+ thread: threadID,
+ user: '111',
+ type: messageTypes.DELETE_MESSAGE,
+ futureType: null,
+ content: JSON.stringify({ targetMessageID: messageID }),
+ time: BigInt(300),
+ };
+
+ backupQueryExecutor.replaceMessage(
+ deleteMessage,
+ !!getProtocolByThreadID(threadID)?.dataIsBackedUp,
+ );
+
+ // Copy content from backup to main
+ // This should remove the search index entry
+ mainQueryExecutor.copyContentFromDatabase(BACKUP_FILE_PATH, null);
+
+ // Verify message is no longer searchable
+ searchResults = mainQueryExecutor.searchMessages(
+ 'deleted',
+ threadID,
+ null,
+ null,
+ );
+ expect(searchResults.length).toBe(0);
+ });
+
+ it('handles EDIT_MESSAGE and DELETE_MESSAGE with invalid JSON gracefully', () => {
+ const threadID = '40db5619-feb2-4e5f-bd0c-1f9a709d366e';
+ const originalMessageID = 'original-message-id';
+
+ // Add original TEXT message that gets indexed
+ const originalMessage: WebMessage = {
+ id: originalMessageID,
+ localID: null,
+ thread: threadID,
+ user: '111',
+ type: messageTypes.TEXT,
+ futureType: null,
+ content: 'Original message to edit',
+ time: BigInt(100),
+ };
+
+ backupQueryExecutor.replaceMessage(
+ originalMessage,
+ !!getProtocolByThreadID(threadID)?.dataIsBackedUp,
+ );
+
+ // Add EDIT_MESSAGE with invalid JSON
+ const invalidEditMessage: WebMessage = {
+ id: 'invalid-edit-id',
+ localID: null,
+ thread: threadID,
+ user: '111',
+ type: messageTypes.EDIT_MESSAGE,
+ futureType: null,
+ content: 'invalid json { broken',
+ time: BigInt(200),
+ };
+
+ // Add DELETE_MESSAGE with invalid JSON
+ const invalidDeleteMessage: WebMessage = {
+ id: 'invalid-delete-id',
+ localID: null,
+ thread: threadID,
+ user: '111',
+ type: messageTypes.DELETE_MESSAGE,
+ futureType: null,
+ content: 'also invalid json } broken',
+ time: BigInt(300),
+ };
+
+ backupQueryExecutor.replaceMessage(
+ invalidEditMessage,
+ !!getProtocolByThreadID(threadID)?.dataIsBackedUp,
+ );
+ backupQueryExecutor.replaceMessage(
+ invalidDeleteMessage,
+ !!getProtocolByThreadID(threadID)?.dataIsBackedUp,
+ );
+
+ // Copy content - should not fail despite invalid
+ // JSON in EDIT/DELETE messages
+ expect(() => {
+ mainQueryExecutor.copyContentFromDatabase(BACKUP_FILE_PATH, null);
+ }).not.toThrow();
+
+ // Original message should still be searchable (invalid EDIT/DELETE ignored)
+ const searchResults = mainQueryExecutor.searchMessages(
+ 'Original',
+ threadID,
+ null,
+ null,
+ );
+ expect(searchResults.length).toBe(1);
+ expect(searchResults[0].message.id).toBe(originalMessageID);
+ });
});
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Dec 7, 1:48 AM (10 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5842027
Default Alt Text
D14974.1765072111.diff (10 KB)
Attached To
Mode
D14974: [SQLite] populate message search index when restoring backup
Attached
Detach File
Event Timeline
Log In to Comment