diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt index 3a84f225cc..a45d384638 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt @@ -898,6 +898,28 @@ object ChatModel { } } + fun increaseGroupSupportChatsUnreadCounter(rhId: Long?, chatId: ChatId) { + changeGroupSupportChatsUnreadCounter(rhId, chatId, 1) + } + + fun decreaseGroupSupportChatsUnreadCounter(rhId: Long?, chatId: ChatId, by: Int = 1) { + changeGroupSupportChatsUnreadCounter(rhId, chatId, -by) + } + + private fun changeGroupSupportChatsUnreadCounter(rhId: Long?, chatId: ChatId, by: Int = 0) { + if (by == 0) return + + val i = getChatIndex(rhId, chatId) + if (i >= 0) { + val chat = chats.value[i] + chats[i] = chat.copy( + chatStats = chat.chatStats.copy( + supportChatsUnreadCount = (chat.chatStats.supportChatsUnreadCount + by).coerceAtLeast(0), + ) + ) + } + } + fun increaseGroupReportsCounter(rhId: Long?, chatId: ChatId) { changeGroupReportsCounter(rhId, chatId, 1) } @@ -1315,6 +1337,8 @@ data class Chat( val unreadMentions: Int = 0, // actual only via getChats() and getChat(.initial), otherwise, zero val reportsCount: Int = 0, + // actual only via getChats() and getChat(.initial), otherwise, zero + val supportChatsUnreadCount: Int = 0, val minUnreadItemId: Long = 0, // actual only via getChats(), otherwise, false val unreadChat: Boolean = false diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index b8f57259bf..78e4e0edfc 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -2559,10 +2559,12 @@ object ChatController { if (active(r.user)) { withContext(Dispatchers.Main) { chatModel.chatsContext.addChatItem(rhId, cInfo, cItem) - // TODO [knocking] increase support chats unread count; move `isActiveReport` checks inside model functions? if (cItem.isActiveReport) { chatModel.chatsContext.increaseGroupReportsCounter(rhId, cInfo.id) } + if (cInfo.groupChatScope() != null && cItem.isRcvNew && cInfo.ntfsEnabled(cItem)) { + chatModel.chatsContext.increaseGroupSupportChatsUnreadCounter(rhId, cInfo.id) + } } withContext(Dispatchers.Main) { chatModel.secondaryChatsContext.value?.addChatItem(rhId, cInfo, cItem) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt index a440266958..58a019de1e 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt @@ -63,6 +63,7 @@ fun ChatView( onComposed: suspend (chatId: String) -> Unit ) { val showSearch = rememberSaveable { mutableStateOf(false) } + val chat = chatModel.chats.value.firstOrNull { chat -> chat.chatInfo.id == staleChatId.value } // They have their own iterator inside for a reason to prevent crash "Reading a state that was created after the snapshot..." val remoteHostId = remember { derivedStateOf { chatModel.chats.value.firstOrNull { chat -> chat.chatInfo.id == staleChatId.value }?.remoteHostId } } val activeChatInfo = remember { derivedStateOf { @@ -78,7 +79,7 @@ fun ChatView( } } val user = chatModel.currentUser.value val chatInfo = activeChatInfo.value - if (chatInfo == null || user == null) { + if (chat == null || chatInfo == null || user == null) { LaunchedEffect(Unit) { chatModel.chatId.value = null ModalManager.end.closeModals() @@ -139,6 +140,7 @@ fun ChatView( chatsCtx.chats.value.firstOrNull { chat -> chat.chatInfo.id == staleChatId.value }?.chatStats?.unreadCount ?: 0 } } + val reportsCount = reportsCount(chatInfo.id) val clipboard = LocalClipboardManager.current CompositionLocalProvider( LocalAppBarHandler provides rememberAppBarHandler(chatInfo.id, keyboardCoversBar = false), @@ -340,7 +342,7 @@ fun ChatView( } } }, - showGroupReports = { + showReportsOrSupportChats = { val info = activeChatInfo.value ?: return@ChatLayout if (ModalManager.end.hasModalsOpen()) { ModalManager.end.closeModals() @@ -348,7 +350,30 @@ fun ChatView( } hideKeyboard(view) scope.launch { - showGroupReportsView(staleChatId, scrollToItemId, info) + if (reportsCount > 0) { + showGroupReportsView(staleChatId, scrollToItemId, info) + } else if (info is ChatInfo.Group && info.groupInfo.membership.memberRole >= GroupMemberRole.Moderator) { + ModalManager.end.showCustomModal { close -> + MemberSupportView( + chatRh, + chat, + info.groupInfo, + scrollToItemId, + close + ) + } + } else if (info is ChatInfo.Group) { + val scopeInfo = GroupChatScopeInfo.MemberSupport(groupMember_ = null) + val supportChatInfo = ChatInfo.Group(info.groupInfo, groupChatScope = scopeInfo) + scope.launch { + showMemberSupportChatView( + chatModel.chatId, + scrollToItemId = scrollToItemId, + supportChatInfo, + scopeInfo + ) + } + } } }, showMemberInfo = { groupInfo: GroupInfo, member: GroupMember -> @@ -599,6 +624,9 @@ fun ChatView( withBGApi { withContext(Dispatchers.Main) { chatModel.chatsContext.markChatItemsRead(chatRh, chatInfo.id, itemsIds) + if (chatsCtx.secondaryContextFilter != null) { + chatModel.chatsContext.decreaseGroupSupportChatsUnreadCounter(chatRh, chatInfo.id) + } ntfManager.cancelNotificationsForChat(chatInfo.id) chatModel.controller.apiChatItemsRead( chatRh, @@ -705,7 +733,7 @@ fun ChatLayout( selectedChatItems: MutableState?>, back: () -> Unit, info: () -> Unit, - showGroupReports: () -> Unit, + showReportsOrSupportChats: () -> Unit, showMemberInfo: (GroupInfo, GroupMember) -> Unit, loadMessages: suspend (ChatId, ChatPagination, visibleItemIndexesNonReversed: () -> IntRange) -> Unit, deleteMessage: (Long, CIDeleteMode) -> Unit, @@ -856,9 +884,10 @@ fun ChatLayout( } } val reportsCount = reportsCount(chatInfo?.id) + val supportChatsUnreadCount = supportChatsUnreadCount(chatInfo?.id) if (oneHandUI.value && chatBottomBar.value) { - if (chatsCtx.secondaryContextFilter == null && reportsCount > 0) { // TODO [knocking] support chats unread count toolbar - ReportedCountToolbar(reportsCount, withStatusBar = true, showGroupReports) + if (chatsCtx.secondaryContextFilter == null && (reportsCount > 0 || supportChatsUnreadCount > 0)) { + SupportChatsCountToolbar(reportsCount, supportChatsUnreadCount, withStatusBar = true, showReportsOrSupportChats) } else { StatusBarBackground() } @@ -914,8 +943,8 @@ fun ChatLayout( SelectedItemsCounterToolbar(selectedChatItems, !oneHandUI.value || !chatBottomBar.value) } } - if (reportsCount > 0 && (!oneHandUI.value || !chatBottomBar.value)) { - ReportedCountToolbar(reportsCount, withStatusBar = false, showGroupReports) + if ((reportsCount > 0 || supportChatsUnreadCount > 0) && (!oneHandUI.value || !chatBottomBar.value)) { + SupportChatsCountToolbar(reportsCount, supportChatsUnreadCount, withStatusBar = false, showReportsOrSupportChats) } } } @@ -1147,10 +1176,11 @@ fun ChatInfoToolbarTitle(cInfo: ChatInfo, imageSize: Dp = 40.dp, iconColor: Colo } @Composable -private fun ReportedCountToolbar( +private fun SupportChatsCountToolbar( reportsCount: Int, + supportChatsUnreadCount: Int, withStatusBar: Boolean, - showGroupReports: () -> Unit + showReportsOrSupportChats: () -> Unit ) { Box { val statusBarPadding = if (withStatusBar) WindowInsets.statusBars.asPaddingValues().calculateTopPadding() else 0.dp @@ -1159,18 +1189,25 @@ private fun ReportedCountToolbar( .fillMaxWidth() .height(AppBarHeight * fontSizeSqrtMultiplier + statusBarPadding) .background(MaterialTheme.colors.background) - .clickable(onClick = showGroupReports) + .clickable(onClick = showReportsOrSupportChats) .padding(top = statusBarPadding), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center ) { - Icon(painterResource(MR.images.ic_flag), null, Modifier.size(22.dp), tint = MaterialTheme.colors.error) + val iconColor = if (reportsCount == 0) MaterialTheme.colors.primary else MaterialTheme.colors.error + Icon(painterResource(MR.images.ic_flag), null, Modifier.size(22.dp), tint = iconColor) Spacer(Modifier.width(4.dp)) Text( - if (reportsCount == 1) { - stringResource(MR.strings.group_reports_active_one) + if (supportChatsUnreadCount == 0) { + if (reportsCount == 1) { + stringResource(MR.strings.group_reports_active_one) + } else { + stringResource(MR.strings.group_reports_active).format(reportsCount) + } + } else if (reportsCount == 0) { + stringResource(MR.strings.group_new_support_messages).format(supportChatsUnreadCount) } else { - stringResource(MR.strings.group_reports_active).format(reportsCount) + String.format(generalGetString(MR.strings.group_reports_active_new_support_messages), reportsCount, supportChatsUnreadCount) }, style = MaterialTheme.typography.button ) @@ -1255,9 +1292,10 @@ fun BoxScope.ChatItemsList( } val reversedChatItems = remember { derivedStateOf { chatsCtx.chatItems.value.asReversed() } } val reportsCount = reportsCount(chatInfo.id) + val supportChatsUnreadCount = supportChatsUnreadCount(chatInfo.id) val topPaddingToContent = topPaddingToContent( chatView = chatsCtx.secondaryContextFilter == null, - additionalTopBar = chatsCtx.secondaryContextFilter == null && reportsCount > 0 // TODO [knocking] && support chats unread count > 0 ? + additionalTopBar = chatsCtx.secondaryContextFilter == null && (reportsCount > 0 || supportChatsUnreadCount > 0) ) val topPaddingToContentPx = rememberUpdatedState(with(LocalDensity.current) { topPaddingToContent.roundToPx() }) val numberOfBottomAppBars = numberOfBottomAppBars() @@ -1597,7 +1635,7 @@ fun BoxScope.ChatItemsList( ), reverseLayout = true, additionalBarOffset = composeViewHeight, - additionalTopBar = rememberUpdatedState(chatsCtx.secondaryContextFilter == null && reportsCount > 0), // TODO [knocking] && support chats unread count > 0 ? + additionalTopBar = rememberUpdatedState(chatsCtx.secondaryContextFilter == null && (reportsCount > 0 || supportChatsUnreadCount > 0)), chatBottomBar = remember { appPrefs.chatBottomBar.state } ) { val mergedItemsValue = mergedItems.value @@ -2282,6 +2320,15 @@ fun reportsCount(staleChatId: String?): Int { } } +@Composable +fun supportChatsUnreadCount(staleChatId: String?): Int { + return if (staleChatId?.startsWith("#") != true) { + 0 + } else { + remember(staleChatId) { derivedStateOf { chatModel.chats.value.firstOrNull { chat -> chat.chatInfo.id == staleChatId }?.chatStats } }.value?.supportChatsUnreadCount ?: 0 + } +} + private fun reversedChatItemsStatic(chatsCtx: ChatModel.ChatsContext): List = chatsCtx.chatItems.value.asReversed() @@ -2980,7 +3027,7 @@ fun PreviewChatLayout() { selectedChatItems = remember { mutableStateOf(setOf()) }, back = {}, info = {}, - showGroupReports = {}, + showReportsOrSupportChats = {}, showMemberInfo = { _, _ -> }, loadMessages = { _, _, _ -> }, deleteMessage = { _, _ -> }, @@ -3058,7 +3105,7 @@ fun PreviewGroupChatLayout() { selectedChatItems = remember { mutableStateOf(setOf()) }, back = {}, info = {}, - showGroupReports = {}, + showReportsOrSupportChats = {}, showMemberInfo = { _, _ -> }, loadMessages = { _, _, _ -> }, deleteMessage = { _, _ -> }, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/MemberSupportView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/MemberSupportView.kt index 1b7ee1c4d6..d69b6728b9 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/MemberSupportView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/MemberSupportView.kt @@ -27,7 +27,6 @@ import chat.simplex.common.views.chat.* import chat.simplex.common.views.chat.item.ItemAction import chat.simplex.common.views.chatlist.setGroupMembers import chat.simplex.common.views.chatlist.unreadCountStr -import chat.simplex.common.views.newchat.AddContactLearnMore import chat.simplex.res.MR import dev.icerock.moko.resources.compose.painterResource import kotlinx.coroutines.launch diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt index 93d512507a..584a358c5e 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt @@ -364,6 +364,8 @@ fun ChatPreviewView( progressView() } else if (chat.chatStats.reportsCount > 0) { GroupReportsIcon() + } else if (chat.chatStats.supportChatsUnreadCount > 0) { + GroupSupportUnreadIcon() } else { IncognitoIcon(chat.chatInfo.incognito) } @@ -559,6 +561,18 @@ fun GroupReportsIcon() { ) } +@Composable +fun GroupSupportUnreadIcon() { + Icon( + painterResource(MR.images.ic_flag), + contentDescription = null, + tint = MaterialTheme.colors.primary, + modifier = Modifier + .size(21.sp.toDp()) + .offset(x = 2.sp.toDp()) + ) +} + @Composable private fun groupInvitationPreviewText(currentUserProfileDisplayName: String?, groupInfo: GroupInfo): String { return if (groupInfo.membership.memberIncognito) diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index 41cde59499..a3f7ae9dfd 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -465,6 +465,8 @@ 1 report %d reports Member reports + %d new support messages + %1$d reports, %2$d new support messages Share message… diff --git a/src/Simplex/Chat/Messages.hs b/src/Simplex/Chat/Messages.hs index 00dd999139..8aa595bed8 100644 --- a/src/Simplex/Chat/Messages.hs +++ b/src/Simplex/Chat/Messages.hs @@ -350,13 +350,14 @@ data ChatStats = ChatStats { unreadCount :: Int, -- returned both in /_get chat initial API and in /_get chats API unreadMentions :: Int, -- returned both in /_get chat initial API and in /_get chats API reportsCount :: Int, -- returned both in /_get chat initial API and in /_get chats API + supportChatsUnreadCount :: Int, -- returned both in /_get chat initial API and in /_get chats API minUnreadItemId :: ChatItemId, unreadChat :: Bool } deriving (Show) emptyChatStats :: ChatStats -emptyChatStats = ChatStats 0 0 0 0 False +emptyChatStats = ChatStats 0 0 0 0 0 False data NavigationInfo = NavigationInfo { afterUnread :: Int, diff --git a/src/Simplex/Chat/Store/Messages.hs b/src/Simplex/Chat/Store/Messages.hs index d1daace916..d0fb2bfa35 100644 --- a/src/Simplex/Chat/Store/Messages.hs +++ b/src/Simplex/Chat/Store/Messages.hs @@ -632,15 +632,17 @@ data ChatPreviewData (c :: ChatType) where data AChatPreviewData = forall c. ChatTypeI c => ACPD (SChatType c) (ChatPreviewData c) -type ChatStatsRow = (Int, Int, ChatItemId, BoolInt) +type ChatStatsRow = (Int, ChatItemId, BoolInt) toChatStats :: ChatStatsRow -> ChatStats -toChatStats (unreadCount, reportsCount, minUnreadItemId, BI unreadChat) = ChatStats {unreadCount, unreadMentions = 0, reportsCount, minUnreadItemId, unreadChat} +toChatStats (unreadCount, minUnreadItemId, BI unreadChat) = + ChatStats {unreadCount, unreadMentions = 0, reportsCount = 0, supportChatsUnreadCount = 0, minUnreadItemId, unreadChat} -type GroupStatsRow = (Int, Int, Int, ChatItemId, BoolInt) +type GroupStatsRow = (Int, Int, Int, Int, ChatItemId, BoolInt) toGroupStats :: GroupStatsRow -> ChatStats -toGroupStats (unreadCount, unreadMentions, reportsCount, minUnreadItemId, BI unreadChat) = ChatStats {unreadCount, unreadMentions, reportsCount, minUnreadItemId, unreadChat} +toGroupStats (unreadCount, unreadMentions, reportsCount, supportChatsUnreadCount, minUnreadItemId, BI unreadChat) = + ChatStats {unreadCount, unreadMentions, reportsCount, supportChatsUnreadCount, minUnreadItemId, unreadChat} findDirectChatPreviews_ :: DB.Connection -> User -> PaginationByTime -> ChatListQuery -> IO [AChatPreviewData] findDirectChatPreviews_ db User {userId} pagination clq = @@ -662,7 +664,6 @@ findDirectChatPreviews_ db User {userId} pagination clq = LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), ct.unread_chat FROM contacts ct @@ -762,13 +763,14 @@ findGroupChatPreviews_ db User {userId} pagination clq = COALESCE(ChatStats.UnreadCount, 0), COALESCE(ChatStats.UnreadMentions, 0), COALESCE(ReportCount.Count, 0), + COALESCE(SupportChatsUnreadCount.Count, 0), COALESCE(ChatStats.MinUnread, 0), g.unread_chat FROM groups g LEFT JOIN ( SELECT group_id, COUNT(1) AS UnreadCount, SUM(user_mention) as UnreadMentions, MIN(chat_item_id) AS MinUnread FROM chat_items - WHERE user_id = ? AND group_id IS NOT NULL AND item_status = ? + WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND item_status = ? GROUP BY group_id ) ChatStats ON ChatStats.group_id = g.group_id LEFT JOIN ( @@ -778,8 +780,16 @@ findGroupChatPreviews_ db User {userId} pagination clq = AND msg_content_tag = ? AND item_deleted = ? AND item_sent = 0 GROUP BY group_id ) ReportCount ON ReportCount.group_id = g.group_id + LEFT JOIN ( + SELECT group_id, COUNT(1) AS Count + FROM chat_items + WHERE user_id = ? AND group_id IS NOT NULL + AND group_scope_tag IS NOT NULL + AND item_status = ? + GROUP BY group_id + ) SupportChatsUnreadCount ON SupportChatsUnreadCount.group_id = g.group_id |] - baseParams = (userId, userId, CISRcvNew, userId, MCReport_, BI False) + baseParams = (userId, userId, CISRcvNew, userId, MCReport_, BI False, userId, CISRcvNew) getPreviews = case clq of CLQFilters {favorite = False, unread = False} -> do let q = baseQuery <> " WHERE g.user_id = ?" @@ -866,7 +876,6 @@ findLocalChatPreviews_ db User {userId} pagination clq = LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), nf.unread_chat FROM note_folders nf @@ -1485,14 +1494,16 @@ getGroupChatInitial_ db user g scopeInfo_ contentFilter count = do where getStats minUnreadItemId (unreadCount, unreadMentions) = do reportsCount <- getGroupReportsCount_ db user g False - pure ChatStats {unreadCount, unreadMentions, reportsCount, minUnreadItemId, unreadChat = False} + supportChatsUnreadCount <- getGroupSupportChatsUnreadCount_ db user g + pure ChatStats {unreadCount, unreadMentions, reportsCount, supportChatsUnreadCount, minUnreadItemId, unreadChat = False} getGroupStats_ :: DB.Connection -> User -> GroupInfo -> Maybe GroupChatScopeInfo -> ExceptT StoreError IO ChatStats getGroupStats_ db user g scopeInfo_ = do minUnreadItemId <- fromMaybe 0 <$> getGroupMinUnreadId_ db user g scopeInfo_ Nothing (unreadCount, unreadMentions) <- getGroupUnreadCount_ db user g scopeInfo_ Nothing reportsCount <- liftIO $ getGroupReportsCount_ db user g False - pure ChatStats {unreadCount, unreadMentions, reportsCount, minUnreadItemId, unreadChat = False} + supportChatsUnreadCount <- liftIO $ getGroupSupportChatsUnreadCount_ db user g + pure ChatStats {unreadCount, unreadMentions, reportsCount, supportChatsUnreadCount, minUnreadItemId, unreadChat = False} getGroupMinUnreadId_ :: DB.Connection -> User -> GroupInfo -> Maybe GroupChatScopeInfo -> Maybe MsgContentTag -> ExceptT StoreError IO (Maybe ChatItemId) getGroupMinUnreadId_ db user g scopeInfo_ contentFilter = @@ -1506,7 +1517,7 @@ getGroupUnreadCount_ :: DB.Connection -> User -> GroupInfo -> Maybe GroupChatSco getGroupUnreadCount_ db user g scopeInfo_ contentFilter = head <$> queryUnreadGroupItems db user g scopeInfo_ contentFilter baseQuery "" where - baseQuery = "SELECT COUNT(1), COALESCE(SUM(user_mention), 0) FROM chat_items WHERE user_id = ? AND group_id = ? " + baseQuery = "SELECT COUNT(1), COALESCE(SUM(user_mention), 0) FROM chat_items WHERE user_id = ? AND group_id = ? AND group_scope_tag IS NULL " getGroupReportsCount_ :: DB.Connection -> User -> GroupInfo -> Bool -> IO Int getGroupReportsCount_ db User {userId} GroupInfo {groupId} archived = @@ -1516,6 +1527,14 @@ getGroupReportsCount_ db User {userId} GroupInfo {groupId} archived = "SELECT COUNT(1) FROM chat_items WHERE user_id = ? AND group_id = ? AND msg_content_tag = ? AND item_deleted = ? AND item_sent = 0" (userId, groupId, MCReport_, BI archived) +getGroupSupportChatsUnreadCount_ :: DB.Connection -> User -> GroupInfo -> IO Int +getGroupSupportChatsUnreadCount_ db User {userId} GroupInfo {groupId} = + fromOnly . head + <$> DB.query + db + "SELECT COUNT(1) FROM chat_items WHERE user_id = ? AND group_id = ? AND group_scope_tag IS NOT NULL AND item_status = ?" + (userId, groupId, CISRcvNew) + queryUnreadGroupItems :: FromRow r => DB.Connection -> User -> GroupInfo -> Maybe GroupChatScopeInfo -> Maybe MsgContentTag -> Query -> Query -> ExceptT StoreError IO [r] queryUnreadGroupItems db User {userId} GroupInfo {groupId} scopeInfo_ contentFilter baseQuery orderLimit = case (scopeInfo_, contentFilter) of diff --git a/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt b/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt index 95795c6aa7..3b63f346d5 100644 --- a/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt +++ b/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt @@ -1584,7 +1584,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), ct.unread_chat FROM contacts ct @@ -1625,7 +1624,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), ct.unread_chat FROM contacts ct @@ -1660,7 +1658,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), ct.unread_chat FROM contacts ct @@ -1694,7 +1691,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), ct.unread_chat FROM contacts ct @@ -1728,7 +1724,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), ct.unread_chat FROM contacts ct @@ -1762,7 +1757,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), ct.unread_chat FROM contacts ct @@ -1796,7 +1790,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), ct.unread_chat FROM contacts ct @@ -1830,7 +1823,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), ct.unread_chat FROM contacts ct @@ -1864,7 +1856,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), ct.unread_chat FROM contacts ct @@ -1895,7 +1886,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), ct.unread_chat FROM contacts ct @@ -1926,7 +1916,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), ct.unread_chat FROM contacts ct @@ -1959,13 +1948,14 @@ Query: COALESCE(ChatStats.UnreadCount, 0), COALESCE(ChatStats.UnreadMentions, 0), COALESCE(ReportCount.Count, 0), + COALESCE(SupportChatsUnreadCount.Count, 0), COALESCE(ChatStats.MinUnread, 0), g.unread_chat FROM groups g LEFT JOIN ( SELECT group_id, COUNT(1) AS UnreadCount, SUM(user_mention) as UnreadMentions, MIN(chat_item_id) AS MinUnread FROM chat_items - WHERE user_id = ? AND group_id IS NOT NULL AND item_status = ? + WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND item_status = ? GROUP BY group_id ) ChatStats ON ChatStats.group_id = g.group_id LEFT JOIN ( @@ -1975,6 +1965,14 @@ Query: AND msg_content_tag = ? AND item_deleted = ? AND item_sent = 0 GROUP BY group_id ) ReportCount ON ReportCount.group_id = g.group_id + LEFT JOIN ( + SELECT group_id, COUNT(1) AS Count + FROM chat_items + WHERE user_id = ? AND group_id IS NOT NULL + AND group_scope_tag IS NOT NULL + AND item_status = ? + GROUP BY group_id + ) SupportChatsUnreadCount ON SupportChatsUnreadCount.group_id = g.group_id JOIN group_profiles gp ON gp.group_profile_id = g.group_profile_id WHERE g.user_id = ? @@ -1987,13 +1985,16 @@ Query: ORDER BY g.chat_ts DESC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) +MATERIALIZE SupportChatsUnreadCount +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=?) SEARCH gp USING INTEGER PRIMARY KEY (rowid=?) SEARCH ChatStats USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN SEARCH ReportCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN +SEARCH SupportChatsUnreadCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN CORRELATED SCALAR SUBQUERY 1 SEARCH ci USING INDEX idx_chat_items_groups_item_ts (user_id=? AND group_id=?) @@ -2011,13 +2012,14 @@ Query: COALESCE(ChatStats.UnreadCount, 0), COALESCE(ChatStats.UnreadMentions, 0), COALESCE(ReportCount.Count, 0), + COALESCE(SupportChatsUnreadCount.Count, 0), COALESCE(ChatStats.MinUnread, 0), g.unread_chat FROM groups g LEFT JOIN ( SELECT group_id, COUNT(1) AS UnreadCount, SUM(user_mention) as UnreadMentions, MIN(chat_item_id) AS MinUnread FROM chat_items - WHERE user_id = ? AND group_id IS NOT NULL AND item_status = ? + WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND item_status = ? GROUP BY group_id ) ChatStats ON ChatStats.group_id = g.group_id LEFT JOIN ( @@ -2027,6 +2029,14 @@ Query: AND msg_content_tag = ? AND item_deleted = ? AND item_sent = 0 GROUP BY group_id ) ReportCount ON ReportCount.group_id = g.group_id + LEFT JOIN ( + SELECT group_id, COUNT(1) AS Count + FROM chat_items + WHERE user_id = ? AND group_id IS NOT NULL + AND group_scope_tag IS NOT NULL + AND item_status = ? + GROUP BY group_id + ) SupportChatsUnreadCount ON SupportChatsUnreadCount.group_id = g.group_id WHERE g.user_id = ? AND (g.favorite = 1 @@ -2034,12 +2044,15 @@ Query: ORDER BY g.chat_ts DESC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) +MATERIALIZE SupportChatsUnreadCount +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=?) SEARCH ChatStats USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN SEARCH ReportCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN +SEARCH SupportChatsUnreadCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN CORRELATED SCALAR SUBQUERY 1 SEARCH ci USING INDEX idx_chat_items_groups_item_ts (user_id=? AND group_id=?) @@ -2057,13 +2070,14 @@ Query: COALESCE(ChatStats.UnreadCount, 0), COALESCE(ChatStats.UnreadMentions, 0), COALESCE(ReportCount.Count, 0), + COALESCE(SupportChatsUnreadCount.Count, 0), COALESCE(ChatStats.MinUnread, 0), g.unread_chat FROM groups g LEFT JOIN ( SELECT group_id, COUNT(1) AS UnreadCount, SUM(user_mention) as UnreadMentions, MIN(chat_item_id) AS MinUnread FROM chat_items - WHERE user_id = ? AND group_id IS NOT NULL AND item_status = ? + WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND item_status = ? GROUP BY group_id ) ChatStats ON ChatStats.group_id = g.group_id LEFT JOIN ( @@ -2073,18 +2087,29 @@ Query: AND msg_content_tag = ? AND item_deleted = ? AND item_sent = 0 GROUP BY group_id ) ReportCount ON ReportCount.group_id = g.group_id + LEFT JOIN ( + SELECT group_id, COUNT(1) AS Count + FROM chat_items + WHERE user_id = ? AND group_id IS NOT NULL + AND group_scope_tag IS NOT NULL + AND item_status = ? + GROUP BY group_id + ) SupportChatsUnreadCount ON SupportChatsUnreadCount.group_id = g.group_id WHERE g.user_id = ? AND (g.unread_chat = 1 OR ChatStats.UnreadCount > 0) AND g.chat_ts < ? ORDER BY g.chat_ts DESC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) +MATERIALIZE SupportChatsUnreadCount +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=? AND chat_ts 0) AND g.chat_ts > ? ORDER BY g.chat_ts ASC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) +MATERIALIZE SupportChatsUnreadCount +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=? AND chat_ts>?) SEARCH ChatStats USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN SEARCH ReportCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN +SEARCH SupportChatsUnreadCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN CORRELATED SCALAR SUBQUERY 1 SEARCH ci USING INDEX idx_chat_items_groups_item_ts (user_id=? AND group_id=?) @@ -2147,13 +2184,14 @@ Query: COALESCE(ChatStats.UnreadCount, 0), COALESCE(ChatStats.UnreadMentions, 0), COALESCE(ReportCount.Count, 0), + COALESCE(SupportChatsUnreadCount.Count, 0), COALESCE(ChatStats.MinUnread, 0), g.unread_chat FROM groups g LEFT JOIN ( SELECT group_id, COUNT(1) AS UnreadCount, SUM(user_mention) as UnreadMentions, MIN(chat_item_id) AS MinUnread FROM chat_items - WHERE user_id = ? AND group_id IS NOT NULL AND item_status = ? + WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND item_status = ? GROUP BY group_id ) ChatStats ON ChatStats.group_id = g.group_id LEFT JOIN ( @@ -2163,18 +2201,29 @@ Query: AND msg_content_tag = ? AND item_deleted = ? AND item_sent = 0 GROUP BY group_id ) ReportCount ON ReportCount.group_id = g.group_id + LEFT JOIN ( + SELECT group_id, COUNT(1) AS Count + FROM chat_items + WHERE user_id = ? AND group_id IS NOT NULL + AND group_scope_tag IS NOT NULL + AND item_status = ? + GROUP BY group_id + ) SupportChatsUnreadCount ON SupportChatsUnreadCount.group_id = g.group_id WHERE g.user_id = ? AND (g.unread_chat = 1 OR ChatStats.UnreadCount > 0) ORDER BY g.chat_ts DESC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) +MATERIALIZE SupportChatsUnreadCount +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=?) SEARCH ChatStats USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN SEARCH ReportCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN +SEARCH SupportChatsUnreadCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN CORRELATED SCALAR SUBQUERY 1 SEARCH ci USING INDEX idx_chat_items_groups_item_ts (user_id=? AND group_id=?) @@ -2192,13 +2241,14 @@ Query: COALESCE(ChatStats.UnreadCount, 0), COALESCE(ChatStats.UnreadMentions, 0), COALESCE(ReportCount.Count, 0), + COALESCE(SupportChatsUnreadCount.Count, 0), COALESCE(ChatStats.MinUnread, 0), g.unread_chat FROM groups g LEFT JOIN ( SELECT group_id, COUNT(1) AS UnreadCount, SUM(user_mention) as UnreadMentions, MIN(chat_item_id) AS MinUnread FROM chat_items - WHERE user_id = ? AND group_id IS NOT NULL AND item_status = ? + WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND item_status = ? GROUP BY group_id ) ChatStats ON ChatStats.group_id = g.group_id LEFT JOIN ( @@ -2208,18 +2258,29 @@ Query: AND msg_content_tag = ? AND item_deleted = ? AND item_sent = 0 GROUP BY group_id ) ReportCount ON ReportCount.group_id = g.group_id + LEFT JOIN ( + SELECT group_id, COUNT(1) AS Count + FROM chat_items + WHERE user_id = ? AND group_id IS NOT NULL + AND group_scope_tag IS NOT NULL + AND item_status = ? + GROUP BY group_id + ) SupportChatsUnreadCount ON SupportChatsUnreadCount.group_id = g.group_id WHERE g.user_id = ? AND g.favorite = 1 AND g.chat_ts < ? ORDER BY g.chat_ts DESC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) +MATERIALIZE SupportChatsUnreadCount +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=? AND chat_ts ? ORDER BY g.chat_ts ASC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) +MATERIALIZE SupportChatsUnreadCount +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=? AND chat_ts>?) SEARCH ChatStats USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN SEARCH ReportCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN +SEARCH SupportChatsUnreadCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN CORRELATED SCALAR SUBQUERY 1 SEARCH ci USING INDEX idx_chat_items_groups_item_ts (user_id=? AND group_id=?) @@ -2282,13 +2355,14 @@ Query: COALESCE(ChatStats.UnreadCount, 0), COALESCE(ChatStats.UnreadMentions, 0), COALESCE(ReportCount.Count, 0), + COALESCE(SupportChatsUnreadCount.Count, 0), COALESCE(ChatStats.MinUnread, 0), g.unread_chat FROM groups g LEFT JOIN ( SELECT group_id, COUNT(1) AS UnreadCount, SUM(user_mention) as UnreadMentions, MIN(chat_item_id) AS MinUnread FROM chat_items - WHERE user_id = ? AND group_id IS NOT NULL AND item_status = ? + WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND item_status = ? GROUP BY group_id ) ChatStats ON ChatStats.group_id = g.group_id LEFT JOIN ( @@ -2298,18 +2372,29 @@ Query: AND msg_content_tag = ? AND item_deleted = ? AND item_sent = 0 GROUP BY group_id ) ReportCount ON ReportCount.group_id = g.group_id + LEFT JOIN ( + SELECT group_id, COUNT(1) AS Count + FROM chat_items + WHERE user_id = ? AND group_id IS NOT NULL + AND group_scope_tag IS NOT NULL + AND item_status = ? + GROUP BY group_id + ) SupportChatsUnreadCount ON SupportChatsUnreadCount.group_id = g.group_id WHERE g.user_id = ? AND g.favorite = 1 ORDER BY g.chat_ts DESC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) +MATERIALIZE SupportChatsUnreadCount +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=?) SEARCH ChatStats USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN SEARCH ReportCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN +SEARCH SupportChatsUnreadCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN CORRELATED SCALAR SUBQUERY 1 SEARCH ci USING INDEX idx_chat_items_groups_item_ts (user_id=? AND group_id=?) @@ -2327,13 +2412,14 @@ Query: COALESCE(ChatStats.UnreadCount, 0), COALESCE(ChatStats.UnreadMentions, 0), COALESCE(ReportCount.Count, 0), + COALESCE(SupportChatsUnreadCount.Count, 0), COALESCE(ChatStats.MinUnread, 0), g.unread_chat FROM groups g LEFT JOIN ( SELECT group_id, COUNT(1) AS UnreadCount, SUM(user_mention) as UnreadMentions, MIN(chat_item_id) AS MinUnread FROM chat_items - WHERE user_id = ? AND group_id IS NOT NULL AND item_status = ? + WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND item_status = ? GROUP BY group_id ) ChatStats ON ChatStats.group_id = g.group_id LEFT JOIN ( @@ -2343,15 +2429,26 @@ Query: AND msg_content_tag = ? AND item_deleted = ? AND item_sent = 0 GROUP BY group_id ) ReportCount ON ReportCount.group_id = g.group_id + LEFT JOIN ( + SELECT group_id, COUNT(1) AS Count + FROM chat_items + WHERE user_id = ? AND group_id IS NOT NULL + AND group_scope_tag IS NOT NULL + AND item_status = ? + GROUP BY group_id + ) SupportChatsUnreadCount ON SupportChatsUnreadCount.group_id = g.group_id WHERE g.user_id = ? AND g.chat_ts < ? ORDER BY g.chat_ts DESC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) +MATERIALIZE SupportChatsUnreadCount +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=? AND chat_ts ? ORDER BY g.chat_ts ASC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) +MATERIALIZE SupportChatsUnreadCount +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=? AND chat_ts>?) SEARCH ChatStats USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN SEARCH ReportCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN +SEARCH SupportChatsUnreadCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN CORRELATED SCALAR SUBQUERY 1 SEARCH ci USING INDEX idx_chat_items_groups_item_ts (user_id=? AND group_id=?) @@ -2411,13 +2520,14 @@ Query: COALESCE(ChatStats.UnreadCount, 0), COALESCE(ChatStats.UnreadMentions, 0), COALESCE(ReportCount.Count, 0), + COALESCE(SupportChatsUnreadCount.Count, 0), COALESCE(ChatStats.MinUnread, 0), g.unread_chat FROM groups g LEFT JOIN ( SELECT group_id, COUNT(1) AS UnreadCount, SUM(user_mention) as UnreadMentions, MIN(chat_item_id) AS MinUnread FROM chat_items - WHERE user_id = ? AND group_id IS NOT NULL AND item_status = ? + WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND item_status = ? GROUP BY group_id ) ChatStats ON ChatStats.group_id = g.group_id LEFT JOIN ( @@ -2427,15 +2537,26 @@ Query: AND msg_content_tag = ? AND item_deleted = ? AND item_sent = 0 GROUP BY group_id ) ReportCount ON ReportCount.group_id = g.group_id + LEFT JOIN ( + SELECT group_id, COUNT(1) AS Count + FROM chat_items + WHERE user_id = ? AND group_id IS NOT NULL + AND group_scope_tag IS NOT NULL + AND item_status = ? + GROUP BY group_id + ) SupportChatsUnreadCount ON SupportChatsUnreadCount.group_id = g.group_id WHERE g.user_id = ? ORDER BY g.chat_ts DESC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) +MATERIALIZE SupportChatsUnreadCount +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=?) SEARCH ChatStats USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN SEARCH ReportCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN +SEARCH SupportChatsUnreadCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN CORRELATED SCALAR SUBQUERY 1 SEARCH ci USING INDEX idx_chat_items_groups_item_ts (user_id=? AND group_id=?) @@ -2451,7 +2572,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), nf.unread_chat FROM note_folders nf @@ -2487,7 +2607,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), nf.unread_chat FROM note_folders nf @@ -2522,7 +2641,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), nf.unread_chat FROM note_folders nf @@ -2557,7 +2675,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), nf.unread_chat FROM note_folders nf @@ -2592,7 +2709,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), nf.unread_chat FROM note_folders nf @@ -2627,7 +2743,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), nf.unread_chat FROM note_folders nf @@ -2662,7 +2777,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), nf.unread_chat FROM note_folders nf @@ -2697,7 +2811,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), nf.unread_chat FROM note_folders nf @@ -2729,7 +2842,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), nf.unread_chat FROM note_folders nf @@ -2761,7 +2873,6 @@ Query: LIMIT 1 ) AS chat_item_id, COALESCE(ChatStats.UnreadCount, 0), - 0, COALESCE(ChatStats.MinUnread, 0), nf.unread_chat FROM note_folders nf @@ -5527,6 +5638,10 @@ Query: SELECT COUNT(1) FROM chat_item_versions WHERE chat_item_id = ? Plan: SEARCH chat_item_versions USING COVERING INDEX idx_chat_item_versions_chat_item_id (chat_item_id=?) +Query: SELECT COUNT(1) FROM chat_items WHERE user_id = ? AND group_id = ? AND group_scope_tag IS NOT NULL AND item_status = ? +Plan: +SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id=? AND item_status=?) + Query: SELECT COUNT(1) FROM chat_items WHERE user_id = ? AND group_id = ? AND msg_content_tag = ? AND item_deleted = ? AND item_sent = 0 Plan: SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id=? AND msg_content_tag=? AND item_deleted=? AND item_sent=?) @@ -5539,7 +5654,7 @@ Query: SELECT COUNT(1) FROM groups WHERE user_id = ? AND chat_item_ttl > 0 Plan: SEARCH groups USING INDEX idx_groups_chat_ts (user_id=?) -Query: SELECT COUNT(1), COALESCE(SUM(user_mention), 0) FROM chat_items WHERE user_id = ? AND group_id = ? AND group_scope_tag IS NULL AND group_scope_group_member_id IS NULL AND item_status = ? +Query: SELECT COUNT(1), COALESCE(SUM(user_mention), 0) FROM chat_items WHERE user_id = ? AND group_id = ? AND group_scope_tag IS NULL AND group_scope_tag IS NULL AND group_scope_group_member_id IS NULL AND item_status = ? Plan: SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id=? AND item_status=?)