core: channel messages (#6604)

* core: channel messages (WIP)

* do not include member ID when quoting channel messages

* query plans

* reduce duplication

* refactor

* refactor plan

* refactor 2

* all tests

* remove plan

* refactor 3

* refactor 4

* refactor 5

* refactor 6

* plans

* plans to imrove test coverage and fix bugs

* update plan

* update plan

* bug fixes (wip)

* new plan

* fixes wip

* more tests

* comment, fix lint

* restore comment

* restore comments

* rename param

* move type

* simplify

* comment

* fix stale state

* refactor

* less diff

* simplify

* less diff

* refactor

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
This commit is contained in:
Evgeny
2026-02-12 07:11:59 +00:00
committed by GitHub
parent e29712c2e8
commit 628b00eb08
31 changed files with 3453 additions and 532 deletions
@@ -10,7 +10,7 @@ m20230511_reactions =
[sql|
CREATE TABLE chat_item_reactions (
chat_item_reaction_id INTEGER PRIMARY KEY AUTOINCREMENT,
item_member_id BLOB, -- member that created item, NULL for items in direct chats
item_member_id BLOB,
shared_msg_id BLOB NOT NULL,
contact_id INTEGER REFERENCES contacts ON DELETE CASCADE,
group_id INTEGER REFERENCES groups ON DELETE CASCADE,
@@ -5,7 +5,7 @@ module Simplex.Chat.Store.SQLite.Migrations.M20250813_delivery_tasks where
import Database.SQLite.Simple (Query)
import Database.SQLite.Simple.QQ (sql)
-- TODO [channels fwd] add later in new migration for MemberProfileUpdate delivery jobs:
-- TODO [relays] add later in new migration for MemberProfileUpdate delivery jobs:
-- TODO - ALTER TABLE group_members ADD COLUMN last_profile_delivery_ts TEXT;
-- TODO - ALTER TABLE group_members ADD COLUMN join_ts TEXT;
@@ -21,7 +21,7 @@ import Database.SQLite.Simple.QQ (sql)
-- delivery_tasks table:
-- - sender_group_member_id <-> GroupMemberId (sender of the original message that created task),
-- - message_id <-> MessageId (reference to the original message that created task),
-- - message_from_channel <-> Maybe MessageFromChannel (for MessageDeliveryTask),
-- - message_from_channel <-> ShowGroupAsSender (for MessageDeliveryTask),
-- - task_status <-> DeliveryTaskStatus,
-- - task_err_reason <-> Maybe Text (set when task status is DTSError, not encoded in status to allow filtering by DTSError in queries).
@@ -1105,7 +1105,7 @@ SEARCH chat_item_reactions USING INDEX idx_chat_item_reactions_contact (contact_
Query:
DELETE FROM chat_item_reactions
WHERE group_id = ? AND group_member_id = ? AND shared_msg_id = ? AND item_member_id = ? AND reaction_sent = ? AND reaction = ?
WHERE group_id = ? AND group_member_id = ? AND shared_msg_id = ? AND item_member_id IS NOT DISTINCT FROM ? AND reaction_sent = ? AND reaction = ?
Plan:
SEARCH chat_item_reactions USING INDEX idx_chat_item_reactions_group (group_id=? AND shared_msg_id=?)
@@ -1406,7 +1406,7 @@ SEARCH ct USING INTEGER PRIMARY KEY (rowid=?)
Query:
SELECT chat_item_id
FROM chat_items
WHERE user_id = ? AND group_id = ? AND group_member_id = ? AND shared_msg_id = ?
WHERE user_id = ? AND group_id = ? AND group_member_id IS NOT DISTINCT FROM ? AND shared_msg_id = ?
ORDER BY chat_item_id DESC
LIMIT 1
@@ -1611,11 +1611,12 @@ Query:
SELECT r.file_status, r.file_queue_info, r.group_member_id, f.file_name,
f.file_size, f.chunk_size, f.cancelled, cs.local_display_name, m.local_display_name,
f.file_path, f.file_crypto_key, f.file_crypto_nonce, r.file_inline, r.rcv_file_inline,
r.agent_rcv_file_id, r.agent_rcv_file_deleted, r.user_approved_relays
r.agent_rcv_file_id, r.agent_rcv_file_deleted, r.user_approved_relays, g.local_display_name
FROM rcv_files r
JOIN files f USING (file_id)
LEFT JOIN contacts cs ON cs.contact_id = f.contact_id
LEFT JOIN group_members m ON m.group_member_id = r.group_member_id
LEFT JOIN groups g ON g.group_id = f.group_id
WHERE f.user_id = ? AND f.file_id = ?
Plan:
@@ -1623,6 +1624,7 @@ SEARCH f USING INTEGER PRIMARY KEY (rowid=?)
SEARCH r USING INTEGER PRIMARY KEY (rowid=?)
SEARCH cs USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
SEARCH m USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
SEARCH g USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
Query:
SELECT r.probe, r.contact_id, g.group_id, r.group_member_id
@@ -3700,7 +3702,7 @@ SEARCH chat_item_reactions USING INDEX idx_chat_item_reactions_contact (contact_
Query:
SELECT reaction
FROM chat_item_reactions
WHERE group_id = ? AND group_member_id = ? AND item_member_id = ? AND shared_msg_id = ? AND reaction_sent = ?
WHERE group_id = ? AND group_member_id = ? AND item_member_id IS NOT DISTINCT FROM ? AND shared_msg_id = ? AND reaction_sent = ?
Plan:
SEARCH chat_item_reactions USING INDEX idx_chat_item_reactions_group (group_id=? AND shared_msg_id=?)
@@ -3718,7 +3720,7 @@ USE TEMP B-TREE FOR GROUP BY
Query:
SELECT reaction, MAX(reaction_sent), COUNT(chat_item_reaction_id)
FROM chat_item_reactions
WHERE group_id = ? AND item_member_id = ? AND shared_msg_id = ?
WHERE group_id = ? AND item_member_id IS NOT DISTINCT FROM ? AND shared_msg_id = ?
GROUP BY reaction
Plan:
@@ -5885,7 +5887,7 @@ Query: DELETE FROM chat_item_reactions WHERE group_id = ?
Plan:
SEARCH chat_item_reactions USING COVERING INDEX idx_chat_item_reactions_group_id (group_id=?)
Query: DELETE FROM chat_item_reactions WHERE group_id = ? AND shared_msg_id = ? AND item_member_id = ?
Query: DELETE FROM chat_item_reactions WHERE group_id = ? AND shared_msg_id = ? AND item_member_id IS NOT DISTINCT FROM ?
Plan:
SEARCH chat_item_reactions USING INDEX idx_chat_item_reactions_group (group_id=? AND shared_msg_id=?)
@@ -541,7 +541,7 @@ CREATE TABLE chat_item_versions(
) STRICT;
CREATE TABLE chat_item_reactions(
chat_item_reaction_id INTEGER PRIMARY KEY AUTOINCREMENT,
item_member_id BLOB, -- member that created item, NULL for items in direct chats
item_member_id BLOB,
shared_msg_id BLOB NOT NULL,
contact_id INTEGER REFERENCES contacts ON DELETE CASCADE,
group_id INTEGER REFERENCES groups ON DELETE CASCADE,