core: fix opening chats on new unread items (after sent or viewed items) (#6747)

* core: fix opening chats on new unread items (after sent or viewed items)

* fix test

* sqlite schema and query plan change

* fix postgresql, update schema

* stabilize tests

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
This commit is contained in:
Evgeny
2026-04-04 16:03:36 +01:00
committed by GitHub
parent 276e6a127e
commit 714156c766
15 changed files with 155 additions and 76 deletions
+1 -1
View File
@@ -635,7 +635,7 @@ setUserChatsRead db User {userId} = do
DB.execute db "UPDATE contacts SET unread_chat = ?, updated_at = ? WHERE user_id = ? AND unread_chat = ?" (BI False, updatedAt, userId, BI True)
DB.execute db "UPDATE groups SET unread_chat = ?, updated_at = ? WHERE user_id = ? AND unread_chat = ?" (BI False, updatedAt, userId, BI True)
DB.execute db "UPDATE note_folders SET unread_chat = ?, updated_at = ? WHERE user_id = ? AND unread_chat = ?" (BI False, updatedAt, userId, BI True)
DB.execute db "UPDATE chat_items SET item_status = ?, updated_at = ? WHERE user_id = ? AND item_status = ?" (CISRcvRead, updatedAt, userId, CISRcvNew)
DB.execute db "UPDATE chat_items SET item_status = ?, item_viewed = 1, updated_at = ? WHERE user_id = ? AND item_status = ?" (CISRcvRead, updatedAt, userId, CISRcvNew)
updateContactStatus :: DB.Connection -> User -> Contact -> ContactStatus -> IO Contact
updateContactStatus db User {userId} ct@Contact {contactId} contactStatus = do
+30 -23
View File
@@ -185,9 +185,11 @@ import UnliftIO.STM
#if defined(dbPostgres)
import Database.PostgreSQL.Simple (FromRow, In (..), Only (..), Query, ToRow, (:.) (..))
import Database.PostgreSQL.Simple.SqlQQ (sql)
import Database.PostgreSQL.Simple.ToField (ToField)
#else
import Database.SQLite.Simple (FromRow, Only (..), Query, ToRow, (:.) (..))
import Database.SQLite.Simple.QQ (sql)
import Database.SQLite.Simple.ToField (ToField)
#endif
deleteContactCIs :: DB.Connection -> User -> Contact -> IO ()
@@ -586,20 +588,20 @@ createNewChatItem_ db User {userId} chatDirection showGroupAsSender msgId_ share
user_id, created_by_msg_id, contact_id, group_id, group_member_id, note_folder_id, group_scope_tag, group_scope_group_member_id,
-- meta
item_sent, item_ts, item_content, item_content_tag, item_text, item_status, msg_content_tag, shared_msg_id,
forwarded_by_group_member_id, include_in_history, created_at, updated_at, item_live, user_mention, has_link, show_group_as_sender, msg_signed, timed_ttl, timed_delete_at,
forwarded_by_group_member_id, include_in_history, created_at, updated_at, item_live, user_mention, has_link, item_viewed, show_group_as_sender, msg_signed, timed_ttl, timed_delete_at,
-- quote
quoted_shared_msg_id, quoted_sent_at, quoted_content, quoted_sent, quoted_member_id,
-- forwarded from
fwd_from_tag, fwd_from_chat_name, fwd_from_msg_dir, fwd_from_contact_id, fwd_from_group_id, fwd_from_chat_item_id
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|]
((userId, msgId_) :. idsRow :. groupScopeRow :. itemRow :. quoteRow' :. forwardedFromRow)
ciId <- insertedRowId db
forM_ msgId_ $ \msgId -> insertChatItemMessage_ db ciId msgId createdAt
pure ciId
where
itemRow :: (SMsgDirection d, UTCTime, CIContent d, Text, Text, CIStatus d, Maybe MsgContentTag, Maybe SharedMsgId, Maybe GroupMemberId, BoolInt) :. (UTCTime, UTCTime, Maybe BoolInt, BoolInt, BoolInt, BoolInt, Maybe MsgSigStatus) :. (Maybe Int, Maybe UTCTime)
itemRow = (msgDirection @d, itemTs, ciContent, toCIContentTag ciContent, ciContentToText ciContent, ciCreateStatus ciContent, msgContentTag <$> ciMsgContent ciContent, sharedMsgId, forwardedByMember, BI includeInHistory) :. (createdAt, createdAt, BI <$> justTrue live, BI userMention, BI hasLink, BI showGroupAsSender, msgSigned) :. ciTimedRow timed
itemRow :: (SMsgDirection d, UTCTime, CIContent d, Text, Text, CIStatus d, Maybe MsgContentTag, Maybe SharedMsgId, Maybe GroupMemberId, BoolInt) :. (UTCTime, UTCTime, Maybe BoolInt, BoolInt, BoolInt, BoolInt, BoolInt, Maybe MsgSigStatus) :. (Maybe Int, Maybe UTCTime)
itemRow = (msgDirection @d, itemTs, ciContent, toCIContentTag ciContent, ciContentToText ciContent, ciCreateStatus ciContent, mcTag_, sharedMsgId, forwardedByMember, BI includeInHistory) :. (createdAt, createdAt, BI <$> justTrue live, BI userMention, BI hasLink, BI itemViewed, BI showGroupAsSender, msgSigned) :. ciTimedRow timed
quoteRow' = let (a, b, c, d, e) = quoteRow in (a, b, c, BI <$> d, e)
idsRow :: (Maybe ContactId, Maybe GroupId, Maybe GroupMemberId, Maybe NoteFolderId)
idsRow = case chatDirection of
@@ -622,8 +624,13 @@ createNewChatItem_ db User {userId} chatDirection showGroupAsSender msgId_ share
_ -> (Nothing, Nothing)
includeInHistory :: Bool
includeInHistory = case groupScope of
Just Nothing -> isJust (ciMsgContent ciContent) && ((msgContentTag <$> ciMsgContent ciContent) /= Just MCReport_)
Just Nothing -> isJust mcTag_ && mcTag_ /= Just MCReport_
_ -> False
itemViewed :: Bool
itemViewed = case msgDirection @d of
SMDSnd -> isJust mcTag_
SMDRcv -> False
mcTag_ = msgContentTag <$> ciMsgContent ciContent
forwardedFromRow :: (Maybe CIForwardedFromTag, Maybe Text, Maybe MsgDirection, Maybe Int64, Maybe Int64, Maybe Int64)
forwardedFromRow = case itemForwarded of
Nothing ->
@@ -1346,7 +1353,7 @@ getContactMinUnreadId_ db User {userId} Contact {contactId} =
|]
(userId, contactId, CISRcvNew)
-- max viewed item: received read or sent (any item_status != CISRcvNew)
-- max viewed item: sent content or received read (excludes born-read events)
getContactMaxViewedItemId_ :: DB.Connection -> User -> Contact -> IO (Maybe ChatItemId)
getContactMaxViewedItemId_ db User {userId} Contact {contactId} =
fmap join . maybeFirstRow fromOnly $
@@ -1355,11 +1362,11 @@ getContactMaxViewedItemId_ db User {userId} Contact {contactId} =
[sql|
SELECT chat_item_id
FROM chat_items
WHERE user_id = ? AND contact_id = ? AND item_status != ?
WHERE user_id = ? AND contact_id = ? AND item_viewed = 1
ORDER BY created_at DESC, chat_item_id DESC
LIMIT 1
|]
(userId, contactId, CISRcvNew)
(userId, contactId)
getContactUnreadCount_ :: DB.Connection -> User -> Contact -> IO Int
getContactUnreadCount_ db User {userId} Contact {contactId} =
@@ -1688,23 +1695,23 @@ getGroupStats_ db user g scopeInfo_ = do
getGroupMinUnreadId_ :: DB.Connection -> User -> GroupInfo -> Maybe GroupChatScopeInfo -> Maybe MsgContentTag -> ExceptT StoreError IO (Maybe ChatItemId)
getGroupMinUnreadId_ db user g scopeInfo_ contentFilter =
fmap join . maybeFirstRow fromOnly $
queryUnreadGroupItems db user g scopeInfo_ contentFilter " item_status = ? " baseQuery orderLimit
queryUnreadGroupItems db user g scopeInfo_ contentFilter " item_status = ? " CISRcvNew baseQuery orderLimit
where
baseQuery = "SELECT chat_item_id FROM chat_items WHERE user_id = ? AND group_id = ? "
orderLimit = " ORDER BY item_ts ASC, chat_item_id ASC LIMIT 1"
-- max viewed item: received read or sent (any item_status != CISRcvNew)
-- max viewed item: sent content or received read (excludes born-read events)
getGroupMaxViewedItemId_ :: DB.Connection -> User -> GroupInfo -> Maybe GroupChatScopeInfo -> Maybe MsgContentTag -> ExceptT StoreError IO (Maybe ChatItemId)
getGroupMaxViewedItemId_ db user g scopeInfo_ contentFilter =
fmap join . maybeFirstRow fromOnly $
queryUnreadGroupItems db user g scopeInfo_ contentFilter " item_status != ? " baseQuery orderLimit
queryUnreadGroupItems db user g scopeInfo_ contentFilter " item_viewed = ? " (BI True) baseQuery orderLimit
where
baseQuery = "SELECT chat_item_id FROM chat_items WHERE user_id = ? AND group_id = ? "
orderLimit = " ORDER BY item_ts DESC, chat_item_id DESC LIMIT 1"
getGroupUnreadCount_ :: DB.Connection -> User -> GroupInfo -> Maybe GroupChatScopeInfo -> Maybe MsgContentTag -> ExceptT StoreError IO (Int, Int)
getGroupUnreadCount_ db user g scopeInfo_ contentFilter =
head <$> queryUnreadGroupItems db user g scopeInfo_ contentFilter " item_status = ? " baseQuery ""
head <$> queryUnreadGroupItems db user g scopeInfo_ contentFilter " item_status = ? " CISRcvNew baseQuery ""
where
baseQuery = "SELECT COUNT(1), COALESCE(SUM(user_mention), 0) FROM chat_items WHERE user_id = ? AND group_id = ? "
@@ -1716,27 +1723,27 @@ 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)
queryUnreadGroupItems :: FromRow r => DB.Connection -> User -> GroupInfo -> Maybe GroupChatScopeInfo -> Maybe MsgContentTag -> Query -> Query -> Query -> ExceptT StoreError IO [r]
queryUnreadGroupItems db User {userId} GroupInfo {groupId} scopeInfo_ contentFilter statusCond baseQuery orderLimit =
queryUnreadGroupItems :: (ToField p, FromRow r) => DB.Connection -> User -> GroupInfo -> Maybe GroupChatScopeInfo -> Maybe MsgContentTag -> Query -> p -> Query -> Query -> ExceptT StoreError IO [r]
queryUnreadGroupItems db User {userId} GroupInfo {groupId} scopeInfo_ contentFilter statusCond statusParam baseQuery orderLimit =
case (scopeInfo_, contentFilter) of
(Nothing, Nothing) ->
liftIO $
DB.query
db
(baseQuery <> " AND group_scope_tag IS NULL AND group_scope_group_member_id IS NULL AND " <> statusCond <> orderLimit)
(userId, groupId, CISRcvNew)
(userId, groupId, statusParam)
(Nothing, Just mcTag) ->
liftIO $
DB.query
db
(baseQuery <> " AND msg_content_tag = ? AND " <> statusCond <> orderLimit)
(userId, groupId, mcTag, CISRcvNew)
(userId, groupId, mcTag, statusParam)
(Just GCSIMemberSupport {groupMember_ = m}, Nothing) ->
liftIO $
DB.query
db
(baseQuery <> " AND group_scope_tag = ? AND group_scope_group_member_id IS NOT DISTINCT FROM ? AND " <> statusCond <> orderLimit)
(userId, groupId, GCSTMemberSupport_, groupMemberId' <$> m, CISRcvNew)
(userId, groupId, GCSTMemberSupport_, groupMemberId' <$> m, statusParam)
(Just _scope, Just _mcTag) ->
throwError $ SEInternalError "group scope and content filter are not supported together"
@@ -1997,7 +2004,7 @@ updateDirectChatItemsRead db User {userId} contactId = do
DB.execute
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
UPDATE chat_items SET item_status = ?, item_viewed = 1, updated_at = ?
WHERE user_id = ? AND contact_id = ? AND item_status = ?
|]
(CISRcvRead, currentTs, userId, contactId, CISRcvNew)
@@ -2042,7 +2049,7 @@ setDirectChatItemRead_ db User {userId} contactId itemId currentTs =
DB.execute
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
UPDATE chat_items SET item_status = ?, item_viewed = 1, updated_at = ?
WHERE user_id = ? AND contact_id = ? AND item_status = ? AND chat_item_id = ?
|]
(CISRcvRead, currentTs, userId, contactId, CISRcvNew, itemId)
@@ -2062,7 +2069,7 @@ updateGroupChatItemsRead db User {userId} GroupInfo {groupId} = do
DB.execute
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
UPDATE chat_items SET item_status = ?, item_viewed = 1, updated_at = ?
WHERE user_id = ? AND group_id = ?
AND item_status = ?
|]
@@ -2076,7 +2083,7 @@ updateSupportChatItemsRead db vr user@User {userId} g@GroupInfo {groupId, member
DB.execute
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
UPDATE chat_items SET item_status = ?, item_viewed = 1, updated_at = ?
WHERE user_id = ? AND group_id = ?
AND group_scope_tag = ? AND group_scope_group_member_id IS NOT DISTINCT FROM ?
AND item_status = ?
@@ -2154,7 +2161,7 @@ updateGroupChatItemsReadList db vr user@User {userId} g@GroupInfo {groupId} scop
DB.query
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
UPDATE chat_items SET item_status = ?, item_viewed = 1, updated_at = ?
WHERE user_id = ? AND group_id = ? AND item_status = ? AND chat_item_id = ?
RETURNING chat_item_id, timed_ttl, timed_delete_at, group_member_id, user_mention
|]
@@ -2237,7 +2244,7 @@ updateLocalChatItemsRead db User {userId} noteFolderId = do
DB.execute
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
UPDATE chat_items SET item_status = ?, item_viewed = 1, updated_at = ?
WHERE user_id = ? AND note_folder_id = ? AND item_status = ?
|]
(CISRcvRead, currentTs, userId, noteFolderId, CISRcvNew)
@@ -27,6 +27,7 @@ import Simplex.Chat.Store.Postgres.Migrations.M20251230_strict_tables
import Simplex.Chat.Store.Postgres.Migrations.M20260108_chat_indices
import Simplex.Chat.Store.Postgres.Migrations.M20260122_has_link
import Simplex.Chat.Store.Postgres.Migrations.M20260222_chat_relays
import Simplex.Chat.Store.Postgres.Migrations.M20260403_item_viewed
import Simplex.Messaging.Agent.Store.Shared (Migration (..))
schemaMigrations :: [(String, Text, Maybe Text)]
@@ -53,7 +54,8 @@ schemaMigrations =
("20251230_strict_tables", m20251230_strict_tables, Just down_m20251230_strict_tables),
("20260108_chat_indices", m20260108_chat_indices, Just down_m20260108_chat_indices),
("20260122_has_link", m20260122_has_link, Just down_m20260122_has_link),
("20260222_chat_relays", m20260222_chat_relays, Just down_m20260222_chat_relays)
("20260222_chat_relays", m20260222_chat_relays, Just down_m20260222_chat_relays),
("20260403_item_viewed", m20260403_item_viewed, Just down_m20260403_item_viewed)
]
-- | The list of migrations in ascending order by date
@@ -1,15 +1,14 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
module Simplex.Chat.Store.Postgres.Migrations.M20260222_chat_relays where
import Data.Text (Text)
import qualified Data.Text as T
import Text.RawString.QQ (r)
m20260222_chat_relays :: Text
m20260222_chat_relays =
T.pack
[r|
[r|
CREATE TABLE chat_relays(
chat_relay_id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
address BYTEA NOT NULL,
@@ -80,8 +79,7 @@ ALTER TABLE connections ADD COLUMN relay_test SMALLINT NOT NULL DEFAULT 0;
down_m20260222_chat_relays :: Text
down_m20260222_chat_relays =
T.pack
[r|
[r|
UPDATE group_members SET member_role = 'observer' WHERE member_role = 'relay';
ALTER TABLE users DROP COLUMN is_user_chat_relay;
@@ -0,0 +1,23 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
module Simplex.Chat.Store.Postgres.Migrations.M20260403_item_viewed where
import Data.Text (Text)
import Text.RawString.QQ (r)
m20260403_item_viewed :: Text
m20260403_item_viewed =
[r|
ALTER TABLE chat_items ADD COLUMN item_viewed SMALLINT NOT NULL DEFAULT 0;
CREATE INDEX idx_chat_items_contacts_item_viewed ON chat_items(user_id, contact_id, item_viewed, created_at);
CREATE INDEX idx_chat_items_groups_item_viewed ON chat_items(user_id, group_id, item_viewed, item_ts);
|]
down_m20260403_item_viewed :: Text
down_m20260403_item_viewed =
[r|
DROP INDEX idx_chat_items_contacts_item_viewed;
DROP INDEX idx_chat_items_groups_item_viewed;
ALTER TABLE chat_items DROP COLUMN item_viewed;
|]
@@ -344,7 +344,8 @@ CREATE TABLE test_chat_schema.chat_items (
group_scope_group_member_id bigint,
show_group_as_sender smallint DEFAULT 0 NOT NULL,
has_link smallint DEFAULT 0 NOT NULL,
msg_signed text
msg_signed text,
item_viewed smallint DEFAULT 0 NOT NULL
);
@@ -1906,6 +1907,10 @@ CREATE INDEX idx_chat_items_contacts_has_link_created_at ON test_chat_schema.cha
CREATE INDEX idx_chat_items_contacts_item_viewed ON test_chat_schema.chat_items USING btree (user_id, contact_id, item_viewed, created_at);
CREATE INDEX idx_chat_items_contacts_msg_content_tag_created_at ON test_chat_schema.chat_items USING btree (user_id, contact_id, msg_content_tag, created_at);
@@ -1978,6 +1983,10 @@ CREATE INDEX idx_chat_items_groups_item_ts ON test_chat_schema.chat_items USING
CREATE INDEX idx_chat_items_groups_item_viewed ON test_chat_schema.chat_items USING btree (user_id, group_id, item_viewed, item_ts);
CREATE INDEX idx_chat_items_groups_msg_content_tag_deleted ON test_chat_schema.chat_items USING btree (user_id, group_id, msg_content_tag, item_deleted, item_sent);
+3 -1
View File
@@ -150,6 +150,7 @@ import Simplex.Chat.Store.SQLite.Migrations.M20251230_strict_tables
import Simplex.Chat.Store.SQLite.Migrations.M20260108_chat_indices
import Simplex.Chat.Store.SQLite.Migrations.M20260122_has_link
import Simplex.Chat.Store.SQLite.Migrations.M20260222_chat_relays
import Simplex.Chat.Store.SQLite.Migrations.M20260403_item_viewed
import Simplex.Messaging.Agent.Store.Shared (Migration (..))
schemaMigrations :: [(String, Query, Maybe Query)]
@@ -299,7 +300,8 @@ schemaMigrations =
("20251230_strict_tables", m20251230_strict_tables, Just down_m20251230_strict_tables),
("20260108_chat_indices", m20260108_chat_indices, Just down_m20260108_chat_indices),
("20260122_has_link", m20260122_has_link, Just down_m20260122_has_link),
("20260222_chat_relays", m20260222_chat_relays, Just down_m20260222_chat_relays)
("20260222_chat_relays", m20260222_chat_relays, Just down_m20260222_chat_relays),
("20260403_item_viewed", m20260403_item_viewed, Just down_m20260403_item_viewed)
]
-- | The list of migrations in ascending order by date
@@ -0,0 +1,22 @@
{-# LANGUAGE QuasiQuotes #-}
module Simplex.Chat.Store.SQLite.Migrations.M20260403_item_viewed where
import Database.SQLite.Simple (Query)
import Database.SQLite.Simple.QQ (sql)
m20260403_item_viewed :: Query
m20260403_item_viewed =
[sql|
ALTER TABLE chat_items ADD COLUMN item_viewed INTEGER NOT NULL DEFAULT 0;
CREATE INDEX idx_chat_items_contacts_item_viewed ON chat_items(user_id, contact_id, item_viewed, created_at);
CREATE INDEX idx_chat_items_groups_item_viewed ON chat_items(user_id, group_id, item_viewed, item_ts);
|]
down_m20260403_item_viewed :: Query
down_m20260403_item_viewed =
[sql|
DROP INDEX idx_chat_items_contacts_item_viewed;
DROP INDEX idx_chat_items_groups_item_viewed;
ALTER TABLE chat_items DROP COLUMN item_viewed;
|]
@@ -868,7 +868,7 @@ Query:
LIMIT ?
Plan:
SEARCH chat_items USING INDEX idx_chat_items_note_folder_has_link_created_at (user_id=?)
SEARCH chat_items USING INDEX idx_chat_items_groups_item_viewed (user_id=?)
USE TEMP B-TREE FOR ORDER BY
Query:
@@ -879,7 +879,7 @@ Query:
LIMIT ?
Plan:
SEARCH chat_items USING INDEX idx_chat_items_note_folder_has_link_created_at (user_id=?)
SEARCH chat_items USING INDEX idx_chat_items_groups_item_viewed (user_id=?)
USE TEMP B-TREE FOR ORDER BY
Query:
@@ -1064,7 +1064,7 @@ SEARCH g USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
SEARCH h USING INDEX idx_sent_probe_hashes_sent_probe_id (sent_probe_id=?)
Query:
UPDATE chat_items SET item_status = ?, updated_at = ?
UPDATE chat_items SET item_status = ?, item_viewed = 1, updated_at = ?
WHERE user_id = ? AND group_id = ? AND item_status = ? AND chat_item_id = ?
RETURNING chat_item_id, timed_ttl, timed_delete_at, group_member_id, user_mention
@@ -1469,7 +1469,7 @@ Query:
LIMIT ?
Plan:
SEARCH chat_items USING INDEX idx_chat_items_note_folder_has_link_created_at (user_id=?)
SEARCH chat_items USING INDEX idx_chat_items_groups_item_viewed (user_id=?)
USE TEMP B-TREE FOR ORDER BY
Query:
@@ -1651,7 +1651,7 @@ SEARCH m USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
SEARCH g USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
Query:
UPDATE chat_items SET item_status = ?, updated_at = ?
UPDATE chat_items SET item_status = ?, item_viewed = 1, updated_at = ?
WHERE user_id = ? AND group_id = ?
AND group_scope_tag = ? AND group_scope_group_member_id IS NOT DISTINCT FROM ?
AND item_status = ?
@@ -3382,16 +3382,6 @@ Query:
Plan:
SEARCH chat_items USING INDEX idx_chat_items_contact_id (contact_id=?)
Query:
SELECT chat_item_id
FROM chat_items
WHERE user_id = ? AND contact_id = ? AND item_status != ?
ORDER BY created_at DESC, chat_item_id DESC
LIMIT 1
Plan:
SEARCH chat_items USING INDEX idx_chat_items_contacts_created_at (user_id=? AND contact_id=?)
Query:
SELECT chat_item_id
FROM chat_items
@@ -3412,6 +3402,16 @@ Query:
Plan:
SEARCH chat_items USING INDEX idx_chat_items_contact_id (contact_id=?)
Query:
SELECT chat_item_id
FROM chat_items
WHERE user_id = ? AND contact_id = ? AND item_viewed = 1
ORDER BY created_at DESC, chat_item_id DESC
LIMIT 1
Plan:
SEARCH chat_items USING COVERING INDEX idx_chat_items_contacts_item_viewed (user_id=? AND contact_id=? AND item_viewed=?)
Query:
SELECT chat_item_id
FROM chat_items
@@ -4540,12 +4540,12 @@ Query:
user_id, created_by_msg_id, contact_id, group_id, group_member_id, note_folder_id, group_scope_tag, group_scope_group_member_id,
-- meta
item_sent, item_ts, item_content, item_content_tag, item_text, item_status, msg_content_tag, shared_msg_id,
forwarded_by_group_member_id, include_in_history, created_at, updated_at, item_live, user_mention, has_link, show_group_as_sender, msg_signed, timed_ttl, timed_delete_at,
forwarded_by_group_member_id, include_in_history, created_at, updated_at, item_live, user_mention, has_link, item_viewed, show_group_as_sender, msg_signed, timed_ttl, timed_delete_at,
-- quote
quoted_shared_msg_id, quoted_sent_at, quoted_content, quoted_sent, quoted_member_id,
-- forwarded from
fwd_from_tag, fwd_from_chat_name, fwd_from_msg_dir, fwd_from_contact_id, fwd_from_group_id, fwd_from_chat_item_id
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
Plan:
@@ -4763,21 +4763,21 @@ Plan:
SEARCH chat_items USING INTEGER PRIMARY KEY (rowid=?)
Query:
UPDATE chat_items SET item_status = ?, updated_at = ?
UPDATE chat_items SET item_status = ?, item_viewed = 1, updated_at = ?
WHERE user_id = ? AND contact_id = ? AND item_status = ?
Plan:
SEARCH chat_items USING INDEX idx_chat_items_contacts (user_id=? AND contact_id=? AND item_status=?)
Query:
UPDATE chat_items SET item_status = ?, updated_at = ?
UPDATE chat_items SET item_status = ?, item_viewed = 1, updated_at = ?
WHERE user_id = ? AND contact_id = ? AND item_status = ? AND chat_item_id = ?
Plan:
SEARCH chat_items USING INTEGER PRIMARY KEY (rowid=?)
Query:
UPDATE chat_items SET item_status = ?, updated_at = ?
UPDATE chat_items SET item_status = ?, item_viewed = 1, updated_at = ?
WHERE user_id = ? AND group_id = ?
AND item_status = ?
@@ -4785,7 +4785,7 @@ Plan:
SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id=? AND item_status=?)
Query:
UPDATE chat_items SET item_status = ?, updated_at = ?
UPDATE chat_items SET item_status = ?, item_viewed = 1, updated_at = ?
WHERE user_id = ? AND note_folder_id = ? AND item_status = ?
Plan:
@@ -5545,7 +5545,7 @@ Query:
JOIN files f ON f.chat_item_id = i.chat_item_id
WHERE i.user_id = ?
Plan:
SEARCH i USING COVERING INDEX idx_chat_items_note_folder_has_link_created_at (user_id=?)
SEARCH i USING COVERING INDEX idx_chat_items_groups_item_viewed (user_id=?)
SEARCH f USING INDEX idx_files_chat_item_id (chat_item_id=?)
Query:
@@ -5554,7 +5554,7 @@ Query:
JOIN files f ON f.chat_item_id = i.chat_item_id
WHERE i.user_id = ? AND i.contact_id = ?
Plan:
SEARCH i USING COVERING INDEX idx_chat_items_contacts_has_link_created_at (user_id=? AND contact_id=?)
SEARCH i USING COVERING INDEX idx_chat_items_contacts_item_viewed (user_id=? AND contact_id=?)
SEARCH f USING INDEX idx_files_chat_item_id (chat_item_id=?)
Query:
@@ -5572,7 +5572,7 @@ Query:
JOIN files f ON f.chat_item_id = i.chat_item_id
WHERE i.user_id = ? AND i.group_id = ?
Plan:
SEARCH i USING COVERING INDEX idx_chat_items_groups_has_link_item_ts (user_id=? AND group_id=?)
SEARCH i USING COVERING INDEX idx_chat_items_groups_item_viewed (user_id=? AND group_id=?)
SEARCH f USING INDEX idx_files_chat_item_id (chat_item_id=?)
Query:
@@ -6027,7 +6027,7 @@ SEARCH chat_item_versions USING COVERING INDEX idx_chat_item_versions_chat_item_
Query: DELETE FROM chat_items WHERE user_id = ? AND contact_id = ?
Plan:
SEARCH chat_items USING COVERING INDEX idx_chat_items_contacts_has_link_created_at (user_id=? AND contact_id=?)
SEARCH chat_items USING COVERING INDEX idx_chat_items_contacts_item_viewed (user_id=? AND contact_id=?)
SEARCH chat_item_mentions USING COVERING INDEX idx_chat_item_mentions_chat_item_id (chat_item_id=?)
SEARCH group_snd_item_statuses USING COVERING INDEX idx_group_snd_item_statuses_chat_item_id (chat_item_id=?)
SEARCH chat_item_versions USING COVERING INDEX idx_chat_item_versions_chat_item_id (chat_item_id=?)
@@ -6051,7 +6051,7 @@ SEARCH groups USING COVERING INDEX idx_groups_chat_item_id (chat_item_id=?)
Query: DELETE FROM chat_items WHERE user_id = ? AND contact_id = ? AND item_content_tag != 'chatBanner'
Plan:
SEARCH chat_items USING INDEX idx_chat_items_contacts_has_link_created_at (user_id=? AND contact_id=?)
SEARCH chat_items USING INDEX idx_chat_items_contacts_item_viewed (user_id=? AND contact_id=?)
SEARCH chat_item_mentions USING COVERING INDEX idx_chat_item_mentions_chat_item_id (chat_item_id=?)
SEARCH group_snd_item_statuses USING COVERING INDEX idx_group_snd_item_statuses_chat_item_id (chat_item_id=?)
SEARCH chat_item_versions USING COVERING INDEX idx_chat_item_versions_chat_item_id (chat_item_id=?)
@@ -6063,7 +6063,7 @@ SEARCH groups USING COVERING INDEX idx_groups_chat_item_id (chat_item_id=?)
Query: DELETE FROM chat_items WHERE user_id = ? AND group_id = ?
Plan:
SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_has_link_item_ts (user_id=? AND group_id=?)
SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_item_viewed (user_id=? AND group_id=?)
SEARCH chat_item_mentions USING COVERING INDEX idx_chat_item_mentions_chat_item_id (chat_item_id=?)
SEARCH group_snd_item_statuses USING COVERING INDEX idx_group_snd_item_statuses_chat_item_id (chat_item_id=?)
SEARCH chat_item_versions USING COVERING INDEX idx_chat_item_versions_chat_item_id (chat_item_id=?)
@@ -6087,7 +6087,7 @@ SEARCH groups USING COVERING INDEX idx_groups_chat_item_id (chat_item_id=?)
Query: DELETE FROM chat_items WHERE user_id = ? AND group_id = ? AND item_content_tag != 'chatBanner'
Plan:
SEARCH chat_items USING INDEX idx_chat_items_groups_has_link_item_ts (user_id=? AND group_id=?)
SEARCH chat_items USING INDEX idx_chat_items_groups_item_viewed (user_id=? AND group_id=?)
SEARCH chat_item_mentions USING COVERING INDEX idx_chat_item_mentions_chat_item_id (chat_item_id=?)
SEARCH group_snd_item_statuses USING COVERING INDEX idx_group_snd_item_statuses_chat_item_id (chat_item_id=?)
SEARCH chat_item_versions USING COVERING INDEX idx_chat_item_versions_chat_item_id (chat_item_id=?)
@@ -6390,7 +6390,7 @@ SEARCH protocol_servers USING COVERING INDEX idx_smp_servers_user_id (user_id=?)
SEARCH settings USING COVERING INDEX idx_settings_user_id (user_id=?)
SEARCH commands USING COVERING INDEX idx_commands_user_id (user_id=?)
SEARCH calls USING COVERING INDEX idx_calls_user_id (user_id=?)
SEARCH chat_items USING COVERING INDEX idx_chat_items_note_folder_has_link_created_at (user_id=?)
SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_item_viewed (user_id=?)
SEARCH contact_requests USING COVERING INDEX sqlite_autoindex_contact_requests_2 (user_id=?)
SEARCH user_contact_links USING COVERING INDEX sqlite_autoindex_user_contact_links_1 (user_id=?)
SEARCH connections USING COVERING INDEX idx_connections_to_subscribe (user_id=?)
@@ -6554,7 +6554,7 @@ Query: SELECT EXISTS (SELECT 1 FROM chat_items WHERE user_id = ? AND contact_id
Plan:
SCAN CONSTANT ROW
SCALAR SUBQUERY 1
SEARCH chat_items USING COVERING INDEX idx_chat_items_contacts_has_link_created_at (user_id=? AND contact_id=?)
SEARCH chat_items USING COVERING INDEX idx_chat_items_contacts_item_viewed (user_id=? AND contact_id=?)
Query: SELECT EXISTS (SELECT 1 FROM group_members WHERE group_id = ? AND member_id = ?)
Plan:
@@ -6588,14 +6588,14 @@ Query: SELECT chat_item_id FROM chat_items WHERE user_id = ? AND contact_id = ?
Plan:
SEARCH chat_items USING INDEX idx_chat_items_direct_shared_msg_id (user_id=? AND contact_id=? AND shared_msg_id=?)
Query: SELECT chat_item_id 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 != ? ORDER BY item_ts DESC, chat_item_id DESC LIMIT 1
Plan:
SEARCH chat_items USING INDEX idx_chat_items_group_scope_item_ts (user_id=? AND group_id=? AND group_scope_tag=? AND group_scope_group_member_id=?)
Query: SELECT chat_item_id 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 = ? ORDER BY item_ts ASC, chat_item_id ASC LIMIT 1
Plan:
SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_item_status (user_id=? AND group_id=? AND group_scope_tag=? AND group_scope_group_member_id=? AND item_status=?)
Query: SELECT chat_item_id 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_viewed = ? ORDER BY item_ts DESC, chat_item_id DESC LIMIT 1
Plan:
SEARCH chat_items USING INDEX idx_chat_items_groups_item_viewed (user_id=? AND group_id=? AND item_viewed=?)
Query: SELECT chat_item_id FROM chat_items WHERE user_id = ? AND group_id = ? AND group_member_id = ? LIMIT 1
Plan:
SEARCH chat_items USING COVERING INDEX idx_chat_items_group_shared_msg_id (user_id=? AND group_id=? AND group_member_id=?)
@@ -6820,6 +6820,10 @@ Query: SELECT xgrplinkmem_received FROM group_members WHERE group_member_id = ?
Plan:
SEARCH group_members USING INTEGER PRIMARY KEY (rowid=?)
Query: UPDATE chat_items SET item_status = ?, item_viewed = 1, updated_at = ? WHERE user_id = ? AND item_status = ?
Plan:
SEARCH chat_items USING INDEX idx_chat_items_user_id_item_status (user_id=? AND item_status=?)
Query: UPDATE chat_items SET item_status = ?, updated_at = ? WHERE user_id = ? AND contact_id = ? AND chat_item_id = ?
Plan:
SEARCH chat_items USING INTEGER PRIMARY KEY (rowid=?)
@@ -6828,10 +6832,6 @@ Query: UPDATE chat_items SET item_status = ?, updated_at = ? WHERE user_id = ? A
Plan:
SEARCH chat_items USING INTEGER PRIMARY KEY (rowid=?)
Query: UPDATE chat_items SET item_status = ?, updated_at = ? WHERE user_id = ? AND item_status = ?
Plan:
SEARCH chat_items USING INDEX idx_chat_items_user_id_item_status (user_id=? AND item_status=?)
Query: UPDATE chat_items SET timed_delete_at = ? WHERE user_id = ? AND contact_id = ? AND chat_item_id = ?
Plan:
SEARCH chat_items USING INTEGER PRIMARY KEY (rowid=?)
@@ -464,7 +464,8 @@ CREATE TABLE chat_items(
group_scope_group_member_id INTEGER REFERENCES group_members(group_member_id) ON DELETE CASCADE,
show_group_as_sender INTEGER NOT NULL DEFAULT 0,
has_link INTEGER NOT NULL DEFAULT 0,
msg_signed TEXT
msg_signed TEXT,
item_viewed INTEGER NOT NULL DEFAULT 0
) STRICT;
CREATE TABLE sqlite_sequence(name,seq);
CREATE TABLE chat_item_messages(
@@ -1278,6 +1279,18 @@ CREATE UNIQUE INDEX idx_group_relays_group_member_id ON group_relays(
group_member_id
);
CREATE INDEX idx_group_relays_chat_relay_id ON group_relays(chat_relay_id);
CREATE INDEX idx_chat_items_contacts_item_viewed ON chat_items(
user_id,
contact_id,
item_viewed,
created_at
);
CREATE INDEX idx_chat_items_groups_item_viewed ON chat_items(
user_id,
group_id,
item_viewed,
item_ts
);
CREATE TRIGGER on_group_members_insert_update_summary
AFTER INSERT ON group_members
FOR EACH ROW