feat: 新增群组成员数量统计功能并在接口中返回

实现了群组成员数量统计的接口,包含数据库层统计逻辑,在群组详情、设置等接口中返回实时成员数,同时修复了测试用例中参数空格问题。
This commit is contained in:
Austin
2026-10-13 17:58:05 +08:00
parent 43808c36d1
commit e8804883fc
7 changed files with 120 additions and 14 deletions
+1
View File
@@ -405,6 +405,7 @@ type TenantBusinessAdapter interface {
TenantGroupMemberUpsert(t.TenantID, *t.GroupMember) (*t.GroupMember, error)
TenantGroupMemberGet(t.TenantID, string, t.Uid) (*t.GroupMember, error)
TenantGroupMemberList(t.TenantID, string, t.GroupMemberListOptions) ([]t.GroupMember, string, error)
TenantGroupMembersCount(t.TenantID, []string) (map[string]int64, error)
TenantGroupMemberUpdate(t.TenantID, string, t.Uid, t.GroupMemberPatch) (*t.GroupMember, error)
TenantUsersShareOpenPrivateGroup(t.TenantID, t.Uid, t.Uid) (bool, error)
TenantGroupInvitationCreate(t.TenantID, *t.GroupInvitation) (*t.GroupInvitation, error)
+44
View File
@@ -394,6 +394,50 @@ func (a *adapter) TenantGroupMemberList(id t.TenantID, topic string, opts t.Grou
return items, next, rows.Err()
}
// TenantGroupMembersCount counts active members for the given topics using the
// same visibility rules as TenantGroupMemberList: membership active, subscription
// not deleted, user not deleted. Returns counts keyed by topic; topics with no
// active members are absent from the map.
func (a *adapter) TenantGroupMembersCount(id t.TenantID, topics []string) (map[string]int64, error) {
if tenantAdp, err := a.routeGroupTenant(id); err != nil {
return nil, err
} else if tenantAdp != a {
return tenantAdp.TenantGroupMembersCount(id, topics)
}
if len(topics) == 0 {
return map[string]int64{}, nil
}
placeholders := strings.TrimSuffix(strings.Repeat("?,", len(topics)), ",")
args := make([]any, 0, len(topics)+3)
args = append(args, t.StateDeleted, id, t.GroupMemberStatusActive)
for _, topic := range topics {
args = append(args, topic)
}
ctx, cancel := a.getContext()
if cancel != nil {
defer cancel()
}
rows, err := a.db.QueryContext(ctx, tenantShardSQL(id, `SELECT gm.topic, COUNT(DISTINCT gm.user_id) FROM im_group_members AS gm
JOIN im_subscriptions AS s ON s.tenant_id=gm.tenant_id AND s.topic=gm.topic AND s.userid=gm.user_id AND s.deletedat IS NULL
JOIN im_users AS u ON u.tenant_id=gm.tenant_id AND u.id=gm.user_id AND u.state!=?
WHERE gm.tenant_id=? AND gm.member_status=? AND gm.topic IN (`+placeholders+`)
GROUP BY gm.topic`), args...)
if err != nil {
return nil, err
}
defer rows.Close()
counts := make(map[string]int64, len(topics))
for rows.Next() {
var topic string
var count int64
if err = rows.Scan(&topic, &count); err != nil {
return nil, err
}
counts[topic] = count
}
return counts, rows.Err()
}
func (a *adapter) TenantUsersShareOpenPrivateGroup(id t.TenantID, userID, peerID t.Uid) (bool, error) {
if tenantAdp, err := a.routeGroupTenant(id); err != nil {
return false, err