diff --git a/Session/Conversations/Message Cells/VisibleMessageCell.swift b/Session/Conversations/Message Cells/VisibleMessageCell.swift index 442a7e9aa..366dbd9bc 100644 --- a/Session/Conversations/Message Cells/VisibleMessageCell.swift +++ b/Session/Conversations/Message Cells/VisibleMessageCell.swift @@ -503,7 +503,7 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate { let quoteView: QuoteView = QuoteView( for: .regular, authorId: quote.authorId, - quotedText: quote.body, + quotedText: quote.body ?? "QUOTED_MESSAGE_NOT_FOUND".localized(), threadVariant: cellViewModel.threadVariant, currentUserPublicKey: cellViewModel.currentUserPublicKey, currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey, diff --git a/Session/Meta/Translations/de.lproj/Localizable.strings b/Session/Meta/Translations/de.lproj/Localizable.strings index 0088b2bec..1b6923de1 100644 --- a/Session/Meta/Translations/de.lproj/Localizable.strings +++ b/Session/Meta/Translations/de.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/en.lproj/Localizable.strings b/Session/Meta/Translations/en.lproj/Localizable.strings index 58ae00a85..b70b14eef 100644 --- a/Session/Meta/Translations/en.lproj/Localizable.strings +++ b/Session/Meta/Translations/en.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/es.lproj/Localizable.strings b/Session/Meta/Translations/es.lproj/Localizable.strings index c85047355..26b6f747b 100644 --- a/Session/Meta/Translations/es.lproj/Localizable.strings +++ b/Session/Meta/Translations/es.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/fa.lproj/Localizable.strings b/Session/Meta/Translations/fa.lproj/Localizable.strings index fc7608274..ccea39b67 100644 --- a/Session/Meta/Translations/fa.lproj/Localizable.strings +++ b/Session/Meta/Translations/fa.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "پیام شما ارسال نشد."; "INVALID_SESSION_ID_MESSAGE" = "لطفاً شناسه Session را مجدد بررسی کنید."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "لطفاً شناسه بازیابی را مجدد بررسی کنید."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "مدیا"; "DOCUMENT_TAB_TITLE" = "مدارک"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "شما در این مکالمه هیچ مدرکی ندارید."; diff --git a/Session/Meta/Translations/fi.lproj/Localizable.strings b/Session/Meta/Translations/fi.lproj/Localizable.strings index 4ff458bd0..112f7f830 100644 --- a/Session/Meta/Translations/fi.lproj/Localizable.strings +++ b/Session/Meta/Translations/fi.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/fr.lproj/Localizable.strings b/Session/Meta/Translations/fr.lproj/Localizable.strings index 881482017..2121d21f5 100644 --- a/Session/Meta/Translations/fr.lproj/Localizable.strings +++ b/Session/Meta/Translations/fr.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/hi.lproj/Localizable.strings b/Session/Meta/Translations/hi.lproj/Localizable.strings index 1cf729168..db0a168c9 100644 --- a/Session/Meta/Translations/hi.lproj/Localizable.strings +++ b/Session/Meta/Translations/hi.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/hr.lproj/Localizable.strings b/Session/Meta/Translations/hr.lproj/Localizable.strings index 39fd0eda0..064a9f609 100644 --- a/Session/Meta/Translations/hr.lproj/Localizable.strings +++ b/Session/Meta/Translations/hr.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/id-ID.lproj/Localizable.strings b/Session/Meta/Translations/id-ID.lproj/Localizable.strings index 60468ace4..6126efb67 100644 --- a/Session/Meta/Translations/id-ID.lproj/Localizable.strings +++ b/Session/Meta/Translations/id-ID.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/it.lproj/Localizable.strings b/Session/Meta/Translations/it.lproj/Localizable.strings index b528d3110..673f5aab1 100644 --- a/Session/Meta/Translations/it.lproj/Localizable.strings +++ b/Session/Meta/Translations/it.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/ja.lproj/Localizable.strings b/Session/Meta/Translations/ja.lproj/Localizable.strings index f7933ef8d..2db44861f 100644 --- a/Session/Meta/Translations/ja.lproj/Localizable.strings +++ b/Session/Meta/Translations/ja.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/nl.lproj/Localizable.strings b/Session/Meta/Translations/nl.lproj/Localizable.strings index 38b5e5143..6f7e2f5d0 100644 --- a/Session/Meta/Translations/nl.lproj/Localizable.strings +++ b/Session/Meta/Translations/nl.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/pl.lproj/Localizable.strings b/Session/Meta/Translations/pl.lproj/Localizable.strings index 2c1ea7e14..2d1c7a5a9 100644 --- a/Session/Meta/Translations/pl.lproj/Localizable.strings +++ b/Session/Meta/Translations/pl.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings index 1235bc38e..19e8437e9 100644 --- a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings +++ b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/ru.lproj/Localizable.strings b/Session/Meta/Translations/ru.lproj/Localizable.strings index 737d22897..9afd5d770 100644 --- a/Session/Meta/Translations/ru.lproj/Localizable.strings +++ b/Session/Meta/Translations/ru.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/si.lproj/Localizable.strings b/Session/Meta/Translations/si.lproj/Localizable.strings index 0e3bdae28..552e22a5b 100644 --- a/Session/Meta/Translations/si.lproj/Localizable.strings +++ b/Session/Meta/Translations/si.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/sk.lproj/Localizable.strings b/Session/Meta/Translations/sk.lproj/Localizable.strings index 58db95bb6..bcbdb04bc 100644 --- a/Session/Meta/Translations/sk.lproj/Localizable.strings +++ b/Session/Meta/Translations/sk.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/sv.lproj/Localizable.strings b/Session/Meta/Translations/sv.lproj/Localizable.strings index beaf86ca9..f5ee39531 100644 --- a/Session/Meta/Translations/sv.lproj/Localizable.strings +++ b/Session/Meta/Translations/sv.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/th.lproj/Localizable.strings b/Session/Meta/Translations/th.lproj/Localizable.strings index 9df4d727c..0545cc50c 100644 --- a/Session/Meta/Translations/th.lproj/Localizable.strings +++ b/Session/Meta/Translations/th.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings index 8045dc6c3..2c44e3ba5 100644 --- a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings +++ b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings index 44d3ce9a2..165bf84a1 100644 --- a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings index a1374b94f..d524979fd 100644 --- a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings @@ -450,6 +450,7 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; "MEDIA_TAB_TITLE" = "Media"; "DOCUMENT_TAB_TITLE" = "Documents"; "DOCUMENT_TILES_EMPTY_DOCUMENT" = "You don't have any document in this conversation."; diff --git a/SessionMessagingKit/Database/Models/Quote.swift b/SessionMessagingKit/Database/Models/Quote.swift index 633676aa6..af92ee454 100644 --- a/SessionMessagingKit/Database/Models/Quote.swift +++ b/SessionMessagingKit/Database/Models/Quote.swift @@ -89,51 +89,7 @@ public extension Quote { self.interactionId = interactionId self.timestampMs = Int64(quoteProto.id) self.authorId = quoteProto.author - - // Prefer to generate the text snippet locally if available. - let quotedInteraction: Interaction? = try? thread - .interactions - .filter(Interaction.Columns.authorId == quoteProto.author) - .filter(Interaction.Columns.timestampMs == Double(quoteProto.id)) - .fetchOne(db) - - if let quotedInteraction: Interaction = quotedInteraction, quotedInteraction.body?.isEmpty == false { - self.body = quotedInteraction.body - } - else if let body: String = quoteProto.text, !body.isEmpty { - self.body = body - } - else { - self.body = nil - } - - // We only use the first attachment - if let attachment = quoteProto.attachments.first(where: { $0.thumbnail != nil })?.thumbnail { - self.attachmentId = try quotedInteraction - .map { quotedInteraction -> Attachment? in - // If the quotedInteraction has an attachment then try clone it - if let attachment: Attachment = try? quotedInteraction.attachments.fetchOne(db) { - return attachment.cloneAsQuoteThumbnail() - } - - // Otherwise if the quotedInteraction has a link preview, try clone that - return try? quotedInteraction.linkPreview - .fetchOne(db)? - .attachment - .fetchOne(db)? - .cloneAsQuoteThumbnail() - } - .defaulting(to: Attachment(proto: attachment)) - .inserted(db) - .id - } - else { - self.attachmentId = nil - } - - // Make sure the quote is valid before completing - if self.body == nil && self.attachmentId == nil { - return nil - } + self.body = nil + self.attachmentId = nil } } diff --git a/SessionMessagingKit/Shared Models/MessageViewModel.swift b/SessionMessagingKit/Shared Models/MessageViewModel.swift index 2cacba1a3..81c452039 100644 --- a/SessionMessagingKit/Shared Models/MessageViewModel.swift +++ b/SessionMessagingKit/Shared Models/MessageViewModel.swift @@ -633,6 +633,7 @@ public extension MessageViewModel { let disappearingMessagesConfig: TypedTableAlias = TypedTableAlias() let profile: TypedTableAlias = TypedTableAlias() let quote: TypedTableAlias = TypedTableAlias() + let interactionAttachment: TypedTableAlias = TypedTableAlias() let linkPreview: TypedTableAlias = TypedTableAlias() let threadProfileTableLiteral: SQL = SQL(stringLiteral: "threadProfile") @@ -708,7 +709,19 @@ public extension MessageViewModel { LEFT JOIN \(DisappearingMessagesConfiguration.self) ON \(disappearingMessagesConfig[.threadId]) = \(interaction[.threadId]) LEFT JOIN \(OpenGroup.self) ON \(openGroup[.threadId]) = \(interaction[.threadId]) LEFT JOIN \(Profile.self) ON \(profile[.id]) = \(interaction[.authorId]) - LEFT JOIN \(Quote.self) ON \(quote[.interactionId]) = \(interaction[.id]) + LEFT JOIN ( + SELECT \(quote[.interactionId]), + \(quote[.authorId]), + \(quote[.timestampMs]), + \(interaction[.body]) AS \(Quote.Columns.body), + \(interactionAttachment[.attachmentId]) AS \(Quote.Columns.attachmentId) + FROM \(Quote.self) + LEFT JOIN \(Interaction.self) ON ( + \(quote[.authorId]) = \(interaction[.authorId]) AND + \(quote[.timestampMs]) = \(interaction[.timestampMs]) + ) + LEFT JOIN \(InteractionAttachment.self) ON \(interaction[.id]) = \(interactionAttachment[.interactionId]) + ) AS \(ViewModel.quoteKey) ON \(quote[.interactionId]) = \(interaction[.id]) LEFT JOIN \(Attachment.self) AS \(ViewModel.quoteAttachmentKey) ON \(ViewModel.quoteAttachmentKey).\(attachmentIdColumnLiteral) = \(quote[.attachmentId]) LEFT JOIN \(LinkPreview.self) ON ( \(linkPreview[.url]) = \(interaction[.linkPreviewUrl]) AND