internal/store/postgres/channel_member_index_plan_integration_test.go
Rama main · réplica de lectura del repositorio original.
package postgres
import (
"context"
"strings"
"testing"
"telesrv/internal/domain"
)
func TestChannelMemberIndexListPathPlansUseUserIndex(t *testing.T) {
pool := testPool(t)
ctx := context.Background()
suffix := randomSuffix(t)
users := NewUserStore(pool)
owner := createTestUser(t, ctx, users, "+1887"+suffix+"61", "PlanIndexOwner", "")
member := createTestUser(t, ctx, users, "+1887"+suffix+"62", "PlanIndexMember", "")
var channelIDs []int64
t.Cleanup(func() {
if len(channelIDs) != 0 {
_, _ = pool.Exec(ctx, "DELETE FROM channels WHERE id = ANY($1::bigint[])", channelIDs)
}
_, _ = pool.Exec(ctx, "DELETE FROM users WHERE id = ANY($1::bigint[])", []int64{owner.ID, member.ID})
})
channels := NewChannelStore(pool)
publicAdmined, err := channels.CreateChannel(ctx, domain.CreateChannelRequest{
CreatorUserID: owner.ID,
Title: "plan admined " + suffix,
Megagroup: true,
Date: 1700000850,
})
if err != nil {
t.Fatalf("create public admined: %v", err)
}
channelIDs = append(channelIDs, publicAdmined.Channel.ID)
publicUsername := "planadmined" + suffix
if _, err := channels.UpdateUsername(ctx, domain.UpdateChannelUsernameRequest{
UserID: owner.ID,
ChannelID: publicAdmined.Channel.ID,
Username: publicUsername,
}); err != nil {
t.Fatalf("set public username: %v", err)
}
left, err := channels.CreateChannel(ctx, domain.CreateChannelRequest{
CreatorUserID: owner.ID,
Title: "plan left " + suffix,
Megagroup: true,
MemberUserIDs: []int64{member.ID},
Date: 1700000851,
})
if err != nil {
t.Fatalf("create left: %v", err)
}
channelIDs = append(channelIDs, left.Channel.ID)
if _, err := channels.LeaveChannel(ctx, left.Channel.ID, member.ID, 1700000852); err != nil {
t.Fatalf("leave channel: %v", err)
}
discussion, err := channels.CreateChannel(ctx, domain.CreateChannelRequest{
CreatorUserID: owner.ID,
Title: "plan discussion " + suffix,
Megagroup: true,
MemberUserIDs: []int64{member.ID},
Date: 1700000853,
})
if err != nil {
t.Fatalf("create discussion: %v", err)
}
channelIDs = append(channelIDs, discussion.Channel.ID)
if _, err := channels.EditChannelAdmin(ctx, domain.EditChannelAdminRequest{
UserID: owner.ID,
ChannelID: discussion.Channel.ID,
MemberID: member.ID,
AdminRights: domain.ChannelAdminRights{
PinMessages: true,
},
Date: 1700000854,
}); err != nil {
t.Fatalf("grant discussion admin: %v", err)
}
tx, err := pool.Begin(ctx)
if err != nil {
t.Fatalf("begin explain tx: %v", err)
}
defer func() { _ = tx.Rollback(ctx) }()
if _, err := tx.Exec(ctx, "SET LOCAL enable_seqscan = off"); err != nil {
t.Fatalf("disable seqscan: %v", err)
}
leftPlan := explainText(t, ctx, tx, `
SELECT channel_id
FROM user_channel_member_index
WHERE user_id = $1
AND status = 'left'
AND (broadcast OR megagroup)
AND NOT deleted
ORDER BY left_at DESC, channel_id DESC
OFFSET $2
LIMIT $3
`, member.ID, 0, domain.MaxLeftChannelsLimit)
requirePlanContains(t, leftPlan, "user_channel_member_index_left_idx")
requirePlanNotContains(t, leftPlan, "channel_members_p")
leftDetailPlan := explainText(t, ctx, tx, `
SELECT channel_id
FROM channel_members
WHERE user_id = $1
AND channel_id = ANY($2::bigint[])
AND status = 'left'
`, member.ID, []int64{left.Channel.ID})
requireUniquePartitionCountAtMost(t, leftDetailPlan, `channel_members_p\d+`, 1)
channelDetailPlan := explainText(t, ctx, tx, `
SELECT id
FROM channels
WHERE id = ANY($1::bigint[])
AND NOT deleted
`, []int64{left.Channel.ID})
requireUniquePartitionCountAtMost(t, channelDetailPlan, `channels_p\d+`, 1)
usernameLookupPlan := explainText(t, ctx, tx, `
SELECT peer_id
FROM peer_usernames
WHERE username_lower = $1 AND peer_type = 'channel'
`, publicUsername)
// 0150 adds peer_usernames_peer_order_idx, which covers this lookup as an
// index-only scan; either index is an acceptable plan, a partition scan is not.
if !strings.Contains(usernameLookupPlan, "peer_usernames_pkey") &&
!strings.Contains(usernameLookupPlan, "peer_usernames_peer_order_idx") {
t.Fatalf("username lookup plan = %s, want a peer_usernames index scan", usernameLookupPlan)
}
requirePlanNotMatches(t, usernameLookupPlan, `channels_p\d+`)
usernameChannelDetailPlan := explainText(t, ctx, tx, `
SELECT id
FROM channels c
WHERE c.id = $1
AND NOT c.deleted
`, publicAdmined.Channel.ID)
requireUniquePartitionCountAtMost(t, usernameChannelDetailPlan, `channels_p\d+`, 1)
requirePlanNotContains(t, usernameChannelDetailPlan, "Append")
adminedPlan := explainText(t, ctx, tx, `
SELECT channel_id
FROM user_channel_member_index
WHERE user_id = $1
AND status = 'active'
AND role IN ('creator','admin')
AND public_username
AND NOT deleted
ORDER BY channel_id DESC
LIMIT $2
`, owner.ID, domain.MaxAdminedPublicChannels)
requirePlanContains(t, adminedPlan, "user_channel_member_index_admined_public_idx")
requirePlanNotContains(t, adminedPlan, "channel_members_p")
discussionPlan := explainText(t, ctx, tx, `
SELECT channel_id
FROM user_channel_member_index
WHERE user_id = $1
AND status = 'active'
AND megagroup
AND NOT broadcast
AND NOT forum
AND NOT deleted
AND (role = 'creator' OR can_pin_messages)
ORDER BY channel_id DESC
LIMIT $2
`, member.ID, domain.MaxDiscussionGroupsLimit)
requirePlanContains(t, discussionPlan, "user_channel_member_index_discussion_idx")
requirePlanNotContains(t, discussionPlan, "channel_members_p")
dialogCandidatePlan := explainText(t, ctx, tx, `
SELECT channel_id
FROM user_channel_member_index
WHERE user_id = $1
AND status = 'active'
AND NOT deleted
ORDER BY channel_id ASC
LIMIT $2
`, owner.ID, channelDialogCandidateLimit)
requirePlanContains(t, dialogCandidatePlan, "user_channel_member_index")
requirePlanNotContains(t, dialogCandidatePlan, "channel_members_p")
dialogDetailPlan := explainText(t, ctx, tx, `
SELECT c.id,
CASE WHEN c.top_message_id > m.available_min_id THEN c.top_message_id ELSE 0 END AS visible_top_id,
CASE WHEN c.top_message_id > m.available_min_id THEN COALESCE(top_msg.message_date, d.top_message_date, c.date) ELSE 0 END AS visible_top_date
FROM channel_members m
JOIN channels c ON c.id = m.channel_id AND c.id = ANY($2::bigint[]) AND NOT c.deleted
LEFT JOIN channel_messages top_msg ON top_msg.channel_id = m.channel_id AND top_msg.channel_id = ANY($2::bigint[]) AND top_msg.id = c.top_message_id AND NOT top_msg.deleted
LEFT JOIN channel_dialogs d ON d.user_id = m.user_id AND d.channel_id = m.channel_id
WHERE m.user_id = $1
AND m.channel_id = ANY($2::bigint[])
AND m.status = 'active'
ORDER BY visible_top_date DESC,
visible_top_id DESC,
c.id DESC
LIMIT $3
`, owner.ID, []int64{publicAdmined.Channel.ID}, channelDialogQueryLimit)
requireUniquePartitionCountAtMost(t, dialogDetailPlan, `channel_members_p\d+`, 1)
requireUniquePartitionCountAtMost(t, dialogDetailPlan, `channels_p\d+`, 1)
requireUniquePartitionCountAtMost(t, dialogDetailPlan, `channel_messages_p\d+`, 1)
inactiveCandidatePlan := explainText(t, ctx, tx, `
SELECT channel_id
FROM user_channel_member_index
WHERE user_id = $1
AND status = 'active'
AND (broadcast OR megagroup)
AND NOT deleted
ORDER BY channel_id ASC
LIMIT $2
`, owner.ID, channelDialogCandidateLimit)
requirePlanContains(t, inactiveCandidatePlan, "user_channel_member_index")
requirePlanNotContains(t, inactiveCandidatePlan, "channel_members_p")
inactiveDetailPlan := explainText(t, ctx, tx, `
SELECT c.id,
CASE WHEN c.top_message_id > m.available_min_id THEN c.top_message_id ELSE 0 END AS visible_top_id,
CASE WHEN c.top_message_id > m.available_min_id THEN COALESCE(top_msg.message_date, d.top_message_date, c.date) ELSE GREATEST(c.date, m.joined_at) END AS visible_top_date
FROM channel_members m
JOIN channels c ON c.id = m.channel_id AND c.id = ANY($2::bigint[]) AND NOT c.deleted
LEFT JOIN channel_messages top_msg ON top_msg.channel_id = m.channel_id AND top_msg.channel_id = ANY($2::bigint[]) AND top_msg.id = c.top_message_id AND NOT top_msg.deleted
LEFT JOIN channel_dialogs d ON d.user_id = m.user_id AND d.channel_id = m.channel_id
WHERE m.user_id = $1
AND m.channel_id = ANY($2::bigint[])
AND m.status = 'active'
AND (c.broadcast OR c.megagroup)
ORDER BY visible_top_date ASC,
visible_top_id ASC,
c.id ASC
LIMIT $3
`, owner.ID, []int64{publicAdmined.Channel.ID}, domain.MaxInactiveChannelsLimit)
requireUniquePartitionCountAtMost(t, inactiveDetailPlan, `channel_members_p\d+`, 1)
requireUniquePartitionCountAtMost(t, inactiveDetailPlan, `channels_p\d+`, 1)
requireUniquePartitionCountAtMost(t, inactiveDetailPlan, `channel_messages_p\d+`, 1)
mentionAffectedPlan := explainText(t, ctx, tx, `
SELECT DISTINCT user_id
FROM channel_unread_mention_index
WHERE channel_id = $1
AND message_id = ANY($2::int[])
ORDER BY user_id ASC
`, publicAdmined.Channel.ID, []int32{1, 2})
requirePlanContains(t, mentionAffectedPlan, "Index")
requireUniquePartitionCountAtMost(t, mentionAffectedPlan, `channel_unread_mention_index_p\d+`, 1)
requirePlanNotMatches(t, mentionAffectedPlan, `channel_unread_mentions_p\d+`)
mentionDeleteBatchPlan := explainText(t, ctx, tx, `
WITH affected AS (
SELECT DISTINCT unnest($3::bigint[]) AS user_id
),
deleted_mentions AS (
DELETE FROM channel_unread_mentions um
USING affected a
WHERE um.user_id = ANY($3::bigint[])
AND um.user_id = a.user_id
AND um.channel_id = $1
AND um.message_id = ANY($2::int[])
RETURNING um.user_id, um.channel_id, um.message_id
),
deleted_index AS (
DELETE FROM channel_unread_mention_index i
USING affected a
WHERE i.channel_id = $1
AND i.user_id = a.user_id
AND i.message_id = ANY($2::int[])
),
counts_before AS (
SELECT user_id, COUNT(*)::int AS count
FROM channel_unread_mentions
WHERE channel_id = $1
AND user_id = ANY($3::bigint[])
GROUP BY user_id
),
deleted_counts AS (
SELECT user_id, COUNT(*)::int AS count
FROM deleted_mentions
GROUP BY user_id
)
UPDATE channel_dialogs d
SET unread_mentions_count = GREATEST(COALESCE(c.count, 0) - COALESCE(dc.count, 0), 0),
updated_at = now()
FROM affected a
LEFT JOIN counts_before c ON c.user_id = a.user_id
LEFT JOIN deleted_counts dc ON dc.user_id = a.user_id
WHERE d.user_id = ANY($3::bigint[])
AND d.channel_id = $1
AND d.user_id = a.user_id
`, publicAdmined.Channel.ID, []int32{1, 2}, []int64{member.ID})
requireUniquePartitionCountAtMost(t, mentionDeleteBatchPlan, `channel_unread_mentions_p\d+`, 1)
requireUniquePartitionCountAtMost(t, mentionDeleteBatchPlan, `channel_dialogs_p\d+`, 1)
requireUniquePartitionCountAtMost(t, mentionDeleteBatchPlan, `channel_unread_mention_index_p\d+`, 1)
}