@ -47,6 +47,7 @@ public struct SessionThreadViewModel: FetchableRecord, Decodable, Equatable, Has
public static let interactionVariantKey : SQL = SQL ( stringLiteral : CodingKeys . interactionVariant . stringValue )
public static let interactionTimestampMsKey : SQL = SQL ( stringLiteral : CodingKeys . interactionTimestampMs . stringValue )
public static let interactionBodyKey : SQL = SQL ( stringLiteral : CodingKeys . interactionBody . stringValue )
public static let interactionStateKey : SQL = SQL ( stringLiteral : CodingKeys . interactionState . stringValue )
public static let interactionIsOpenGroupInvitationKey : SQL = SQL ( stringLiteral : CodingKeys . interactionIsOpenGroupInvitation . stringValue )
public static let interactionAttachmentDescriptionInfoKey : SQL = SQL ( stringLiteral : CodingKeys . interactionAttachmentDescriptionInfo . stringValue )
public static let interactionAttachmentCountKey : SQL = SQL ( stringLiteral : CodingKeys . interactionAttachmentCount . stringValue )
@ -262,27 +263,17 @@ public extension SessionThreadViewModel {
let groupMember : TypedTableAlias < GroupMember > = TypedTableAlias ( )
let openGroup : TypedTableAlias < OpenGroup > = TypedTableAlias ( )
let interaction : TypedTableAlias < Interaction > = TypedTableAlias ( )
let recipientState : TypedTableAlias < RecipientState > = TypedTableAlias ( )
let linkPreview : TypedTableAlias < LinkPreview > = TypedTableAlias ( )
let attachment : TypedTableAlias < Attachment > = TypedTableAlias ( )
let interactionAttachment : TypedTableAlias < InteractionAttachment > = TypedTableAlias ( )
let profile : TypedTableAlias < Profile > = TypedTableAlias ( )
let unreadCountTableLiteral : SQL = SQL ( stringLiteral : " \( ViewModel . threadUnreadCountString ) _table " )
let unreadMentionCountTableLiteral : SQL = SQL ( stringLiteral : " \( ViewModel . threadUnreadMentionCountString ) _table " )
let interactionThreadIdLiteral : SQL = SQL ( stringLiteral : Interaction . Columns . threadId . name )
let profileIdColumnLiteral : SQL = SQL ( stringLiteral : Profile . Columns . id . name )
let profileNicknameColumnLiteral : SQL = SQL ( stringLiteral : Profile . Columns . nickname . name )
let profileNameColumnLiteral : SQL = SQL ( stringLiteral : Profile . Columns . name . name )
let authorProfileLiteral : SQL = SQL ( stringLiteral : " authorProfile " )
let attachmentIdColumnLiteral : SQL = SQL ( stringLiteral : Attachment . Columns . id . name )
let attachmentVariantColumnLiteral : SQL = SQL ( stringLiteral : Attachment . Columns . variant . name )
let attachmentContentTypeColumnLiteral : SQL = SQL ( stringLiteral : Attachment . Columns . contentType . name )
let attachmentSourceFilenameColumnLiteral : SQL = SQL ( stringLiteral : Attachment . Columns . sourceFilename . name )
let firstInteractionAttachmentLiteral : SQL = SQL ( stringLiteral : " firstInteractionAttachment " )
let interactionAttachmentAttachmentIdColumnLiteral : SQL = SQL ( stringLiteral : InteractionAttachment . Columns . attachmentId . name )
let interactionAttachmentInteractionIdColumnLiteral : SQL = SQL ( stringLiteral : InteractionAttachment . Columns . interactionId . name )
let interactionAttachmentAlbumIndexColumnLiteral : SQL = SQL ( stringLiteral : InteractionAttachment . Columns . albumIndex . name )
let interactionStateTableLiteral : SQL = SQL ( stringLiteral : " interactionState " )
let interactionStateInteractionIdColumnLiteral : SQL = SQL ( stringLiteral : RecipientState . Columns . interactionId . name )
let interactionStateStateColumnLiteral : SQL = SQL ( stringLiteral : RecipientState . Columns . state . name )
// / * * N o t e : * * T h e ` n u m C o l u m n s B e f o r e P r o f i l e s ` v a l u e * * M U S T * * m a t c h t h e n u m b e r o f f i e l d s b e f o r e
// / t h e ` V i e w M o d e l . c o n t a c t P r o f i l e K e y ` e n t r y b e l o w o t h e r w i s e t h e q u e r y w i l l f a i l t o
@ -291,7 +282,6 @@ public extension SessionThreadViewModel {
// / E x p l i c i t l y s e t d e f a u l t v a l u e s f o r t h e f i e l d s i g n o r e d f o r s e a r c h r e s u l t s
let numColumnsBeforeProfiles : Int = 11
let numColumnsBetweenProfilesAndAttachmentInfo : Int = 10 // T h e a t t a c h m e n t i n f o c o l u m n s w i l l b e c o m b i n e d
// TODO: S o m e t e s t i n g a r o u n d t h e s u b q u e r i e s i n t h e j o i n s t o s e e i f t h e y i m p a c t p e r f o r m a n c e ( ' S i m u l a t o r 1 ' d e v i c e t a k e s ~ 1 2 5 m s t o c o m p l e t e t h i s q u e r y )
let request : SQLRequest < ViewModel > = " " "
SELECT
@ -306,8 +296,8 @@ public extension SessionThreadViewModel {
\ ( thread [ . onlyNotifyForMentions ] ) AS \ ( ViewModel . threadOnlyNotifyForMentionsKey ) ,
( \ ( typingIndicator [ . threadId ] ) IS NOT NULL ) AS \ ( ViewModel . threadContactIsTypingKey ) ,
\ ( unreadCountTableLiteral) . \ ( ViewModel . threadUnreadCountKey ) AS \ ( ViewModel . threadUnreadCountKey ) ,
\ ( unreadMentionCountTableLiteral) . \ ( ViewModel . threadUnreadMentionCountKey ) AS \ ( ViewModel . threadUnreadMentionCountKey ) ,
\ ( Interaction. self ) . \ ( ViewModel . threadUnreadCountKey ) ,
\ ( Interaction. self ) . \ ( ViewModel . threadUnreadMentionCountKey ) ,
\ ( ViewModel . contactProfileKey ) . * ,
\ ( ViewModel . closedGroupProfileFrontKey ) . * ,
@ -318,59 +308,75 @@ public extension SessionThreadViewModel {
\ ( openGroup [ . name ] ) AS \ ( ViewModel . openGroupNameKey ) ,
\ ( openGroup [ . imageData ] ) AS \ ( ViewModel . openGroupProfilePictureDataKey ) ,
\ ( interaction [ . id ] ) AS \ ( ViewModel . interactionIdKey ) ,
\ ( interaction [ . variant ] ) AS \ ( ViewModel . interactionVariantKey ) ,
\ ( interaction [ . timestampMs ] ) AS \ ( ViewModel . interactionTimestampMsKey ) ,
\ ( interaction [ . body ] ) AS \ ( ViewModel . interactionBodyKey ) ,
\ ( Interaction . self ) . \ ( ViewModel . interactionIdKey ) ,
\ ( Interaction . self ) . \ ( ViewModel . interactionVariantKey ) ,
\ ( Interaction . self ) . \ ( ViewModel . interactionTimestampMsKey ) ,
\ ( Interaction . self ) . \ ( ViewModel . interactionBodyKey ) ,
-- Default to ' sending ' assuming non - processed interaction when null
IFNULL ( \ ( interactionStateTableLiteral ) . \ ( interactionStateStateColumnLiteral ) , \ ( SQL ( " \( RecipientState . State . sending ) " ) ) ) AS \ ( interactionStateTableLiteral ) ,
IFNULL ( MIN ( \ ( recipientState [ . state ] ) ) , \ ( SQL ( " \( RecipientState . State . sending ) " ) ) ) AS \ ( ViewModel. interactionStateKey ) ,
( \ ( linkPreview [ . url ] ) IS NOT NULL ) AS \ ( ViewModel . interactionIsOpenGroupInvitationKey ) ,
\ ( ViewModel . interactionAttachmentDescriptionInfoKey ) . \ ( attachmentIdColumnLiteral ) ,
\ ( ViewModel . interactionAttachmentDescriptionInfoKey ) . \ ( attachmentVariantColumnLiteral ) ,
\ ( ViewModel . interactionAttachmentDescriptionInfoKey ) . \ ( attachmentContentTypeColumnLiteral ) ,
\ ( ViewModel . interactionAttachmentDescriptionInfoKey ) . \ ( attachmentSourceFilenameColumnLiteral ) ,
-- These 4 properties will be combined into ' Attachment . DescriptionInfo '
\ ( attachment [ . id ] ) ,
\ ( attachment [ . variant ] ) ,
\ ( attachment [ . contentType ] ) ,
\ ( attachment [ . sourceFilename ] ) ,
COUNT ( \ ( interactionAttachment [ . interactionId ] ) ) AS \ ( ViewModel . interactionAttachmentCountKey ) ,
\ ( interaction [ . authorId ] ) ,
IFNULL ( \ ( authorProfileLiteral) . \ ( profileNicknameColumnLiteral ) , \ ( authorProfileLiteral ) . \ ( profileNameColumnLiteral ) ) AS \ ( ViewModel . authorNameInternalKey ) ,
IFNULL ( \ ( profile[ . nickname ] ) , \ ( profile [ . name ] ) ) AS \ ( ViewModel . authorNameInternalKey ) ,
\ ( SQL ( " \( userPublicKey ) " ) ) AS \ ( ViewModel . currentUserPublicKeyKey )
FROM \ ( SessionThread . self )
LEFT JOIN \ ( Contact . self ) ON \ ( contact [ . id ] ) = \ ( thread [ . id ] )
LEFT JOIN \ ( ThreadTypingIndicator . self ) ON \ ( typingIndicator [ . threadId ] ) = \ ( thread [ . id ] )
LEFT JOIN (
SELECT * , MAX ( \ ( interaction [ . timestampMs ] ) )
FROM \ ( Interaction . self )
GROUP BY \ ( interaction [ . threadId ] )
) AS \ ( Interaction . self ) ON \ ( interaction [ . threadId ] ) = \ ( thread [ . id ] )
LEFT JOIN (
-- Fetch all interaction - specific data in a subquery to be more efficient
SELECT
\ ( interaction [ . id ] ) AS \ ( ViewModel . interactionIdKey ) ,
\ ( interaction [ . threadId ] ) ,
COUNT ( * ) AS \ ( ViewModel . threadUnreadCountKey )
FROM \ ( Interaction . self )
WHERE \ ( interaction [ . wasRead ] ) = false
GROUP BY \ ( interaction [ . thread Id] )
) AS \ ( unreadCountTableLiteral ) ON \ ( unreadCountTableLiteral ) . \ ( interactionThreadIdLiteral ) = \ ( thread [ . id ] )
LEFT JOIN (
SELECT
\ ( interaction [ . threadId] ) ,
COUNT ( * ) AS \ ( ViewModel . threadUnreadMentionCountKey )
\ ( interaction [ . variant ] ) AS \ ( ViewModel . interactionVariantKey ) ,
MAX ( \ ( interaction [ . timestampMs ] ) ) AS \ ( ViewModel . interactionTimestampMsKey ) ,
\ ( interaction [ . body ] ) AS \ ( ViewModel . interactionBodyKey ) ,
\ ( interaction [ . au tho rId] ) ,
\ ( interaction [ . linkPreviewUrl ] ) ,
SUM ( \ ( interaction [ . wasRead ] ) = false ) AS \ ( ViewModel . threadUnreadCountKey ) ,
SUM ( \ ( interaction [ . wasRead] ) = false AND \ ( interaction [ . hasMention ] ) = true ) AS \ ( ViewModel . threadUnreadMentionCountKey )
FROM \ ( Interaction . self )
WHERE (
\ ( interaction [ . wasRead ] ) = false AND
\ ( interaction [ . hasMention ] ) = true
)
GROUP BY \ ( interaction [ . threadId ] )
) AS \ ( unreadMentionCountTableLiteral ) ON \ ( unreadMentionCountTableLiteral ) . \ ( interactionThreadIdLiteral ) = \ ( thread [ . id ] )
) AS \ ( Interaction . self ) ON \ ( interaction [ . threadId ] ) = \ ( thread [ . id ] )
LEFT JOIN \ ( RecipientState . self ) ON (
-- Ignore ' skipped ' states
\ ( SQL ( " \( recipientState [ . state ] ) != \( RecipientState . State . skipped ) " ) ) AND
\ ( recipientState [ . interactionId ] ) = \ ( Interaction . self ) . \ ( ViewModel . interactionIdKey )
)
LEFT JOIN \ ( LinkPreview . self ) ON (
\ ( linkPreview [ . url ] ) = \ ( interaction [ . linkPreviewUrl ] ) AND
\ ( SQL ( " \( linkPreview [ . variant ] ) = \( LinkPreview . Variant . openGroupInvitation ) " ) ) AND
\ ( Interaction . linkPreviewFilterLiteral ( timestampColumn : ViewModel . interactionTimestampMsKey ) )
)
LEFT JOIN \ ( InteractionAttachment . self ) AS \ ( firstInteractionAttachmentLiteral ) ON (
\ ( firstInteractionAttachmentLiteral ) . \ ( interactionAttachmentAlbumIndexColumnLiteral ) = 0 AND
\ ( firstInteractionAttachmentLiteral ) . \ ( interactionAttachmentInteractionIdColumnLiteral ) = \ ( Interaction . self ) . \ ( ViewModel . interactionIdKey )
)
LEFT JOIN \ ( Attachment . self ) ON \ ( attachment [ . id ] ) = \ ( firstInteractionAttachmentLiteral ) . \ ( interactionAttachmentAttachmentIdColumnLiteral )
LEFT JOIN \ ( InteractionAttachment . self ) ON \ ( interactionAttachment [ . interactionId ] ) = \ ( Interaction . self ) . \ ( ViewModel . interactionIdKey )
LEFT JOIN \ ( Profile . self ) ON \ ( profile [ . id ] ) = \ ( interaction [ . authorId ] )
-- Thread naming & avatar content
LEFT JOIN \ ( Profile . self ) AS \ ( ViewModel . contactProfileKey ) ON \ ( ViewModel . contactProfileKey ) . \ ( profileIdColumnLiteral ) = \ ( thread [ . id ] )
LEFT JOIN \ ( OpenGroup . self ) ON \ ( openGroup [ . threadId ] ) = \ ( thread [ . id ] )
LEFT JOIN \ ( ClosedGroup . self ) ON \ ( closedGroup [ . threadId ] ) = \ ( thread [ . id ] )
LEFT JOIN \ ( GroupMember . self ) ON (
\ ( SQL ( " \( groupMember [ . role ] ) = \( GroupMember . Role . admin ) " ) ) AND
\ ( groupMember [ . groupId ] ) = \ ( closedGroup [ . threadId ] ) AND
\ ( SQL ( " \( groupMember [ . profileId ] ) = \( userPublicKey ) " ) )
)
LEFT JOIN \ ( OpenGroup . self ) ON \ ( openGroup [ . threadId ] ) = \ ( thread [ . id ] )
LEFT JOIN \ ( Profile . self ) AS \ ( ViewModel . closedGroupProfileFrontKey ) ON (
\ ( ViewModel . closedGroupProfileFrontKey ) . \ ( profileIdColumnLiteral ) = (
@ -400,25 +406,6 @@ public extension SessionThreadViewModel {
\ ( ViewModel . closedGroupProfileBackKey ) . \ ( profileIdColumnLiteral ) IS NULL AND
\ ( ViewModel . closedGroupProfileBackFallbackKey ) . \ ( profileIdColumnLiteral ) = \ ( SQL ( " \( userPublicKey ) " ) )
)
LEFT JOIN \ ( Profile . self ) AS \ ( authorProfileLiteral ) ON \ ( authorProfileLiteral ) . \ ( profileIdColumnLiteral ) = \ ( interaction [ . authorId ] )
LEFT JOIN \ ( LinkPreview . self ) ON (
\ ( linkPreview [ . url ] ) = \ ( interaction [ . linkPreviewUrl ] ) AND
\ ( SQL ( " \( linkPreview [ . variant ] ) = \( LinkPreview . Variant . openGroupInvitation ) " ) ) AND
\ ( Interaction . linkPreviewFilterLiteral )
)
LEFT JOIN \ ( InteractionAttachment . self ) ON \ ( interactionAttachment [ . interactionId ] ) = \ ( interaction [ . id ] )
LEFT JOIN \ ( InteractionAttachment . self ) AS \ ( firstInteractionAttachmentLiteral ) ON (
\ ( firstInteractionAttachmentLiteral ) . \ ( interactionAttachmentAlbumIndexColumnLiteral ) = 0 AND
\ ( firstInteractionAttachmentLiteral ) . \ ( interactionAttachmentInteractionIdColumnLiteral ) = \ ( interaction [ . id ] )
)
LEFT JOIN \ ( Attachment . self ) AS \ ( ViewModel . interactionAttachmentDescriptionInfoKey ) ON \ ( ViewModel . interactionAttachmentDescriptionInfoKey ) . \ ( attachmentIdColumnLiteral ) = \ ( firstInteractionAttachmentLiteral ) . \ ( interactionAttachmentAttachmentIdColumnLiteral )
LEFT JOIN (
\ ( RecipientState . selectInteractionState (
tableLiteral : interactionStateTableLiteral ,
idColumnLiteral : interactionStateInteractionIdColumnLiteral
) )
) AS \ ( interactionStateTableLiteral ) ON \ ( interactionStateTableLiteral ) . \ ( interactionStateInteractionIdColumnLiteral ) = \ ( interaction [ . id ] )
WHERE (
\ ( filters )
@ -452,7 +439,6 @@ public extension SessionThreadViewModel {
static func homeQuery ( userPublicKey : String ) -> AdaptedFetchRequest < SQLRequest < SessionThreadViewModel > > {
let thread : TypedTableAlias < SessionThread > = TypedTableAlias ( )
let contact : TypedTableAlias < Contact > = TypedTableAlias ( )
let interaction : TypedTableAlias < Interaction > = TypedTableAlias ( )
return baseQuery (
userPublicKey : userPublicKey ,
@ -465,11 +451,11 @@ public extension SessionThreadViewModel {
) AND (
-- Only show the ' Note to Self ' thread if it has an interaction
\ ( SQL ( " \( thread [ . id ] ) != \( userPublicKey ) " ) ) OR
\ ( interaction[ . id ] ) IS NOT NULL
\ ( Interaction. self ) . \ ( ViewModel . interactionIdKey ) IS NOT NULL
)
" " " ,
ordering : " " "
\ ( thread [ . isPinned ] ) DESC , IFNULL ( \ ( interaction[ . timestampMs ] ) , \ ( thread [ . creationDateTimestamp ] ) ) DESC
\ ( thread [ . isPinned ] ) DESC , IFNULL ( \ ( Interaction. self ) . \ ( ViewModel . interactionTimestampMsKey ) , \ ( thread [ . creationDateTimestamp ] ) ) DESC
" " "
)
}
@ -477,7 +463,6 @@ public extension SessionThreadViewModel {
static func messageRequestsQuery ( userPublicKey : String ) -> AdaptedFetchRequest < SQLRequest < SessionThreadViewModel > > {
let thread : TypedTableAlias < SessionThread > = TypedTableAlias ( )
let contact : TypedTableAlias < Contact > = TypedTableAlias ( )
let interaction : TypedTableAlias < Interaction > = TypedTableAlias ( )
return baseQuery (
userPublicKey : userPublicKey ,
@ -493,7 +478,7 @@ public extension SessionThreadViewModel {
)
" " " ,
ordering : " " "
IFNULL ( \ ( interaction[ . timestampMs ] ) , \ ( thread [ . creationDateTimestamp ] ) ) DESC
IFNULL ( \ ( Interaction. self ) . \ ( ViewModel . interactionTimestampMsKey ) , \ ( thread [ . creationDateTimestamp ] ) ) DESC
" " "
)
}
@ -510,8 +495,6 @@ public extension SessionThreadViewModel {
let openGroup : TypedTableAlias < OpenGroup > = TypedTableAlias ( )
let interaction : TypedTableAlias < Interaction > = TypedTableAlias ( )
let unreadCountTableLiteral : SQL = SQL ( stringLiteral : " \( ViewModel . threadUnreadCountString ) _table " )
let unreadMentionCountTableLiteral : SQL = SQL ( stringLiteral : " \( ViewModel . threadUnreadMentionCountString ) _table " )
let firstUnreadInteractionTableLiteral : SQL = SQL ( stringLiteral : " \( ViewModel . threadFirstUnreadInteractionIdString ) _table " )
let interactionIdLiteral : SQL = SQL ( stringLiteral : Interaction . Columns . id . name )
let interactionThreadIdLiteral : SQL = SQL ( stringLiteral : Interaction . Columns . threadId . name )
@ -555,8 +538,8 @@ public extension SessionThreadViewModel {
\ ( thread [ . onlyNotifyForMentions ] ) AS \ ( ViewModel . threadOnlyNotifyForMentionsKey ) ,
\ ( thread [ . messageDraft ] ) AS \ ( ViewModel . threadMessageDraftKey ) ,
\ ( unreadCountTableLiteral) . \ ( ViewModel . threadUnreadCountKey ) AS \ ( ViewModel . threadUnreadCountKey ) ,
\ ( unreadMentionCountTableLiteral) . \ ( ViewModel . threadUnreadMentionCountKey ) AS \ ( ViewModel . threadUnreadMentionCountKey ) ,
\ ( Interaction. self ) . \ ( ViewModel . threadUnreadCountKey ) ,
\ ( Interaction. self ) . \ ( ViewModel . threadUnreadMentionCountKey ) ,
\ ( firstUnreadInteractionTableLiteral ) . \ ( interactionIdLiteral ) AS \ ( ViewModel . threadFirstUnreadInteractionIdKey ) ,
\ ( ViewModel . contactProfileKey ) . * ,
@ -569,53 +552,39 @@ public extension SessionThreadViewModel {
\ ( openGroup [ . imageData ] ) AS \ ( ViewModel . openGroupProfilePictureDataKey ) ,
\ ( openGroup [ . userCount ] ) AS \ ( ViewModel . openGroupUserCountKey ) ,
\ ( interaction[ . id ] ) AS \ ( ViewModel . interactionIdKey ) ,
\ ( Interaction. self ) . \ ( ViewModel . interactionIdKey ) ,
\ ( SQL ( " \( userPublicKey ) " ) ) AS \ ( ViewModel . currentUserPublicKeyKey )
FROM \ ( SessionThread . self )
LEFT JOIN \ ( Contact . self ) ON \ ( contact [ . id ] ) = \ ( thread [ . id ] )
LEFT JOIN (
-- Fetch all interaction - specific data in a subquery to be more efficient
SELECT
\ ( interaction [ . id ] ) ,
\ ( interaction [ . id ] ) AS \ ( ViewModel . interactionIdKey ) ,
\ ( interaction [ . threadId ] ) ,
MIN ( \ ( interaction [ . timestampMs ] ) )
FROM \ ( Interaction . self )
WHERE (
\ ( interaction [ . wasRead ] ) = false AND
\ ( SQL ( " \( interaction [ . threadId ] ) = \( threadId ) " ) )
)
) AS \ ( firstUnreadInteractionTableLiteral ) ON \ ( firstUnreadInteractionTableLiteral ) . \ ( interactionThreadIdLiteral ) = \ ( thread [ . id ] )
LEFT JOIN (
SELECT * , MAX ( \ ( interaction [ . timestampMs ] ) )
MAX ( \ ( interaction [ . timestampMs ] ) ) ,
SUM ( \ ( interaction [ . wasRead ] ) = false ) AS \ ( ViewModel . threadUnreadCountKey ) ,
SUM ( \ ( interaction [ . wasRead ] ) = false AND \ ( interaction [ . hasMention ] ) = true ) AS \ ( ViewModel . threadUnreadMentionCountKey )
FROM \ ( Interaction . self )
GROUP BY \ ( interaction [ . threadId ] )
) AS \ ( Interaction . self ) ON \ ( interaction [ . threadId ] ) = \ ( thread [ . id ] )
LEFT JOIN (
SELECT
\ ( interaction [ . id ] ) ,
\ ( interaction [ . threadId ] ) ,
COUNT ( * ) AS \ ( ViewModel . threadUnreadCountKey )
FROM \ ( Interaction . self )
WHERE (
\ ( interaction [ . wasRead ] ) = false AND
\ ( SQL ( " \( interaction [ . threadId ] ) = \( threadId ) " ) )
)
GROUP BY \ ( interaction [ . threadId ] )
) AS \ ( unreadCountTableLiteral ) ON \ ( unreadCountTableLiteral ) . \ ( interactionThreadIdLiteral ) = \ ( thread [ . id ] )
LEFT JOIN (
SELECT
\ ( interaction [ . threadId ] ) ,
COUNT ( * ) AS \ ( ViewModel . threadUnreadMentionCountKey )
MIN ( \ ( interaction [ . timestampMs ] ) )
FROM \ ( Interaction . self )
WHERE (
\ ( interaction [ . wasRead ] ) = false AND
\ ( interaction [ . hasMention ] ) = true AND
\ ( SQL ( " \( interaction [ . threadId ] ) = \( threadId ) " ) )
)
GROUP BY \ ( interaction [ . threadId ] )
) AS \ ( unreadMentionCountTableLiteral ) ON \ ( unreadMentionCountTableLiteral ) . \ ( interactionThreadIdLiteral ) = \ ( thread [ . id ] )
) AS \ ( firstUnreadInteractionTableLiteral ) ON \ ( firstUnreadInteractionTableLiteral ) . \ ( interactionThreadIdLiteral ) = \ ( thread [ . id ] )
LEFT JOIN \ ( Profile . self ) AS \ ( ViewModel . contactProfileKey ) ON \ ( ViewModel . contactProfileKey ) . \ ( profileIdColumnLiteral ) = \ ( thread [ . id ] )
LEFT JOIN \ ( OpenGroup . self ) ON \ ( openGroup [ . threadId ] ) = \ ( thread [ . id ] )
LEFT JOIN \ ( ClosedGroup . self ) ON \ ( closedGroup [ . threadId ] ) = \ ( thread [ . id ] )
LEFT JOIN \ ( GroupMember . self ) ON (
\ ( SQL ( " \( groupMember [ . role ] ) = \( GroupMember . Role . standard ) " ) ) AND
@ -633,7 +602,6 @@ public extension SessionThreadViewModel {
)
GROUP BY \ ( groupMember [ . groupId ] )
) AS \ ( closedGroupUserCountTableLiteral ) ON \ ( SQL ( " \( closedGroupUserCountTableLiteral ) . \( groupMemberGroupIdColumnLiteral ) = \( threadId ) " ) )
LEFT JOIN \ ( OpenGroup . self ) ON \ ( openGroup [ . threadId ] ) = \ ( thread [ . id ] )
WHERE \ ( SQL ( " \( thread [ . id ] ) = \( threadId ) " ) )
GROUP BY \ ( thread [ . id ] )