mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-06-04 01:41:43 +00:00
directory: move all storage to the database, optimize performance (#6287)
* core: add custom indexed columns to groups and contacts * directory: use database (TODO search/listing) * triggers to maintain current member count * update simplexmq, fix tests, use summary from GroupInfo * fix all directory tests * remove acceptance fields from group reg * enable all tests * clean up * postgres migrations, fixes * query plans * use function in postgres triggers, improve sqlite query * fix export/import * update schema * prevent admins from promoting groups when approving * update listing every 5 minutes
This commit is contained in:
@@ -17,6 +17,7 @@ import Simplex.Chat.Store.Postgres.Migrations.M20250729_member_contact_requests
|
||||
import Simplex.Chat.Store.Postgres.Migrations.M20250801_via_group_link_uri
|
||||
import Simplex.Chat.Store.Postgres.Migrations.M20250802_chat_peer_type
|
||||
import Simplex.Chat.Store.Postgres.Migrations.M20250813_delivery_tasks
|
||||
import Simplex.Chat.Store.Postgres.Migrations.M20250919_group_summary
|
||||
import Simplex.Messaging.Agent.Store.Shared (Migration (..))
|
||||
|
||||
schemaMigrations :: [(String, Text, Maybe Text)]
|
||||
@@ -33,7 +34,8 @@ schemaMigrations =
|
||||
("20250729_member_contact_requests", m20250729_member_contact_requests, Just down_m20250729_member_contact_requests),
|
||||
("20250801_via_group_link_uri", m20250801_via_group_link_uri, Just down_m20250801_via_group_link_uri),
|
||||
("20250802_chat_peer_type", m20250802_chat_peer_type, Just down_m20250802_chat_peer_type),
|
||||
("20250813_delivery_tasks", m20250813_delivery_tasks, Just down_m20250813_delivery_tasks)
|
||||
("20250813_delivery_tasks", m20250813_delivery_tasks, Just down_m20250813_delivery_tasks),
|
||||
("20250919_group_summary", m20250919_group_summary, Just down_m20250919_group_summary)
|
||||
]
|
||||
|
||||
-- | The list of migrations in ascending order by date
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
|
||||
module Simplex.Chat.Store.Postgres.Migrations.M20250919_group_summary where
|
||||
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
import Text.RawString.QQ (r)
|
||||
|
||||
m20250919_group_summary :: Text
|
||||
m20250919_group_summary =
|
||||
T.pack
|
||||
[r|
|
||||
ALTER TABLE groups ADD COLUMN summary_current_members_count BIGINT NOT NULL DEFAULT 0;
|
||||
CREATE INDEX idx_groups_summary_current_members_count ON groups(summary_current_members_count);
|
||||
|
||||
CREATE FUNCTION is_current_member(p_status TEXT) RETURNS BOOLEAN
|
||||
LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
RETURN p_status IN (
|
||||
'introduced',
|
||||
'intro-inv',
|
||||
'accepted',
|
||||
'announced',
|
||||
'connected',
|
||||
'complete',
|
||||
'creator'
|
||||
);
|
||||
END;
|
||||
$$;
|
||||
|
||||
UPDATE groups g
|
||||
SET summary_current_members_count = COALESCE(c.cnt, 0)
|
||||
FROM (
|
||||
SELECT group_id, COUNT(group_member_id) AS cnt
|
||||
FROM group_members
|
||||
WHERE is_current_member(member_status) = TRUE
|
||||
GROUP BY group_id
|
||||
) c
|
||||
WHERE g.group_id = c.group_id;
|
||||
|
||||
CREATE FUNCTION on_group_members_insert_update_summary() RETURNS TRIGGER
|
||||
LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
IF is_current_member(NEW.member_status) THEN
|
||||
UPDATE groups
|
||||
SET summary_current_members_count = summary_current_members_count + 1
|
||||
WHERE group_id = NEW.group_id;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE FUNCTION on_group_members_delete_update_summary() RETURNS TRIGGER
|
||||
LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
IF is_current_member(OLD.member_status) THEN
|
||||
UPDATE groups
|
||||
SET summary_current_members_count = summary_current_members_count - 1
|
||||
WHERE group_id = OLD.group_id;
|
||||
END IF;
|
||||
RETURN OLD;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE FUNCTION on_group_members_update_update_summary() RETURNS TRIGGER
|
||||
LANGUAGE plpgsql AS $$
|
||||
DECLARE
|
||||
was_active BOOLEAN;
|
||||
is_active BOOLEAN;
|
||||
BEGIN
|
||||
was_active := is_current_member(OLD.member_status);
|
||||
is_active := is_current_member(NEW.member_status);
|
||||
|
||||
IF was_active != is_active THEN
|
||||
UPDATE groups
|
||||
SET summary_current_members_count = summary_current_members_count +
|
||||
(CASE WHEN is_active THEN 1 ELSE -1 END)
|
||||
WHERE group_id = NEW.group_id;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE TRIGGER tr_group_members_insert_update_summary
|
||||
AFTER INSERT ON group_members
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION on_group_members_insert_update_summary();
|
||||
|
||||
CREATE TRIGGER tr_group_members_delete_update_summary
|
||||
AFTER DELETE ON group_members
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION on_group_members_delete_update_summary();
|
||||
|
||||
CREATE TRIGGER tr_group_members_update_update_summary
|
||||
AFTER UPDATE ON group_members
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION on_group_members_update_update_summary();
|
||||
|]
|
||||
|
||||
down_m20250919_group_summary :: Text
|
||||
down_m20250919_group_summary =
|
||||
T.pack
|
||||
[r|
|
||||
DROP TRIGGER tr_group_members_insert_update_summary ON group_members;
|
||||
DROP TRIGGER tr_group_members_delete_update_summary ON group_members;
|
||||
DROP TRIGGER tr_group_members_update_update_summary ON group_members;
|
||||
|
||||
DROP FUNCTION on_group_members_insert_update_summary;
|
||||
DROP FUNCTION on_group_members_delete_update_summary;
|
||||
DROP FUNCTION on_group_members_update_update_summary;
|
||||
|
||||
DROP FUNCTION is_current_member;
|
||||
|
||||
DROP INDEX idx_groups_summary_current_members_count;
|
||||
ALTER TABLE groups DROP COLUMN summary_current_members_count;
|
||||
|]
|
||||
@@ -15,6 +15,76 @@ SET row_security = off;
|
||||
CREATE SCHEMA test_chat_schema;
|
||||
|
||||
|
||||
|
||||
CREATE FUNCTION test_chat_schema.is_current_member(p_status text) RETURNS boolean
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
RETURN p_status IN (
|
||||
'introduced',
|
||||
'intro-inv',
|
||||
'accepted',
|
||||
'announced',
|
||||
'connected',
|
||||
'complete',
|
||||
'creator'
|
||||
);
|
||||
END;
|
||||
$$;
|
||||
|
||||
|
||||
|
||||
CREATE FUNCTION test_chat_schema.on_group_members_delete_update_summary() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
IF is_current_member(OLD.member_status) THEN
|
||||
UPDATE groups
|
||||
SET summary_current_members_count = summary_current_members_count - 1
|
||||
WHERE group_id = OLD.group_id;
|
||||
END IF;
|
||||
RETURN OLD;
|
||||
END;
|
||||
$$;
|
||||
|
||||
|
||||
|
||||
CREATE FUNCTION test_chat_schema.on_group_members_insert_update_summary() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
IF is_current_member(NEW.member_status) THEN
|
||||
UPDATE groups
|
||||
SET summary_current_members_count = summary_current_members_count + 1
|
||||
WHERE group_id = NEW.group_id;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
|
||||
|
||||
CREATE FUNCTION test_chat_schema.on_group_members_update_update_summary() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
was_active BOOLEAN;
|
||||
is_active BOOLEAN;
|
||||
BEGIN
|
||||
was_active := is_current_member(OLD.member_status);
|
||||
is_active := is_current_member(NEW.member_status);
|
||||
|
||||
IF was_active != is_active THEN
|
||||
UPDATE groups
|
||||
SET summary_current_members_count = summary_current_members_count +
|
||||
(CASE WHEN is_active THEN 1 ELSE -1 END)
|
||||
WHERE group_id = NEW.group_id;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
|
||||
SET default_table_access_method = heap;
|
||||
|
||||
|
||||
@@ -716,7 +786,8 @@ CREATE TABLE test_chat_schema.groups (
|
||||
welcome_shared_msg_id bytea,
|
||||
request_shared_msg_id bytea,
|
||||
conn_link_prepared_connection smallint DEFAULT 0 NOT NULL,
|
||||
via_group_link_uri bytea
|
||||
via_group_link_uri bytea,
|
||||
summary_current_members_count bigint DEFAULT 0 NOT NULL
|
||||
);
|
||||
|
||||
|
||||
@@ -2064,6 +2135,10 @@ CREATE INDEX idx_groups_inv_queue_info ON test_chat_schema.groups USING btree (i
|
||||
|
||||
|
||||
|
||||
CREATE INDEX idx_groups_summary_current_members_count ON test_chat_schema.groups USING btree (summary_current_members_count);
|
||||
|
||||
|
||||
|
||||
CREATE INDEX idx_groups_via_group_link_uri_hash ON test_chat_schema.groups USING btree (user_id, via_group_link_uri_hash);
|
||||
|
||||
|
||||
@@ -2248,6 +2323,18 @@ CREATE INDEX note_folders_user_id ON test_chat_schema.note_folders USING btree (
|
||||
|
||||
|
||||
|
||||
CREATE TRIGGER tr_group_members_delete_update_summary AFTER DELETE ON test_chat_schema.group_members FOR EACH ROW EXECUTE FUNCTION test_chat_schema.on_group_members_delete_update_summary();
|
||||
|
||||
|
||||
|
||||
CREATE TRIGGER tr_group_members_insert_update_summary AFTER INSERT ON test_chat_schema.group_members FOR EACH ROW EXECUTE FUNCTION test_chat_schema.on_group_members_insert_update_summary();
|
||||
|
||||
|
||||
|
||||
CREATE TRIGGER tr_group_members_update_update_summary AFTER UPDATE ON test_chat_schema.group_members FOR EACH ROW EXECUTE FUNCTION test_chat_schema.on_group_members_update_update_summary();
|
||||
|
||||
|
||||
|
||||
ALTER TABLE ONLY test_chat_schema.calls
|
||||
ADD CONSTRAINT calls_chat_item_id_fkey FOREIGN KEY (chat_item_id) REFERENCES test_chat_schema.chat_items(chat_item_id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user