diff --git a/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/ConversationDetailsWithEvents.sq b/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/ConversationDetailsWithEvents.sq index 5631338deddb..ab8f65323e37 100644 --- a/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/ConversationDetailsWithEvents.sq +++ b/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/ConversationDetailsWithEvents.sq @@ -100,6 +100,11 @@ ORDER BY name COLLATE NOCASE ASC; selectConversationDetailsWithEvents: +-- @CustomKey conversation_list_membership +-- @CustomKey conversation_list_order +-- @CustomKey conversation_list_last_message +-- @CustomKey conversation_list_unread +-- @CustomKey conversation_list_draft SELECT * FROM ConversationDetailsWithEvents WHERE archived = :fromArchive @@ -138,6 +143,11 @@ WHERE OFFSET :offset; selectConversationDetailsWithEventsFromSearch: +-- @CustomKey conversation_list_membership +-- @CustomKey conversation_list_order +-- @CustomKey conversation_list_last_message +-- @CustomKey conversation_list_unread +-- @CustomKey conversation_list_draft SELECT * FROM ConversationDetailsWithEvents WHERE archived = :fromArchive @@ -177,6 +187,7 @@ LIMIT :limit OFFSET :offset; countConversations: +-- @CustomKey conversation_list_membership SELECT COUNT(*) FROM Conversation WHERE @@ -238,6 +249,7 @@ WHERE AND CASE WHEN :onlyInteractionsEnabled THEN interactionEnabled = 1 ELSE 1 END; countConversationDetailsWithEventsFromSearch: +-- @CustomKey conversation_list_membership SELECT COUNT(*) FROM ConversationDetails WHERE ConversationDetails.type IS NOT 'SELF' diff --git a/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Conversations.sq b/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Conversations.sq index e64879d3b6db..2244cd5e9026 100644 --- a/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Conversations.sq +++ b/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Conversations.sq @@ -91,17 +91,25 @@ conversationIDByGroupId: SELECT qualified_id, verification_status FROM Conversation WHERE mls_group_id = :groupId; deleteAllConversations: +-- @NotifyCustomKey Conversation +-- @NotifyCustomKey conversation_list_membership DELETE FROM Conversation; deleteConversation: +-- @NotifyCustomKey Conversation +-- @NotifyCustomKey conversation_list_membership DELETE FROM Conversation WHERE qualified_id = ?; setDeletedLocally: +-- @NotifyCustomKey Conversation +-- @NotifyCustomKey conversation_list_membership UPDATE Conversation SET deleted_locally = :deletedLocally WHERE qualified_id = :qualifiedId; insertConversation: +-- @NotifyCustomKey Conversation +-- @NotifyCustomKey conversation_list_membership INSERT INTO Conversation(qualified_id, name, type, team_id, mls_group_id, mls_group_state, mls_epoch, protocol, muted_status, muted_time, creator_id, last_modified_date, last_notified_date, access_list, access_role_list, last_read_date, mls_last_keying_material_update_date, mls_cipher_suite, receipt_mode, message_timer, user_message_timer, incomplete_metadata, archived, archived_date_time, is_channel, channel_access, channel_add_permission, wire_cell, history_sharing_retention_seconds) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(qualified_id) DO UPDATE SET @@ -139,11 +147,15 @@ wire_cell = excluded.wire_cell, history_sharing_retention_seconds = excluded.history_sharing_retention_seconds; updateConversation: +-- @NotifyCustomKey Conversation +-- @NotifyCustomKey conversation_list_membership UPDATE Conversation SET name = ?, type = ?, team_id = ? WHERE qualified_id = ?; updateConversationGroupState: +-- @NotifyCustomKey Conversation +-- @NotifyCustomKey conversation_list_membership UPDATE Conversation SET mls_group_state = CASE WHEN mls_group_state = 'ESTABLISHED' THEN :mls_group_state @@ -153,6 +165,8 @@ END WHERE mls_group_id = ?; updateConversationGroupStateByConversationId: +-- @NotifyCustomKey Conversation +-- @NotifyCustomKey conversation_list_membership UPDATE Conversation SET mls_group_state = CASE WHEN mls_group_state = 'ESTABLISHED' THEN :mls_group_state @@ -162,6 +176,8 @@ END WHERE qualified_id = :conversation_id; updateMlsGroupStateAndCipherSuite: +-- @NotifyCustomKey Conversation +-- @NotifyCustomKey conversation_list_membership UPDATE Conversation SET mls_group_state = CASE WHEN mls_group_state = 'ESTABLISHED' THEN :mls_group_state @@ -172,8 +188,10 @@ mls_cipher_suite = :mls_cipher_suite WHERE mls_group_id = :mls_group_id; updateMLSGroupIdAndState: +-- @NotifyCustomKey Conversation +-- @NotifyCustomKey conversation_list_membership UPDATE Conversation -SET mls_group_id = :new_group_id, +SET mls_group_id = :new_group_id, mls_group_state = CASE WHEN mls_group_state = 'ESTABLISHED' THEN :mls_group_state WHEN :mls_group_state IN ('ESTABLISHED', 'PENDING_AFTER_RESET') THEN :mls_group_state @@ -208,11 +226,15 @@ SET last_notified_date = ( ); updateConversationModifiedDate: +-- @NotifyCustomKey Conversation +-- @NotifyCustomKey conversation_list_order UPDATE Conversation SET last_modified_date = ? WHERE qualified_id = ?; updateConversationModifiedDateToMaxOfSources: +-- @NotifyCustomKey Conversation +-- @NotifyCustomKey conversation_list_order UPDATE Conversation SET last_modified_date = ( SELECT MAX(last_modified_date) @@ -289,11 +311,15 @@ selectConversationIds: SELECT qualified_id FROM Conversation WHERE protocol = :protocol AND type = :type AND (:teamId IS NULL OR team_id = :teamId); updateConversationMutingStatus: +-- @NotifyCustomKey Conversation +-- @NotifyCustomKey conversation_list_unread UPDATE Conversation SET muted_status = ?, muted_time = ? WHERE qualified_id = ?; updateConversationArchivingStatus: +-- @NotifyCustomKey Conversation +-- @NotifyCustomKey conversation_list_membership UPDATE Conversation SET archived = ?, archived_date_time = ? WHERE qualified_id = ?; @@ -349,16 +375,23 @@ SELECT sender_user_id FROM Message WHERE id IN ( ) ORDER BY creation_date DESC LIMIT 1; updateConversationName: +-- @NotifyCustomKey Conversation +-- @NotifyCustomKey conversation_list_membership +-- @NotifyCustomKey conversation_list_order UPDATE Conversation SET name = ?, last_modified_date = ? WHERE qualified_id = ?; updateConversationType: +-- @NotifyCustomKey Conversation +-- @NotifyCustomKey conversation_list_membership UPDATE Conversation SET type = ? WHERE qualified_id = ?; updateConversationGroupIdAndProtocolInfo { +-- @NotifyCustomKey Conversation +-- @NotifyCustomKey conversation_list_membership UPDATE Conversation SET mls_group_id = :groupId, protocol = :protocol, mls_cipher_suite = :mls_cipher_suite WHERE qualified_id = :qualified_id AND diff --git a/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/MessageDrafts.sq b/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/MessageDrafts.sq index 1ec7f1e3097d..eb51e44be6dd 100644 --- a/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/MessageDrafts.sq +++ b/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/MessageDrafts.sq @@ -16,9 +16,13 @@ CREATE TABLE MessageDraft ( ); deleteDraft: +-- @NotifyCustomKey MessageDraft +-- @NotifyCustomKey conversation_list_draft DELETE FROM MessageDraft WHERE conversation_id = ?; upsertDraft: +-- @NotifyCustomKey MessageDraft +-- @NotifyCustomKey conversation_list_draft INSERT INTO MessageDraft(conversation_id, text, edit_message_id, quoted_message_id, mention_list) VALUES( ?, ?, ?, ?, ?) ON CONFLICT(conversation_id) DO UPDATE SET diff --git a/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Messages.sq b/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Messages.sq index 7db2b791dc0e..d69c1afe0bb5 100644 --- a/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Messages.sq +++ b/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Messages.sq @@ -235,21 +235,36 @@ AND content_type IN ('TEXT', 'ASSET', 'KNOCK', 'MISSED_CALL') GROUP BY conversation_id; deleteAllMessages: +-- @NotifyCustomKey Message +-- @NotifyCustomKey conversation_list_last_message +-- @NotifyCustomKey message_search_all DELETE FROM Message; deleteMessage: -DELETE FROM Message WHERE id = ? AND conversation_id = ?; +-- @NotifyCustomKey Message +-- @NotifyCustomKey conversation_list_last_message +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id +DELETE FROM Message WHERE id = :message_id AND conversation_id = :conversation_id; deleteMessageLinkPreviews: DELETE FROM MessageLinkPreview WHERE message_id = ? AND conversation_id = ?; deleteMessageMentions: -DELETE FROM MessageMention WHERE message_id = ? AND conversation_id = ?; +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id +DELETE FROM MessageMention WHERE message_id = :message_id AND conversation_id = :conversation_id; deleteMessageById: +-- @NotifyCustomKey Message +-- @NotifyCustomKey conversation_list_last_message DELETE FROM Message WHERE id = ?; markMessageAsDeleted { + -- @NotifyCustomKey Message + -- @NotifyCustomKey conversation_list_last_message + -- @NotifyCustomKey message_list_:conversation_id + -- @NotifyCustomKey message_search_:conversation_id UPDATE Message SET visibility = 'DELETED' WHERE id = :message_id AND conversation_id = :conversation_id; @@ -264,6 +279,10 @@ markMessageAsDeleted { } markMessageAsEdited: +-- @NotifyCustomKey Message +-- @NotifyCustomKey conversation_list_last_message +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id UPDATE Message SET last_edit_date = ? WHERE id = ? AND conversation_id = ?; @@ -275,12 +294,20 @@ selectChanges: SELECT changes(); insertOrIgnoreMessage: +-- @NotifyCustomKey Message +-- @NotifyCustomKey conversation_list_last_message +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO Message(id, content_type, conversation_id, creation_date, sender_user_id, sender_client_id, status, last_edit_date, visibility, expects_read_confirmation, expire_after_millis, self_deletion_end_date) -VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); +VALUES(:id, :content_type, :conversation_id, :creation_date, :sender_user_id, :sender_client_id, :status, :last_edit_date, :visibility, :expects_read_confirmation, :expire_after_millis, :self_deletion_end_date); insertMessage: +-- @NotifyCustomKey Message +-- @NotifyCustomKey conversation_list_last_message +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT INTO Message(id, content_type, conversation_id, creation_date, sender_user_id, sender_client_id, status, last_edit_date, visibility, expects_read_confirmation, expire_after_millis, self_deletion_end_date) -VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); +VALUES(:id, :content_type, :conversation_id, :creation_date, :sender_user_id, :sender_client_id, :status, :last_edit_date, :visibility, :expects_read_confirmation, :expire_after_millis, :self_deletion_end_date); insertOrIgnoreBulkSystemMessage: INSERT OR IGNORE INTO Message(id, content_type, conversation_id, creation_date, sender_user_id, sender_client_id, status, visibility, expects_read_confirmation) @@ -291,10 +318,14 @@ INSERT OR IGNORE INTO MessageLinkPreview(message_id, conversation_id, url, url_o VALUES (?, ?, ?, ?, ?, ?, ?); insertMessageMention: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageMention(message_id, conversation_id, start, length, user_id) -VALUES (?, ?, ?, ?, ?); +VALUES (:message_id, :conversation_id, :start, :length, :user_id); insertMessageTextContent: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageTextContent(message_id, conversation_id, text_body, quoted_message_id, is_quote_verified, is_quoting_self) VALUES(:message_id, :conversation_id, :text_body, :quoted_message_id, :is_quote_verified, CASE WHEN @@ -311,71 +342,105 @@ CASE WHEN 0 ))END); insertMessageRestrictedAssetContent: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageRestrictedAssetContent(message_id, conversation_id, asset_mime_type,asset_size,asset_name) -VALUES(?, ?, ?,?,?); +VALUES(:message_id, :conversation_id, :asset_mime_type, :asset_size, :asset_name); insertMessageAssetContent: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageAssetContent(message_id, conversation_id, asset_size, asset_name, asset_mime_type, asset_otr_key, asset_sha256, asset_id, asset_token, asset_domain, asset_encryption_algorithm, asset_width, asset_height, asset_duration_ms, asset_normalized_loudness) -VALUES(?, ?, ?, ?, ?, ? ,?, ?, ?, ?, ?, ?, ?, ?, ?); +VALUES(:message_id, :conversation_id, :asset_size, :asset_name, :asset_mime_type, :asset_otr_key, :asset_sha256, :asset_id, :asset_token, :asset_domain, :asset_encryption_algorithm, :asset_width, :asset_height, :asset_duration_ms, :asset_normalized_loudness); insertMessageUnknownContent: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageUnknownContent(message_id, conversation_id, unknown_type_name, unknown_encoded_data) -VALUES(?, ?, ?, ?); +VALUES(:message_id, :conversation_id, :unknown_type_name, :unknown_encoded_data); insertMissedCallMessage: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageMissedCallContent(message_id, conversation_id, caller_id) -VALUES(?, ?, ?); +VALUES(:message_id, :conversation_id, :caller_id); insertLocationMessageContent: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageConversationLocationContent(message_id, conversation_id, latitude, longitude, name, zoom) -VALUES(?, ?, ?, ?, ?, ?); +VALUES(:message_id, :conversation_id, :latitude, :longitude, :name, :zoom); insertSystemMessageContent: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageSystemContent(message_id, conversation_id, content_type, text_1, integer_1, boolean_1, list_1, enum_1, blob_1) -VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?); +VALUES(:message_id, :conversation_id, :content_type, :text_1, :integer_1, :boolean_1, :list_1, :enum_1, :blob_1); insertSystemMemberChange: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageSystemContent(message_id, conversation_id, content_type, list_1, enum_1) -VALUES(?, ?, 'MEMBER_CHANGE', :member_change_list, :member_change_type); +VALUES(:message_id, :conversation_id, 'MEMBER_CHANGE', :member_change_list, :member_change_type); insertSystemFailedDecryption: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageSystemContent(message_id, conversation_id, content_type, blob_1, boolean_1, integer_1) -VALUES(?, ?, 'FAILED_DECRYPT', :unknown_encoded_data, 0, :error_code); +VALUES(:message_id, :conversation_id, 'FAILED_DECRYPT', :unknown_encoded_data, 0, :error_code); insertSystemConversationRenamed: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageSystemContent(message_id, conversation_id, content_type, text_1) VALUES(:message_id, :conversation_id, 'CONVERSATION_RENAMED', :conversation_name); insertSystemNewConversationReceiptMode: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageSystemContent(message_id, conversation_id, content_type, boolean_1) -VALUES(?, ?, 'NEW_CONVERSATION_RECEIPT_MODE', :receipt_mode); +VALUES(:message_id, :conversation_id, 'NEW_CONVERSATION_RECEIPT_MODE', :receipt_mode); insertSystemConversationReceiptModeChanged: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageSystemContent(message_id, conversation_id, content_type, boolean_1) -VALUES(?, ?, 'CONVERSATION_RECEIPT_MODE_CHANGED', :receipt_mode); +VALUES(:message_id, :conversation_id, 'CONVERSATION_RECEIPT_MODE_CHANGED', :receipt_mode); insertSystemConversationAppsEnabledChanged: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageSystemContent(message_id, conversation_id, content_type, boolean_1) -VALUES(?, ?, 'CONVERSATION_APPS_ENABLED_CHANGED', :is_apps_enabled); +VALUES(:message_id, :conversation_id, 'CONVERSATION_APPS_ENABLED_CHANGED', :is_apps_enabled); insertSystemConversationTimerChanged: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageSystemContent(message_id, conversation_id, content_type, integer_1) VALUES(:message_id, :conversation_id, 'CONVERSATION_TIMER_CHANGED', :message_timer); insertSystemFederationTerminated: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageSystemContent(message_id, conversation_id, content_type, list_1, enum_1) VALUES(:message_id, :conversation_id, 'FEDERATION_TERMINATED', :domain_list, :federation_type); insertSystemConversationProtocolChanged: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageSystemContent(message_id, conversation_id, content_type, enum_1) VALUES(:message_id, :conversation_id, 'CONVERSATION_PROTOCOL_CHANGED', :protocol); insertSystemLegalHold: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageSystemContent(message_id, conversation_id, content_type, list_1, enum_1) -VALUES(?, ?, 'LEGAL_HOLD', :legal_hold_member_list, :legal_hold_type); +VALUES(:message_id, :conversation_id, 'LEGAL_HOLD', :legal_hold_member_list, :legal_hold_type); -- Update query for system content updateSystemMessageLegalHoldMembers: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id UPDATE MessageSystemContent SET list_1 = :user_id_list WHERE message_id = :message_id AND conversation_id = :conversation_id AND content_type = 'LEGAL_HOLD'; @@ -392,11 +457,15 @@ WHERE message_id IN ( ); updateMessageStatus: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id UPDATE Message SET status = ? WHERE id = ? AND conversation_id = ?; updateMessagesStatusIfNotRead: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id UPDATE Message SET status = ? WHERE id IN ? @@ -404,6 +473,8 @@ AND conversation_id = ? AND status != 'READ'; updateQuotedMessageId: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id UPDATE MessageTextContent SET quoted_message_id = ? WHERE quoted_message_id = ? AND conversation_id = ?; @@ -412,6 +483,10 @@ selectMessageVisibility: SELECT visibility FROM Message WHERE id = ? AND conversation_id = ?; updateAssetContent { + -- @NotifyCustomKey Message + -- @NotifyCustomKey conversation_list_last_message + -- @NotifyCustomKey message_list_:conversationId + -- @NotifyCustomKey message_search_:conversationId UPDATE OR ROLLBACK Message SET visibility = :visibility WHERE id = :messageId AND conversation_id = :conversationId AND visibility IS NOT 'DELETED'; @@ -422,11 +497,15 @@ updateAssetContent { } updateMessageTextContent: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id UPDATE MessageTextContent SET text_body = ? WHERE message_id = ? AND conversation_id = ?; updateMessageId: +-- @NotifyCustomKey message_list_:conversationId +-- @NotifyCustomKey message_search_:conversationId UPDATE Message SET id = :newId WHERE id = :oldId AND conversation_id = :conversationId; @@ -438,7 +517,8 @@ selectById: SELECT * FROM MessageDetailsView WHERE id = ? AND conversationId = ?; countByConversationIdAndVisibility: -SELECT count(*) FROM Message WHERE conversation_id = ? AND visibility IN ?; +-- @CustomKey message_list_:conversationId +SELECT count(*) FROM Message WHERE conversation_id = :conversationId AND visibility IN :visibility; selectOldestVisibleMessageTimestampByConversationId: SELECT MIN(creation_date) FROM Message WHERE conversation_id = ? AND visibility = "VISIBLE"; @@ -493,6 +573,8 @@ ORDER BY Message.creation_date DESC; promoteMessageToSentUpdatingServerTime { +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id UPDATE Message SET creation_date = CASE WHEN :server_creation_date IS NULL THEN creation_date ELSE :server_creation_date END, @@ -519,20 +601,30 @@ AND visibility = "VISIBLE" AND selfDeletionEndDate <= STRFTIME('%s', 'now') * 1000; -- Checks if message end date is lower than current time in millis markSelfDeletionEndDate: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id UPDATE Message SET self_deletion_end_date = ? WHERE conversation_id = ? AND id = ?; insertMessageRecipientsFailure: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT OR IGNORE INTO MessageRecipientFailure(message_id, conversation_id, recipient_failure_list, recipient_failure_type) -VALUES(?, ?, ?, ?); +VALUES(:message_id, :conversation_id, :recipient_failure_list, :recipient_failure_type); moveMessages: +-- @NotifyCustomKey message_list_:from +-- @NotifyCustomKey message_list_:to +-- @NotifyCustomKey message_search_:from +-- @NotifyCustomKey message_search_:to UPDATE OR REPLACE Message SET conversation_id = :to WHERE conversation_id = :from; selectConversationMessagesFromSearch: +-- @CustomKey message_search_:conversationId +-- @CustomKey message_search_all SELECT MessageDetailsView.* FROM MessageTextContent AS TextContent JOIN MessageDetailsView @@ -558,6 +650,8 @@ LIMIT :limit OFFSET :offset; countBySearchedMessageAndConversationId: +-- @CustomKey message_search_:conversationId +-- @CustomKey message_search_all SELECT COUNT(*) FROM MessageTextContent AS TextContent JOIN Message @@ -584,6 +678,7 @@ ORDER BY Message.creation_date ASC LIMIT 1; updateAudioMessageNormalizedLoudness: +-- @NotifyCustomKey message_list_:conversation_id UPDATE MessageAssetContent SET asset_normalized_loudness = ? WHERE message_id = ? AND conversation_id = ?; diff --git a/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Reactions.sq b/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Reactions.sq index 60a47e422032..42ac25abe750 100644 --- a/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Reactions.sq +++ b/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Reactions.sq @@ -16,17 +16,25 @@ doesMessageExist: SELECT 1 FROM Message WHERE id = :message_id AND conversation_id = :conversation_id; deleteAllReactionsOnMessageFromUser: -DELETE FROM Reaction WHERE message_id = ? AND conversation_id = ? AND sender_id = ?; +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id +DELETE FROM Reaction WHERE message_id = :message_id AND conversation_id = :conversation_id AND sender_id = :sender_id; deleteReaction: -DELETE FROM Reaction WHERE message_id = ? AND conversation_id = ? AND sender_id = ? AND emoji = ?; +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id +DELETE FROM Reaction WHERE message_id = :message_id AND conversation_id = :conversation_id AND sender_id = :sender_id AND emoji = :emoji; insertReaction: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT INTO Reaction(message_id, conversation_id, sender_id, emoji, date) -VALUES(?, ?, ?, ?, ?); +VALUES(:message_id, :conversation_id, :sender_id, :emoji, :date); deleteAllReactionsForMessage: -DELETE FROM Reaction WHERE message_id = ? AND conversation_id = ?; +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id +DELETE FROM Reaction WHERE message_id = :message_id AND conversation_id = :conversation_id; selectByMessageIdAndConversationIdAndSenderId: SELECT * FROM Reaction WHERE message_id = ? AND conversation_id = ? AND sender_id = ?; diff --git a/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Receipts.sq b/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Receipts.sq index 708d5ca7b029..c7662f95b61e 100644 --- a/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Receipts.sq +++ b/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/Receipts.sq @@ -16,8 +16,16 @@ CREATE INDEX receipt_msg_type ON Receipt(message_id, type); -- TODO: Cast to proper types when/if SQLDelight supports it: insertReceipt: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id WITH insertion(message_id, conversation_id, user_id, type, date) AS( - VALUES (CAST(? AS TEXT), CAST(? AS TEXT), CAST(? AS TEXT), CAST(? AS TEXT), CAST(? AS TEXT)) + VALUES ( + CAST(:message_id AS TEXT), + CAST(:conversation_id AS TEXT), + CAST(:user_id AS TEXT), + CAST(:type AS TEXT), + CAST(:date AS TEXT) + ) ) INSERT OR IGNORE INTO Receipt(message_id, conversation_id, user_id, type, date) SELECT diff --git a/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/UnreadEvents.sq b/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/UnreadEvents.sq index ddd3eb926cef..9e1a47262d05 100644 --- a/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/UnreadEvents.sq +++ b/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/UnreadEvents.sq @@ -15,16 +15,24 @@ CREATE INDEX unread_event_conv_tyoe ON UnreadEvent(conversation_id, type); CREATE INDEX unread_event_conv_date ON UnreadEvent(conversation_id, creation_date); deleteUnreadEvent: +-- @NotifyCustomKey UnreadEvent +-- @NotifyCustomKey conversation_list_unread DELETE FROM UnreadEvent WHERE id = ? AND conversation_id = ?; deleteUnreadEvents: +-- @NotifyCustomKey UnreadEvent +-- @NotifyCustomKey conversation_list_unread DELETE FROM UnreadEvent WHERE creation_date <= ? AND conversation_id = ?; insertEvent: +-- @NotifyCustomKey UnreadEvent +-- @NotifyCustomKey conversation_list_unread INSERT OR IGNORE INTO UnreadEvent(id, type, conversation_id, creation_date) VALUES(?, ?, ?, ?); updateEvent: +-- @NotifyCustomKey UnreadEvent +-- @NotifyCustomKey conversation_list_unread UPDATE OR IGNORE UnreadEvent SET type = :type WHERE id = :id AND conversation_id = :conversation_id; diff --git a/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/content/ButtonContent.sq b/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/content/ButtonContent.sq index 00336f029258..ebc2e7a3cf9d 100644 --- a/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/content/ButtonContent.sq +++ b/data/persistence/src/commonMain/db_user/com/wire/kalium/persistence/content/ButtonContent.sq @@ -14,10 +14,14 @@ CREATE TABLE ButtonContent ( ); insertButton: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id INSERT INTO ButtonContent (message_id, conversation_id, id, text) VALUES (:message_id, :conversation_id, :id, :text); markSelected { + -- @NotifyCustomKey message_list_:conversation_id + -- @NotifyCustomKey message_search_:conversation_id UPDATE ButtonContent SET is_selected = 0 WHERE conversation_id = :conversation_id AND @@ -31,7 +35,11 @@ markSelected { } removeAllSelection: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id UPDATE ButtonContent SET is_selected = 0 WHERE conversation_id = :conversation_id AND message_id = :message_id; deleteAllButtons: +-- @NotifyCustomKey message_list_:conversation_id +-- @NotifyCustomKey message_search_:conversation_id DELETE FROM ButtonContent WHERE conversation_id = :conversation_id AND message_id = :message_id; diff --git a/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/conversation/ConversationExtensionsTest.kt b/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/conversation/ConversationExtensionsTest.kt index 3acbd2738eab..e4800ca5922c 100644 --- a/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/conversation/ConversationExtensionsTest.kt +++ b/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/conversation/ConversationExtensionsTest.kt @@ -37,8 +37,12 @@ import com.wire.kalium.persistence.dao.message.KaliumPager import com.wire.kalium.persistence.dao.message.MessageDAO import com.wire.kalium.persistence.dao.message.draft.MessageDraftDAO import com.wire.kalium.persistence.db.ReadDispatcher +import com.wire.kalium.persistence.db.UserDatabaseBuilder import com.wire.kalium.persistence.utils.stubs.newConversationEntity +import com.wire.kalium.persistence.utils.stubs.newDraftMessageEntity +import com.wire.kalium.persistence.utils.stubs.newRegularMessageEntity import com.wire.kalium.persistence.utils.stubs.newUserEntity +import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import kotlinx.datetime.Instant import kotlin.test.AfterTest @@ -51,6 +55,7 @@ import kotlin.test.assertTrue import kotlin.time.Duration.Companion.seconds class ConversationExtensionsTest : BaseDatabaseTest() { + private lateinit var databaseBuilder: UserDatabaseBuilder private lateinit var conversationExtensions: ConversationExtensions private lateinit var messageDAO: MessageDAO private lateinit var messageDraftDAO: MessageDraftDAO @@ -63,7 +68,8 @@ class ConversationExtensionsTest : BaseDatabaseTest() { @BeforeTest fun setUp() { deleteDatabase(selfUserId) - val db = createDatabase(selfUserId, encryptedDBSecret, true) + databaseBuilder = createDatabase(selfUserId, encryptedDBSecret, true, dbInvalidationControlEnabled = true) + val db = databaseBuilder val queries = db.database.conversationDetailsWithEventsQueries messageDAO = db.messageDAO messageDraftDAO = db.messageDraftDAO @@ -182,6 +188,110 @@ class ConversationExtensionsTest : BaseDatabaseTest() { } } } + @Test + fun givenConversationListPagingSource_whenConversationIsInserted_thenItInvalidates() = runTest(dispatcher) { + populateData(count = 1, isChannel = false) + val pagingSource = getPager().pagingSource + + pagingSource.refresh() + val invalidated = pagingSource.observeInvalidation() + + conversationDAO.insertConversation( + newConversationEntity(ConversationIDEntity("new_conversation", "domain")).copy( + name = "new conversation", + type = ConversationEntity.Type.GROUP, + lastModifiedDate = Instant.parse("2024-01-01T00:00:00Z"), + lastReadDate = Instant.parse("2023-12-31T23:59:59Z"), + isChannel = false, + ) + ) + + advanceUntilIdle() + + assertTrue(invalidated()) + } + + @Test + fun givenConversationListPagingSource_whenMessageIsInserted_thenItInvalidates() = runTest(dispatcher) { + populateData(count = 1, isChannel = false) + val conversationId = conversationId() + val pagingSource = getPager().pagingSource + + pagingSource.refresh() + val invalidated = pagingSource.observeInvalidation() + + messageDAO.insertOrIgnoreMessage( + newRegularMessageEntity( + id = "message_after_load", + conversationId = conversationId, + senderUserId = otherUserId, + date = Instant.parse("2024-01-01T00:00:00Z"), + ) + ) + + advanceUntilIdle() + + assertTrue(invalidated()) + } + + @Test + fun givenConversationListPagingSource_whenUnreadChanges_thenItInvalidates() = runTest(dispatcher) { + populateData(count = 1, isChannel = false) + val conversationId = conversationId() + messageDAO.insertOrIgnoreMessage( + newRegularMessageEntity( + id = "message_before_load", + conversationId = conversationId, + senderUserId = otherUserId, + date = Instant.parse("2024-01-01T00:00:00Z"), + ) + ) + val pagingSource = getPager().pagingSource + + pagingSource.refresh() + val invalidated = pagingSource.observeInvalidation() + + databaseBuilder.database.unreadEventsQueries.deleteUnreadEvents( + Instant.parse("2025-01-01T00:00:00Z"), + conversationId, + ) + + advanceUntilIdle() + + assertTrue(invalidated()) + } + + @Test + fun givenConversationListPagingSource_whenDraftChanges_thenItInvalidates() = runTest(dispatcher) { + populateData(count = 1, isChannel = false) + val conversationId = conversationId() + val pagingSource = getPager().pagingSource + + pagingSource.refresh() + val invalidated = pagingSource.observeInvalidation() + + messageDraftDAO.upsertMessageDraft(newDraftMessageEntity(conversationId = conversationId)) + + advanceUntilIdle() + + assertTrue(invalidated()) + } + + @Test + fun givenConversationListPagingSource_whenUnrelatedMetadataChanges_thenItDoesNotInvalidate() = runTest(dispatcher) { + populateData(count = 1, isChannel = false) + val pagingSource = getPager().pagingSource + + pagingSource.refresh() + val invalidated = pagingSource.observeInvalidation() + + databaseBuilder.database.metadataQueries.insertValue("some_key", "some_value") + + advanceUntilIdle() + + assertFalse(invalidated()) + } + private fun getPager(searchQuery: String = "", fromArchive: Boolean = false, filter: ConversationFilterEntity = ConversationFilterEntity.ALL): KaliumPager = conversationExtensions.getPagerForConversationDetailsWithEventsSearch( pagingConfig = PagingConfig(PAGE_SIZE), @@ -194,6 +304,16 @@ class ConversationExtensionsTest : BaseDatabaseTest() { private suspend fun PagingSource.nextPageForOffset(key: Int) = load(PagingSource.LoadParams.Append(key, PAGE_SIZE, true)) + private fun PagingSource.observeInvalidation(): () -> Boolean { + var invalidated = false + registerInvalidatedCallback { + invalidated = true + } + return { invalidated } + } + + private fun conversationId(index: Int = 0, prefix: String = CONVERSATION_ID_PREFIX) = ConversationIDEntity("$prefix$index", "domain") + private suspend fun populateData( archived: Boolean = false, count: Int = CONVERSATION_COUNT, @@ -222,5 +342,6 @@ class ConversationExtensionsTest : BaseDatabaseTest() { const val CONVERSATION_ID_PREFIX = "conversation_" const val ARCHIVED_CONVERSATION_ID_PREFIX = "archived_conversation_" const val PAGE_SIZE = 20 + val otherUserId = UserIDEntity("user", "domain") } } diff --git a/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/message/MessageExtensionsTest.kt b/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/message/MessageExtensionsTest.kt index 4b189398f9d3..f9026145fd3c 100644 --- a/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/message/MessageExtensionsTest.kt +++ b/data/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/message/MessageExtensionsTest.kt @@ -32,13 +32,18 @@ import com.wire.kalium.persistence.dao.message.MessageEntityContent import com.wire.kalium.persistence.dao.message.MessageExtensions import com.wire.kalium.persistence.dao.message.MessageExtensionsImpl import com.wire.kalium.persistence.dao.message.MessageMapper +import com.wire.kalium.persistence.dao.reaction.ReactionDAO +import com.wire.kalium.persistence.dao.receipt.ReceiptDAO +import com.wire.kalium.persistence.dao.receipt.ReceiptTypeEntity import com.wire.kalium.persistence.db.ReadDispatcher +import com.wire.kalium.persistence.db.UserDatabaseBuilder import com.wire.kalium.persistence.db.WriteDispatcher import com.wire.kalium.persistence.utils.stubs.newConversationEntity import com.wire.kalium.persistence.utils.stubs.newRegularMessageEntity import com.wire.kalium.persistence.utils.stubs.newUserEntity import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain import kotlinx.datetime.Instant @@ -53,23 +58,30 @@ import kotlin.test.assertTrue @OptIn(ExperimentalCoroutinesApi::class) class MessageExtensionsTest : BaseDatabaseTest() { + private lateinit var databaseBuilder: UserDatabaseBuilder private lateinit var messageExtensions: MessageExtensions private lateinit var messageDAO: MessageDAO private lateinit var conversationDAO: ConversationDAO private lateinit var userDAO: UserDAO + private lateinit var reactionDAO: ReactionDAO + private lateinit var receiptDAO: ReceiptDAO private val selfUserId = UserIDEntity("selfValue", "selfDomain") + private val otherUserId = UserIDEntity("user", "domain") @BeforeTest fun setUp() { Dispatchers.setMain(dispatcher) deleteDatabase(selfUserId) - val db = createDatabase(selfUserId, encryptedDBSecret, true) + databaseBuilder = createDatabase(selfUserId, encryptedDBSecret, true, dbInvalidationControlEnabled = true) + val db = databaseBuilder val messagesQueries = db.database.messagesQueries val messageAssetViewQueries = db.database.messageAssetViewQueries messageDAO = db.messageDAO conversationDAO = db.conversationDAO userDAO = db.userDAO + reactionDAO = db.reactionDAO + receiptDAO = db.receiptDAO messageExtensions = MessageExtensionsImpl( messagesQueries = messagesQueries, messageAssetViewQueries = messageAssetViewQueries, @@ -188,6 +200,235 @@ class MessageExtensionsTest : BaseDatabaseTest() { } } + @Test + fun givenMessageListPagingSource_whenMessageIsInsertedInSameConversation_thenItInvalidates() = runTest { + populateMessageData() + val pagingSource = getPager().pagingSource + + pagingSource.refresh() + val invalidated = pagingSource.observeInvalidation() + + messageDAO.insertOrIgnoreMessage( + newRegularMessageEntity( + id = "message_after_load", + conversationId = CONVERSATION_ID, + senderUserId = otherUserId, + date = Instant.parse("2024-01-01T00:00:00Z"), + ) + ) + + advanceUntilIdle() + + assertTrue(invalidated()) + } + + @Test + fun givenMessageListPagingSource_whenMessageIsInsertedInOtherConversation_thenItDoesNotInvalidate() = runTest { + populateMessageData() + val pagingSource = getPager().pagingSource + + pagingSource.refresh() + val invalidated = pagingSource.observeInvalidation() + + val otherConversationId = ConversationIDEntity("other-conversation", "domain") + conversationDAO.insertConversation(newConversationEntity(id = otherConversationId)) + messageDAO.insertOrIgnoreMessage( + newRegularMessageEntity( + id = "other_conversation_message", + conversationId = otherConversationId, + senderUserId = otherUserId, + date = Instant.parse("2024-01-01T00:00:00Z"), + ) + ) + + advanceUntilIdle() + + assertFalse(invalidated()) + } + + @Test + fun givenMessageListPagingSource_whenReactionChangesInSameConversation_thenItInvalidates() = runTest { + populateMessageData() + val pagingSource = getPager().pagingSource + + pagingSource.refresh() + val invalidated = pagingSource.observeInvalidation() + + reactionDAO.insertReaction( + originalMessageId = "0", + conversationId = CONVERSATION_ID, + senderUserId = otherUserId, + instant = Instant.parse("2024-01-01T00:00:00Z"), + emoji = "🔥" + ) + + advanceUntilIdle() + + assertTrue(invalidated()) + } + + @Test + fun givenMessageListPagingSource_whenReceiptChangesInSameConversation_thenItInvalidates() = runTest { + populateMessageData() + val pagingSource = getPager().pagingSource + + pagingSource.refresh() + val invalidated = pagingSource.observeInvalidation() + + receiptDAO.insertReceipts( + userId = otherUserId, + conversationId = CONVERSATION_ID, + date = Instant.parse("2024-01-01T00:00:00Z"), + type = ReceiptTypeEntity.READ, + messageIds = listOf("0"), + ) + + advanceUntilIdle() + + assertTrue(invalidated()) + } + + @Test + fun givenMessageListPagingSource_whenTextMessageIsEditedInSameConversation_thenItInvalidates() = runTest { + populateMessageData() + val pagingSource = getPager().pagingSource + + pagingSource.refresh() + val invalidated = pagingSource.observeInvalidation() + + messageDAO.updateTextMessageContent( + editInstant = Instant.parse("2024-01-01T00:00:00Z"), + conversationId = CONVERSATION_ID, + currentMessageId = "0", + newTextContent = MessageEntityContent.Text("edited message"), + newMessageId = "0-edited" + ) + + advanceUntilIdle() + + assertTrue(invalidated()) + } + + @Test + fun givenMessageListPagingSource_whenUnrelatedMetadataChanges_thenItDoesNotInvalidate() = runTest { + populateMessageData() + val pagingSource = getPager().pagingSource + + pagingSource.refresh() + val invalidated = pagingSource.observeInvalidation() + + databaseBuilder.database.metadataQueries.insertValue("some_key", "some_value") + + advanceUntilIdle() + + assertFalse(invalidated()) + } + + @Test + fun givenMessageSearchPagingSource_whenMatchingMessageIsInserted_thenItInvalidates() = runTest { + populateMessageData() + val pagingSource = getSearchMessagesPager(searchQuery = "needle").pagingSource + + pagingSource.refresh().also { result -> + assertIs>(result) + assertTrue(result.data.isEmpty()) + } + val invalidated = pagingSource.observeInvalidation() + + messageDAO.insertOrIgnoreMessage( + newRegularMessageEntity( + id = "search_message_after_load", + conversationId = CONVERSATION_ID, + senderUserId = otherUserId, + date = Instant.parse("2024-01-01T00:00:00Z"), + content = MessageEntityContent.Text("contains needle") + ) + ) + + advanceUntilIdle() + + assertTrue(invalidated()) + getSearchMessagesPager(searchQuery = "needle").pagingSource.refresh().also { result -> + assertIs>(result) + assertEquals(listOf("search_message_after_load"), result.data.map { it.id }) + } + } + + @Test + fun givenMessageSearchPagingSource_whenTextMessageIsEditedToMatch_thenItInvalidates() = runTest { + populateMessageData() + val pagingSource = getSearchMessagesPager(searchQuery = "edited").pagingSource + + pagingSource.refresh().also { result -> + assertIs>(result) + assertTrue(result.data.isEmpty()) + } + val invalidated = pagingSource.observeInvalidation() + + messageDAO.updateTextMessageContent( + editInstant = Instant.parse("2024-01-01T00:00:00Z"), + conversationId = CONVERSATION_ID, + currentMessageId = "0", + newTextContent = MessageEntityContent.Text("edited message"), + newMessageId = "0-edited-search" + ) + + advanceUntilIdle() + + assertTrue(invalidated()) + getSearchMessagesPager(searchQuery = "edited").pagingSource.refresh().also { result -> + assertIs>(result) + assertEquals(listOf("0-edited-search"), result.data.map { it.id }) + } + } + + @Test + fun givenMessageSearchPagingSource_whenMatchingMessageIsInsertedInOtherConversation_thenItDoesNotInvalidateAndResultsStayEmpty() = runTest { + populateMessageData() + val pagingSource = getSearchMessagesPager(searchQuery = "needle").pagingSource + + pagingSource.refresh().also { result -> + assertIs>(result) + assertTrue(result.data.isEmpty()) + } + val invalidated = pagingSource.observeInvalidation() + + val otherConversationId = ConversationIDEntity("other-search-conversation", "domain") + conversationDAO.insertConversation(newConversationEntity(id = otherConversationId)) + messageDAO.insertOrIgnoreMessage( + newRegularMessageEntity( + id = "other_search_message", + conversationId = otherConversationId, + senderUserId = otherUserId, + date = Instant.parse("2024-01-01T00:00:00Z"), + content = MessageEntityContent.Text("contains needle") + ) + ) + + advanceUntilIdle() + + assertFalse(invalidated()) + getSearchMessagesPager(searchQuery = "needle").pagingSource.refresh().also { result -> + assertIs>(result) + assertTrue(result.data.isEmpty()) + } + } + + @Test + fun givenMessageSearchPagingSource_whenUnrelatedMetadataChanges_thenItDoesNotInvalidate() = runTest { + populateMessageData() + val pagingSource = getSearchMessagesPager(searchQuery = "message").pagingSource + + pagingSource.refresh() + val invalidated = pagingSource.observeInvalidation() + + databaseBuilder.database.metadataQueries.insertValue("search_key", "search_value") + + advanceUntilIdle() + + assertFalse(invalidated()) + } + private fun getPager(): KaliumPager = messageExtensions.getPagerForConversation( conversationId = CONVERSATION_ID, visibilities = MessageEntity.Visibility.entries.toList(), @@ -210,9 +451,16 @@ class MessageExtensionsTest : BaseDatabaseTest() { PagingSource.LoadParams.Append(key, PAGE_SIZE, true) ) + private fun PagingSource.observeInvalidation(): () -> Boolean { + var invalidated = false + registerInvalidatedCallback { + invalidated = true + } + return { invalidated } + } + private suspend fun populateMessageData(prefix: String = "") { - val userId = UserIDEntity("user", "domain") - userDAO.upsertUser(newUserEntity(qualifiedID = userId)) + userDAO.upsertUser(newUserEntity(qualifiedID = otherUserId)) conversationDAO.insertConversation(newConversationEntity(id = CONVERSATION_ID)) val messages = buildList { repeat(MESSAGE_COUNT) { @@ -220,7 +468,7 @@ class MessageExtensionsTest : BaseDatabaseTest() { newRegularMessageEntity( id = it.toString(), conversationId = CONVERSATION_ID, - senderUserId = userId, + senderUserId = otherUserId, content = MessageEntityContent.Text("message $it"), // Ordered by date - Inserting with decreasing date is important to assert pagination date = Instant.fromEpochSeconds(MESSAGE_COUNT - it.toLong())