mirror of
https://github.com/djdevin/recflare.git
synced 2026-10-28 00:18:58 -07:00
[rooms] fix slow room role query
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
-- Index a room's `Roles` by account, so "rooms this account has a role in"
|
||||
-- (`getContributedRooms`) is a lookup instead of a scan.
|
||||
--
|
||||
-- Roles live in the room blob, and the only way to ask "which rooms name account N" of
|
||||
-- the blob is a `json_each` over every room's `$.Roles`: the whole table, every blob
|
||||
-- parsed, on every call. `room_role` is a DERIVED copy of those entries, one row per
|
||||
-- (account, room). The blob stays the source of truth; every write in
|
||||
-- `packages/domain/src/rooms-db.ts` that changes `Roles` batches `roomRoleWrites` with it.
|
||||
--
|
||||
-- Every entry with an `AccountId` counts, pending invites (`InvitedRole` only) included,
|
||||
-- which is exactly what the json_each query matched.
|
||||
|
||||
CREATE TABLE IF NOT EXISTS room_role (
|
||||
account_id INTEGER NOT NULL,
|
||||
room_id INTEGER NOT NULL,
|
||||
PRIMARY KEY (account_id, room_id)
|
||||
) WITHOUT ROWID;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_room_role_room ON room_role (room_id);
|
||||
|
||||
-- Backfill from the rooms already stored. A full rebuild rather than an append, so this can
|
||||
-- be re-run as-is to catch role changes made by the old code between migrating and deploying.
|
||||
-- Non-object entries are skipped through a CASE rather than handed to json_extract, which
|
||||
-- raises on a bare string.
|
||||
DELETE FROM room_role;
|
||||
INSERT OR IGNORE INTO room_role (account_id, room_id)
|
||||
SELECT account_id, room_id FROM (
|
||||
SELECT CASE WHEN role.type = 'object' THEN json_extract(role.value, '$.AccountId') END AS account_id,
|
||||
room.room_id AS room_id
|
||||
FROM room, json_each(room.data, '$.Roles') AS role
|
||||
) WHERE account_id > 0 AND room_id IS NOT NULL;
|
||||
@@ -0,0 +1,46 @@
|
||||
-- Give `room_role` the whole role entry, not just which account a room names.
|
||||
--
|
||||
-- 0029 stored (account_id, room_id) alone, which is all `getContributedRooms` asks of it.
|
||||
-- A table of a room's roles should carry the roles themselves, though: each row now mirrors
|
||||
-- one `Roles` entry from the room blob, so a query that cares about the tier (managers only,
|
||||
-- pending invites) can filter on it here instead of going back to `json_each` over every
|
||||
-- room. The blob is still the source of truth, and `roomRoleWrites` still rewrites a room's
|
||||
-- rows alongside every write that changes `Roles`.
|
||||
--
|
||||
-- Columns follow `roomRoles()`, which fills in what older entries lack: `role` and
|
||||
-- `invited_role` default to 0 (Role.None), `last_changed_by_account_id` to null.
|
||||
--
|
||||
-- Nothing reads the table until the worker deploys, so it is rebuilt rather than altered.
|
||||
-- The triggers are dropped in case an early draft of 0029 created them; they are not used.
|
||||
|
||||
DROP TRIGGER IF EXISTS room_role_insert;
|
||||
DROP TRIGGER IF EXISTS room_role_update;
|
||||
DROP TRIGGER IF EXISTS room_role_delete;
|
||||
DROP TABLE IF EXISTS room_role;
|
||||
|
||||
CREATE TABLE room_role (
|
||||
account_id INTEGER NOT NULL,
|
||||
room_id INTEGER NOT NULL,
|
||||
role INTEGER NOT NULL DEFAULT 0,
|
||||
invited_role INTEGER NOT NULL DEFAULT 0,
|
||||
last_changed_by_account_id INTEGER,
|
||||
PRIMARY KEY (account_id, room_id)
|
||||
) WITHOUT ROWID;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_room_role_room ON room_role (room_id);
|
||||
|
||||
-- Backfill from the rooms already stored. Like 0029's, it is a full rebuild, so it can be
|
||||
-- re-run as-is after the deploy to catch role changes the old code made in between.
|
||||
-- Non-object entries are skipped through a CASE rather than handed to json_extract, which
|
||||
-- raises on a bare string.
|
||||
DELETE FROM room_role;
|
||||
INSERT OR IGNORE INTO room_role (account_id, room_id, role, invited_role, last_changed_by_account_id)
|
||||
SELECT account_id, room_id, COALESCE(role, 0), COALESCE(invited_role, 0), last_changed_by_account_id
|
||||
FROM (
|
||||
SELECT room.room_id AS room_id,
|
||||
CASE WHEN r.type = 'object' THEN json_extract(r.value, '$.AccountId') END AS account_id,
|
||||
CASE WHEN r.type = 'object' THEN json_extract(r.value, '$.Role') END AS role,
|
||||
CASE WHEN r.type = 'object' THEN json_extract(r.value, '$.InvitedRole') END AS invited_role,
|
||||
CASE WHEN r.type = 'object' THEN json_extract(r.value, '$.LastChangedByAccountId') END AS last_changed_by_account_id
|
||||
FROM room, json_each(room.data, '$.Roles') AS r
|
||||
) WHERE account_id > 0 AND room_id IS NOT NULL;
|
||||
Reference in New Issue
Block a user