add unreadCount and minUnreadItemId stats to Chat type (#283)

This commit is contained in:
Efim Poberezkin
2022-02-08 20:38:57 +04:00
committed by GitHub
parent b06838b651
commit 7af4cdffee
2 changed files with 105 additions and 27 deletions
+15 -1
View File
@@ -146,7 +146,11 @@ data NewChatItem d = NewChatItem
deriving (Show)
-- | type to show one chat with messages
data Chat c = Chat {chatInfo :: ChatInfo c, chatItems :: [CChatItem c]}
data Chat c = Chat
{ chatInfo :: ChatInfo c,
chatItems :: [CChatItem c],
chatStats :: ChatStats
}
deriving (Show, Generic)
instance ToJSON (Chat c) where
@@ -161,6 +165,16 @@ instance ToJSON AChat where
toJSON (AChat _ c) = J.toJSON c
toEncoding (AChat _ c) = J.toEncoding c
data ChatStats = ChatStats
{ unreadCount :: Int,
minUnreadItemId :: ChatItemId
}
deriving (Show, Generic)
instance ToJSON ChatStats where
toJSON = J.genericToJSON J.defaultOptions
toEncoding = J.genericToEncoding J.defaultOptions
-- | type to show a mix of messages from multiple chats
data AChatItem = forall c d. AChatItem (SChatType c) (SMsgDirection d) (ChatInfo c) (ChatItem c d)
+90 -26
View File
@@ -2021,10 +2021,10 @@ getChatPreviews st user =
pure $ sortOn (Down . ts) (directChats <> groupChats <> cReqChats)
where
ts :: AChat -> UTCTime
ts (AChat _ (Chat _ (ci : _))) = chatItemTs ci
ts (AChat _ (Chat (DirectChat Contact {createdAt}) [])) = createdAt
ts (AChat _ (Chat (GroupChat GroupInfo {createdAt}) [])) = createdAt
ts (AChat _ (Chat (ContactRequest UserContactRequest {createdAt}) [])) = createdAt
ts (AChat _ (Chat _ (ci : _) _)) = chatItemTs ci
ts (AChat _ (Chat (DirectChat Contact {createdAt}) [] _)) = createdAt
ts (AChat _ (Chat (GroupChat GroupInfo {createdAt}) [] _)) = createdAt
ts (AChat _ (Chat (ContactRequest UserContactRequest {createdAt}) [] _)) = createdAt
chatItemTs :: CChatItem d -> UTCTime
chatItemTs (CChatItem _ (ChatItem _ CIMeta {itemTs} _)) = itemTs
@@ -2042,19 +2042,27 @@ getDirectChatPreviews_ db User {userId} = do
-- Connection
c.connection_id, c.agent_conn_id, c.conn_level, c.via_contact, c.conn_status, c.conn_type,
c.contact_id, c.group_member_id, c.snd_file_id, c.rcv_file_id, c.user_contact_link_id, c.created_at,
-- ChatStats
COALESCE(ChatStats.UnreadCount, 0), COALESCE(ChatStats.MinUnread, 0),
-- ChatItem
ci.chat_item_id, ci.item_ts, ci.item_content, ci.item_text, ci.item_status, ci.created_at
FROM contacts ct
JOIN contact_profiles cp ON ct.contact_profile_id = cp.contact_profile_id
JOIN connections c ON c.contact_id = ct.contact_id
LEFT JOIN (
SELECT contact_id, MAX(item_ts) MaxDate
SELECT contact_id, MAX(item_ts) AS MaxDate
FROM chat_items
WHERE item_deleted != 1
GROUP BY contact_id
) CIMaxDates ON CIMaxDates.contact_id = c.contact_id
) CIMaxDates ON CIMaxDates.contact_id = ct.contact_id
LEFT JOIN chat_items ci ON ci.contact_id = CIMaxDates.contact_id
AND ci.item_ts = CIMaxDates.MaxDate
LEFT JOIN (
SELECT contact_id, COUNT(1) AS UnreadCount, MIN(chat_item_id) AS MinUnread
FROM chat_items
WHERE item_status = ?
GROUP BY contact_id
) ChatStats ON ChatStats.contact_id = ct.contact_id
WHERE ct.user_id = ?
AND c.connection_id = (
SELECT cc_connection_id FROM (
@@ -2069,13 +2077,14 @@ getDirectChatPreviews_ db User {userId} = do
)
ORDER BY ci.item_ts DESC
|]
(userId, ConnReady, ConnSndReady)
(CISRcvNew, userId, ConnReady, ConnSndReady)
where
toDirectChatPreview :: TimeZone -> ContactRow :. ConnectionRow :. MaybeChatItemRow -> AChat
toDirectChatPreview tz (contactRow :. connRow :. ciRow_) =
toDirectChatPreview :: TimeZone -> ContactRow :. ConnectionRow :. ChatStatsRow :. MaybeChatItemRow -> AChat
toDirectChatPreview tz (contactRow :. connRow :. statsRow :. ciRow_) =
let contact = toContact $ contactRow :. connRow
ci_ = toDirectChatItemList tz ciRow_
in AChat SCTDirect $ Chat (DirectChat contact) ci_
stats = toChatStats statsRow
in AChat SCTDirect $ Chat (DirectChat contact) ci_ stats
getGroupChatPreviews_ :: DB.Connection -> User -> IO [AChat]
getGroupChatPreviews_ db User {userId, userContactId} = do
@@ -2091,6 +2100,8 @@ getGroupChatPreviews_ db User {userId, userContactId} = do
mu.group_member_id, mu.group_id, mu.member_id, mu.member_role, mu.member_category,
mu.member_status, mu.invited_by, mu.local_display_name, mu.contact_id,
pu.display_name, pu.full_name,
-- ChatStats
COALESCE(ChatStats.UnreadCount, 0), COALESCE(ChatStats.MinUnread, 0),
-- ChatItem
ci.chat_item_id, ci.item_ts, ci.item_content, ci.item_text, ci.item_status, ci.created_at,
-- Maybe GroupMember - sender
@@ -2102,25 +2113,32 @@ getGroupChatPreviews_ db User {userId, userContactId} = do
JOIN group_members mu ON mu.group_id = g.group_id
JOIN contact_profiles pu ON pu.contact_profile_id = mu.contact_profile_id
LEFT JOIN (
SELECT group_id, MAX(item_ts) MaxDate
SELECT group_id, MAX(item_ts) AS MaxDate
FROM chat_items
WHERE item_deleted != 1
GROUP BY group_id
) GIMaxDates ON GIMaxDates.group_id = g.group_id
LEFT JOIN chat_items ci ON ci.group_id = GIMaxDates.group_id
AND ci.item_ts = GIMaxDates.MaxDate
LEFT JOIN (
SELECT group_id, COUNT(1) AS UnreadCount, MIN(chat_item_id) AS MinUnread
FROM chat_items
WHERE item_status = ?
GROUP BY group_id
) ChatStats ON ChatStats.group_id = g.group_id
LEFT JOIN group_members m ON m.group_member_id = ci.group_member_id
LEFT JOIN contact_profiles p ON p.contact_profile_id = m.contact_profile_id
WHERE g.user_id = ? AND mu.contact_id = ?
ORDER BY ci.item_ts DESC
|]
(userId, userContactId)
(CISRcvNew, userId, userContactId)
where
toGroupChatPreview :: TimeZone -> GroupInfoRow :. MaybeGroupChatItemRow -> AChat
toGroupChatPreview tz (groupInfoRow :. ciRow_) =
toGroupChatPreview :: TimeZone -> GroupInfoRow :. ChatStatsRow :. MaybeGroupChatItemRow -> AChat
toGroupChatPreview tz (groupInfoRow :. statsRow :. ciRow_) =
let groupInfo = toGroupInfo userContactId groupInfoRow
ci_ = toGroupChatItemList tz userContactId ciRow_
in AChat SCTGroup $ Chat (GroupChat groupInfo) ci_
stats = toChatStats statsRow
in AChat SCTGroup $ Chat (GroupChat groupInfo) ci_ stats
getContactRequestChatPreviews_ :: DB.Connection -> User -> IO [AChat]
getContactRequestChatPreviews_ db User {userId} =
@@ -2141,7 +2159,8 @@ getContactRequestChatPreviews_ db User {userId} =
toContactRequestChatPreview :: ContactRequestRow -> AChat
toContactRequestChatPreview cReqRow =
let cReq = toContactRequest cReqRow
in AChat SCTContactRequest $ Chat (ContactRequest cReq) []
stats = ChatStats {unreadCount = 0, minUnreadItemId = 0}
in AChat SCTContactRequest $ Chat (ContactRequest cReq) [] stats
getDirectChat :: StoreMonad m => SQLiteStore -> User -> Int64 -> ChatPagination -> m (Chat 'CTDirect)
getDirectChat st user contactId pagination =
@@ -2154,8 +2173,9 @@ getDirectChat st user contactId pagination =
getDirectChatLast_ :: DB.Connection -> User -> Int64 -> Int -> ExceptT StoreError IO (Chat 'CTDirect)
getDirectChatLast_ db User {userId} contactId count = do
contact <- ExceptT $ getContact_ db userId contactId
stats <- liftIO $ getDirectChatStats_ db userId contactId
chatItems <- ExceptT getDirectChatItemsLast_
pure $ Chat (DirectChat contact) (reverse chatItems)
pure $ Chat (DirectChat contact) (reverse chatItems) stats
where
getDirectChatItemsLast_ :: IO (Either StoreError [CChatItem 'CTDirect])
getDirectChatItemsLast_ = do
@@ -2177,8 +2197,9 @@ getDirectChatLast_ db User {userId} contactId count = do
getDirectChatAfter_ :: DB.Connection -> User -> Int64 -> ChatItemId -> Int -> ExceptT StoreError IO (Chat 'CTDirect)
getDirectChatAfter_ db User {userId} contactId afterChatItemId count = do
contact <- ExceptT $ getContact_ db userId contactId
stats <- liftIO $ getDirectChatStats_ db userId contactId
chatItems <- ExceptT getDirectChatItemsAfter_
pure $ Chat (DirectChat contact) chatItems
pure $ Chat (DirectChat contact) chatItems stats
where
getDirectChatItemsAfter_ :: IO (Either StoreError [CChatItem 'CTDirect])
getDirectChatItemsAfter_ = do
@@ -2200,8 +2221,9 @@ getDirectChatAfter_ db User {userId} contactId afterChatItemId count = do
getDirectChatBefore_ :: DB.Connection -> User -> Int64 -> ChatItemId -> Int -> ExceptT StoreError IO (Chat 'CTDirect)
getDirectChatBefore_ db User {userId} contactId beforeChatItemId count = do
contact <- ExceptT $ getContact_ db userId contactId
stats <- liftIO $ getDirectChatStats_ db userId contactId
chatItems <- ExceptT getDirectChatItemsBefore_
pure $ Chat (DirectChat contact) (reverse chatItems)
pure $ Chat (DirectChat contact) (reverse chatItems) stats
where
getDirectChatItemsBefore_ :: IO (Either StoreError [CChatItem 'CTDirect])
getDirectChatItemsBefore_ = do
@@ -2220,6 +2242,23 @@ getDirectChatBefore_ db User {userId} contactId beforeChatItemId count = do
|]
(userId, contactId, beforeChatItemId, count)
getDirectChatStats_ :: DB.Connection -> UserId -> Int64 -> IO ChatStats
getDirectChatStats_ db userId contactId =
toChatStats'
<$> DB.query
db
[sql|
SELECT COUNT(1), MIN(chat_item_id)
FROM chat_items
WHERE user_id = ? AND contact_id = ? AND item_status = ?
GROUP BY contact_id
|]
(userId, contactId, CISRcvNew)
where
toChatStats' :: [ChatStatsRow] -> ChatStats
toChatStats' [statsRow] = toChatStats statsRow
toChatStats' _ = ChatStats {unreadCount = 0, minUnreadItemId = 0}
getContactIdByName :: StoreMonad m => SQLiteStore -> UserId -> ContactName -> m Int64
getContactIdByName st userId cName =
liftIOEither . withTransaction st $ \db -> getContactIdByName_ db userId cName
@@ -2269,8 +2308,9 @@ getGroupChat st user groupId pagination =
getGroupChatLast_ :: DB.Connection -> User -> Int64 -> Int -> ExceptT StoreError IO (Chat 'CTGroup)
getGroupChatLast_ db user@User {userId, userContactId} groupId count = do
groupInfo <- ExceptT $ getGroupInfo_ db user groupId
stats <- liftIO $ getGroupChatStats_ db userId groupId
chatItems <- ExceptT getGroupChatItemsLast_
pure $ Chat (GroupChat groupInfo) (reverse chatItems)
pure $ Chat (GroupChat groupInfo) (reverse chatItems) stats
where
getGroupChatItemsLast_ :: IO (Either StoreError [CChatItem 'CTGroup])
getGroupChatItemsLast_ = do
@@ -2298,8 +2338,9 @@ getGroupChatLast_ db user@User {userId, userContactId} groupId count = do
getGroupChatAfter_ :: DB.Connection -> User -> Int64 -> ChatItemId -> Int -> ExceptT StoreError IO (Chat 'CTGroup)
getGroupChatAfter_ db user@User {userId, userContactId} groupId afterChatItemId count = do
groupInfo <- ExceptT $ getGroupInfo_ db user groupId
stats <- liftIO $ getGroupChatStats_ db userId groupId
chatItems <- ExceptT getGroupChatItemsAfter_
pure $ Chat (GroupChat groupInfo) chatItems
pure $ Chat (GroupChat groupInfo) chatItems stats
where
getGroupChatItemsAfter_ :: IO (Either StoreError [CChatItem 'CTGroup])
getGroupChatItemsAfter_ = do
@@ -2327,8 +2368,9 @@ getGroupChatAfter_ db user@User {userId, userContactId} groupId afterChatItemId
getGroupChatBefore_ :: DB.Connection -> User -> Int64 -> ChatItemId -> Int -> ExceptT StoreError IO (Chat 'CTGroup)
getGroupChatBefore_ db user@User {userId, userContactId} groupId beforeChatItemId count = do
groupInfo <- ExceptT $ getGroupInfo_ db user groupId
stats <- liftIO $ getGroupChatStats_ db userId groupId
chatItems <- ExceptT getGroupChatItemsBefore_
pure $ Chat (GroupChat groupInfo) (reverse chatItems)
pure $ Chat (GroupChat groupInfo) (reverse chatItems) stats
where
getGroupChatItemsBefore_ :: IO (Either StoreError [CChatItem 'CTGroup])
getGroupChatItemsBefore_ = do
@@ -2353,6 +2395,23 @@ getGroupChatBefore_ db user@User {userId, userContactId} groupId beforeChatItemI
|]
(userId, groupId, beforeChatItemId, count)
getGroupChatStats_ :: DB.Connection -> UserId -> Int64 -> IO ChatStats
getGroupChatStats_ db userId groupId =
toChatStats'
<$> DB.query
db
[sql|
SELECT COUNT(1), MIN(chat_item_id)
FROM chat_items
WHERE user_id = ? AND group_id = ? AND item_status = ?
GROUP BY group_id
|]
(userId, groupId, CISRcvNew)
where
toChatStats' :: [ChatStatsRow] -> ChatStats
toChatStats' [statsRow] = toChatStats statsRow
toChatStats' _ = ChatStats {unreadCount = 0, minUnreadItemId = 0}
getGroupInfo :: StoreMonad m => SQLiteStore -> User -> Int64 -> m GroupInfo
getGroupInfo st user groupId =
liftIOEither . withTransaction st $ \db ->
@@ -2444,9 +2503,9 @@ updateDirectChatItemsRead st contactId (fromItemId, toItemId) = do
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
WHERE contact_id = ? AND chat_item_id >= ? AND chat_item_id <= ? AND item_sent = ?
WHERE contact_id = ? AND chat_item_id >= ? AND chat_item_id <= ? AND item_status = ?
|]
(CISRcvRead, currentTs, contactId, fromItemId, toItemId, SMDRcv)
(CISRcvRead, currentTs, contactId, fromItemId, toItemId, CISRcvNew)
updateGroupChatItemsRead :: (StoreMonad m) => SQLiteStore -> Int64 -> (ChatItemId, ChatItemId) -> m ()
updateGroupChatItemsRead st groupId (fromItemId, toItemId) = do
@@ -2456,9 +2515,14 @@ updateGroupChatItemsRead st groupId (fromItemId, toItemId) = do
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
WHERE group_id = ? AND chat_item_id >= ? AND chat_item_id <= ? AND item_sent = ?
WHERE group_id = ? AND chat_item_id >= ? AND chat_item_id <= ? AND item_status = ?
|]
(CISRcvRead, currentTs, groupId, fromItemId, toItemId, SMDRcv)
(CISRcvRead, currentTs, groupId, fromItemId, toItemId, CISRcvNew)
type ChatStatsRow = (Int, ChatItemId)
toChatStats :: ChatStatsRow -> ChatStats
toChatStats (unreadCount, minUnreadItemId) = ChatStats {unreadCount, minUnreadItemId}
type ChatItemRow = (Int64, ChatItemTs, ACIContent, Text, ACIStatus, UTCTime)