Files
multica/server/pkg/db/generated/member.sql.go
d3c1b44d75 MUL-8014: fix(realtime): revoke workspace WebSocket access (#9249)
* fix(realtime): revoke workspace access on membership removal

Close removed members' sockets, revalidate registration, and gate captured write batches with fresh coalesced membership queries. Cover relay failure, replay, queue races, and transactional removal/rollback (MUL-8014).

Co-authored-by: multica-agent <[email protected]>

* fix(realtime): keep registration free of database waits

Co-authored-by: multica-agent <[email protected]>

* perf(realtime): narrow removal event prefilter

Co-authored-by: multica-agent <[email protected]>

* test(wakeup): avoid global backfill in workspace default test

Co-authored-by: multica-agent <[email protected]>

* fix(realtime): bound concurrent authorization and defer relay revocation

Co-authored-by: multica-agent <[email protected]>

* test(realtime): check caller budget without waiting for expiry

Co-authored-by: multica-agent <[email protected]>

* fix(realtime): decouple member-list invalidation from revocation

Co-authored-by: multica-agent <[email protected]>

* perf(realtime): skip removal decoding for member actor metadata

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: Sol-Boy <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-15 12:36:00 +08:00

259 lines
6.3 KiB
Go

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: member.sql
package db
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const createMember = `-- name: CreateMember :one
INSERT INTO member (workspace_id, user_id, role)
VALUES ($1, $2, $3)
RETURNING id, workspace_id, user_id, role, created_at
`
type CreateMemberParams struct {
WorkspaceID pgtype.UUID `json:"workspace_id"`
UserID pgtype.UUID `json:"user_id"`
Role string `json:"role"`
}
func (q *Queries) CreateMember(ctx context.Context, arg CreateMemberParams) (Member, error) {
row := q.db.QueryRow(ctx, createMember, arg.WorkspaceID, arg.UserID, arg.Role)
var i Member
err := row.Scan(
&i.ID,
&i.WorkspaceID,
&i.UserID,
&i.Role,
&i.CreatedAt,
)
return i, err
}
const deleteMember = `-- name: DeleteMember :exec
DELETE FROM member WHERE id = $1
`
func (q *Queries) DeleteMember(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, deleteMember, id)
return err
}
const getMember = `-- name: GetMember :one
SELECT id, workspace_id, user_id, role, created_at FROM member
WHERE id = $1
`
func (q *Queries) GetMember(ctx context.Context, id pgtype.UUID) (Member, error) {
row := q.db.QueryRow(ctx, getMember, id)
var i Member
err := row.Scan(
&i.ID,
&i.WorkspaceID,
&i.UserID,
&i.Role,
&i.CreatedAt,
)
return i, err
}
const getMemberByUserAndWorkspace = `-- name: GetMemberByUserAndWorkspace :one
SELECT id, workspace_id, user_id, role, created_at FROM member
WHERE user_id = $1 AND workspace_id = $2
`
type GetMemberByUserAndWorkspaceParams struct {
UserID pgtype.UUID `json:"user_id"`
WorkspaceID pgtype.UUID `json:"workspace_id"`
}
func (q *Queries) GetMemberByUserAndWorkspace(ctx context.Context, arg GetMemberByUserAndWorkspaceParams) (Member, error) {
row := q.db.QueryRow(ctx, getMemberByUserAndWorkspace, arg.UserID, arg.WorkspaceID)
var i Member
err := row.Scan(
&i.ID,
&i.WorkspaceID,
&i.UserID,
&i.Role,
&i.CreatedAt,
)
return i, err
}
const getRealtimeMemberships = `-- name: GetRealtimeMemberships :many
SELECT m.user_id, m.workspace_id
FROM member m
JOIN (
SELECT unnest($1::uuid[]) AS user_id,
unnest($2::uuid[]) AS workspace_id
) AS requested
ON m.user_id = requested.user_id AND m.workspace_id = requested.workspace_id
`
type GetRealtimeMembershipsParams struct {
UserIds []pgtype.UUID `json:"user_ids"`
WorkspaceIds []pgtype.UUID `json:"workspace_ids"`
}
type GetRealtimeMembershipsRow struct {
UserID pgtype.UUID `json:"user_id"`
WorkspaceID pgtype.UUID `json:"workspace_id"`
}
func (q *Queries) GetRealtimeMemberships(ctx context.Context, arg GetRealtimeMembershipsParams) ([]GetRealtimeMembershipsRow, error) {
rows, err := q.db.Query(ctx, getRealtimeMemberships, arg.UserIds, arg.WorkspaceIds)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetRealtimeMembershipsRow{}
for rows.Next() {
var i GetRealtimeMembershipsRow
if err := rows.Scan(&i.UserID, &i.WorkspaceID); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listMembers = `-- name: ListMembers :many
SELECT id, workspace_id, user_id, role, created_at FROM member
WHERE workspace_id = $1
ORDER BY created_at ASC
`
func (q *Queries) ListMembers(ctx context.Context, workspaceID pgtype.UUID) ([]Member, error) {
rows, err := q.db.Query(ctx, listMembers, workspaceID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []Member{}
for rows.Next() {
var i Member
if err := rows.Scan(
&i.ID,
&i.WorkspaceID,
&i.UserID,
&i.Role,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listMembersWithUser = `-- name: ListMembersWithUser :many
SELECT m.id, m.workspace_id, m.user_id, m.role, m.created_at,
u.name as user_name, u.email as user_email, u.avatar_url as user_avatar_url
FROM member m
JOIN "user" u ON u.id = m.user_id
WHERE m.workspace_id = $1
ORDER BY m.created_at ASC
`
type ListMembersWithUserRow struct {
ID pgtype.UUID `json:"id"`
WorkspaceID pgtype.UUID `json:"workspace_id"`
UserID pgtype.UUID `json:"user_id"`
Role string `json:"role"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UserName string `json:"user_name"`
UserEmail string `json:"user_email"`
UserAvatarUrl pgtype.Text `json:"user_avatar_url"`
}
func (q *Queries) ListMembersWithUser(ctx context.Context, workspaceID pgtype.UUID) ([]ListMembersWithUserRow, error) {
rows, err := q.db.Query(ctx, listMembersWithUser, workspaceID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListMembersWithUserRow{}
for rows.Next() {
var i ListMembersWithUserRow
if err := rows.Scan(
&i.ID,
&i.WorkspaceID,
&i.UserID,
&i.Role,
&i.CreatedAt,
&i.UserName,
&i.UserEmail,
&i.UserAvatarUrl,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listWorkspaceManagerUserIDs = `-- name: ListWorkspaceManagerUserIDs :many
SELECT user_id FROM member
WHERE workspace_id = $1 AND role IN ('owner', 'admin')
ORDER BY created_at ASC
`
func (q *Queries) ListWorkspaceManagerUserIDs(ctx context.Context, workspaceID pgtype.UUID) ([]pgtype.UUID, error) {
rows, err := q.db.Query(ctx, listWorkspaceManagerUserIDs, workspaceID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []pgtype.UUID{}
for rows.Next() {
var user_id pgtype.UUID
if err := rows.Scan(&user_id); err != nil {
return nil, err
}
items = append(items, user_id)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateMemberRole = `-- name: UpdateMemberRole :one
UPDATE member SET role = $2
WHERE id = $1
RETURNING id, workspace_id, user_id, role, created_at
`
type UpdateMemberRoleParams struct {
ID pgtype.UUID `json:"id"`
Role string `json:"role"`
}
func (q *Queries) UpdateMemberRole(ctx context.Context, arg UpdateMemberRoleParams) (Member, error) {
row := q.db.QueryRow(ctx, updateMemberRole, arg.ID, arg.Role)
var i Member
err := row.Scan(
&i.ID,
&i.WorkspaceID,
&i.UserID,
&i.Role,
&i.CreatedAt,
)
return i, err
}