From a968fd252ea68e5624fb405fecb11d1e06f31645 Mon Sep 17 00:00:00 2001 From: richjohnrambo Date: Wed, 23 Sep 2026 09:41:45 +0800 Subject: [PATCH] fix: use shared tables for tenant group members --- server/db/mysql/group_schema_test.go | 8 ++++---- server/db/mysql/tenant_groups.go | 10 +++++++--- server/db/mysql/tenant_tables.go | 6 +----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/server/db/mysql/group_schema_test.go b/server/db/mysql/group_schema_test.go index 5620393..09bad53 100644 --- a/server/db/mysql/group_schema_test.go +++ b/server/db/mysql/group_schema_test.go @@ -117,14 +117,14 @@ func TestTenantPartitionTableNames(t *testing.T) { func TestTenantShardSQL(t *testing.T) { query := tenantShardSQL(7, "SELECT * FROM im_topics t JOIN im_group_members gm ON gm.topic=t.name JOIN im_subscriptions s ON s.topic=gm.topic; INSERT INTO im_system_notifications(event_id) VALUES(?)") - for _, expected := range []string{"im_007_topics", "im_007_group_members", "im_007_subscriptions", "im_007_system_notifications"} { + for _, expected := range []string{"im_topics", "im_group_members", "im_subscriptions", "im_system_notifications"} { if !strings.Contains(query, expected) { - t.Fatalf("tenant shard query is missing %q: %s", expected, query) + t.Fatalf("shared tenant query is missing %q: %s", expected, query) } } - for _, legacy := range []string{" im_topics", " im_group_members", " im_subscriptions", " im_system_notifications"} { + for _, legacy := range []string{"im_007_topics", "im_007_group_members", "im_007_subscriptions", "im_007_system_notifications"} { if strings.Contains(query, legacy) { - t.Fatalf("tenant shard query still references %q: %s", legacy, query) + t.Fatalf("shared tenant query should not reference %q: %s", legacy, query) } } } diff --git a/server/db/mysql/tenant_groups.go b/server/db/mysql/tenant_groups.go index a70538f..6ec4c3e 100644 --- a/server/db/mysql/tenant_groups.go +++ b/server/db/mysql/tenant_groups.go @@ -23,6 +23,8 @@ const ( groupAnnouncementSelectColumnsBase = `id,announcement_id,topic,author_user_id,content,status,version,published_at,idempotency_key,created_at,updated_at, (SELECT COUNT(*) FROM im_group_announcement_reads AS ar WHERE ar.topic=im_group_announcements.topic AND ar.announcement_id=im_group_announcements.announcement_id) AS read_count, (SELECT COUNT(*) FROM im_group_members AS gm WHERE gm.topic=im_group_announcements.topic AND gm.member_status='active') AS member_count` + groupMemberSelectColumns = `id,topic,user_id,role,member_status,nickname,pinned,mute_notifications, + join_source,joined_by,joined_at,left_at,removed_by,version,created_at,updated_at` groupMuteSelectColumns = `topic,user_id,muted_by,muted_at,expires_at,reason,status,revoked_by,revoked_at,version,created_at,updated_at` ) @@ -300,7 +302,7 @@ func (a *adapter) TenantGroupMemberGet(id t.TenantID, topic string, uid t.Uid) ( if cancel != nil { defer cancel() } - return a.groupMemberByQuery(ctx, tenantShardSQL(id, "SELECT * FROM im_group_members WHERE tenant_id=? AND topic=? AND user_id=?"), id, topic, decodeUID(uid)) + return a.groupMemberByQuery(ctx, tenantShardSQL(id, "SELECT "+groupMemberSelectColumns+" FROM im_group_members WHERE tenant_id=? AND topic=? AND user_id=?"), id, topic, decodeUID(uid)) } func (a *adapter) TenantGroupMemberList(id t.TenantID, topic string, opts t.GroupMemberListOptions) ([]t.GroupMember, string, error) { @@ -347,7 +349,9 @@ func (a *adapter) TenantGroupMemberList(id t.TenantID, topic string, opts t.Grou if cancel != nil { defer cancel() } - rows, err := a.db.QueryxContext(ctx, tenantShardSQL(id, `SELECT STRAIGHT_JOIN gm.*,s.modewant,s.modegiven,u.trusted, + rows, err := a.db.QueryxContext(ctx, tenantShardSQL(id, `SELECT STRAIGHT_JOIN gm.id,gm.topic,gm.user_id,gm.role,gm.member_status,gm.nickname, + gm.pinned,gm.mute_notifications,gm.join_source,gm.joined_by,gm.joined_at,gm.left_at,gm.removed_by, + gm.version,gm.created_at,gm.updated_at,s.modewant,s.modegiven,u.trusted, p.nickname AS profile_nickname,p.avatar_file_id AS profile_avatar_file_id,p.signature AS profile_signature, p.gender AS profile_gender,p.region AS profile_region,p.public_account AS profile_public_account FROM im_group_members AS gm FORCE INDEX (`+memberIndex+`) @@ -457,7 +461,7 @@ func (a *adapter) TenantGroupMemberUpdate(id t.TenantID, topic string, uid t.Uid if err = tx.Commit(); err != nil { return nil, err } - return a.groupMemberByQuery(ctx, tenantShardSQL(id, "SELECT * FROM im_group_members WHERE tenant_id=? AND topic=? AND user_id=?"), id, topic, decodeUID(uid)) + return a.groupMemberByQuery(ctx, tenantShardSQL(id, "SELECT "+groupMemberSelectColumns+" FROM im_group_members WHERE tenant_id=? AND topic=? AND user_id=?"), id, topic, decodeUID(uid)) } func (a *adapter) TenantGroupInvitationCreate(id t.TenantID, inv *t.GroupInvitation) (*t.GroupInvitation, error) { diff --git a/server/db/mysql/tenant_tables.go b/server/db/mysql/tenant_tables.go index 4f1f0af..ab67567 100644 --- a/server/db/mysql/tenant_tables.go +++ b/server/db/mysql/tenant_tables.go @@ -5,16 +5,12 @@ package mysql import ( "fmt" - "strings" t "github.com/tinode/chat/server/store/types" ) func tenantShardSQL(tenantID t.TenantID, query string) string { - query = strings.ReplaceAll(query, "im_topics", tenantTopicsTable(tenantID)) - query = strings.ReplaceAll(query, "im_group_members", tenantGroupMembersTable(tenantID)) - query = strings.ReplaceAll(query, "im_subscriptions", tenantSubscriptionsTable(tenantID)) - return strings.ReplaceAll(query, "im_system_notifications", tenantSystemNotificationsTable(tenantID)) + return query } func tenantTablePrefix(tenantID t.TenantID) string {