File
Blob: src/client/stores/db/workspace-replica.ts
| 1 | import type { Page, Workspace, WorkspaceMember, WorkspaceRole } from "@/shared/types"; |
| 2 | import { |
| 3 | db, |
| 4 | type PageAccessMode, |
| 5 | type WorkspaceAccessMode, |
| 6 | type WorkspacePageRow, |
| 7 | type WorkspaceReplicaRow, |
| 8 | } from "./bland-db"; |
| 9 | |
| 10 | interface ReplaceWorkspaceInput { |
| 11 | workspace: Workspace; |
| 12 | accessMode: WorkspaceAccessMode; |
| 13 | workspaceRole: WorkspaceRole | null; |
| 14 | pages: Page[]; |
| 15 | members: WorkspaceMember[]; |
| 16 | } |
| 17 | |
| 18 | function toReplicaRow(input: { |
| 19 | workspace: Workspace; |
| 20 | accessMode: WorkspaceAccessMode; |
| 21 | workspaceRole: WorkspaceRole | null; |
| 22 | }): WorkspaceReplicaRow { |
| 23 | return { |
| 24 | id: input.workspace.id, |
| 25 | slug: input.workspace.slug, |
| 26 | workspace: input.workspace, |
| 27 | accessMode: input.accessMode, |
| 28 | workspaceRole: input.workspaceRole, |
| 29 | }; |
| 30 | } |
| 31 | |
| 32 | async function replaceWorkspace(input: ReplaceWorkspaceInput): Promise<void> { |
| 33 | const workspaceId = input.workspace.id; |
| 34 | await db.transaction("rw", [db.workspaceReplicas, db.workspacePages, db.workspaceMembers], async () => { |
| 35 | await db.workspaceReplicas.put(toReplicaRow(input)); |
| 36 | await db.workspacePages.where("workspace_id").equals(workspaceId).delete(); |
| 37 | if (input.pages.length > 0) { |
| 38 | await db.workspacePages.bulkPut(input.pages); |
| 39 | } |
| 40 | await db.workspaceMembers.where("workspace_id").equals(workspaceId).delete(); |
| 41 | if (input.members.length > 0) { |
| 42 | await db.workspaceMembers.bulkPut(input.members); |
| 43 | } |
| 44 | }); |
| 45 | } |
| 46 | |
| 47 | async function patchWorkspaceHead(workspaceId: string, updates: Partial<Workspace>): Promise<void> { |
| 48 | await db.transaction("rw", db.workspaceReplicas, async () => { |
| 49 | const existing = await db.workspaceReplicas.get(workspaceId); |
| 50 | if (!existing) return; |
| 51 | const nextWorkspace: Workspace = { |
| 52 | ...existing.workspace, |
| 53 | ...updates, |
| 54 | id: existing.workspace.id, |
| 55 | }; |
| 56 | await db.workspaceReplicas.put({ |
| 57 | ...existing, |
| 58 | workspace: nextWorkspace, |
| 59 | slug: nextWorkspace.slug, |
| 60 | }); |
| 61 | }); |
| 62 | } |
| 63 | |
| 64 | async function replaceMembers(workspaceId: string, members: WorkspaceMember[]): Promise<void> { |
| 65 | await db.transaction("rw", db.workspaceMembers, async () => { |
| 66 | await db.workspaceMembers.where("workspace_id").equals(workspaceId).delete(); |
| 67 | if (members.length > 0) { |
| 68 | await db.workspaceMembers.bulkPut(members); |
| 69 | } |
| 70 | }); |
| 71 | } |
| 72 | |
| 73 | async function addPage(_workspaceId: string, page: Page): Promise<void> { |
| 74 | await db.workspacePages.put(page as WorkspacePageRow); |
| 75 | } |
| 76 | |
| 77 | async function upsertPage(_workspaceId: string, page: Page): Promise<void> { |
| 78 | await db.transaction("rw", db.workspacePages, async () => { |
| 79 | const existing = await db.workspacePages.get(page.id); |
| 80 | if (!existing) { |
| 81 | await db.workspacePages.put(page as WorkspacePageRow); |
| 82 | return; |
| 83 | } |
| 84 | await db.workspacePages.put({ ...existing, ...page }); |
| 85 | }); |
| 86 | } |
| 87 | |
| 88 | async function upsertPages(_workspaceId: string, pages: Page[]): Promise<void> { |
| 89 | if (pages.length === 0) return; |
| 90 | await db.transaction("rw", db.workspacePages, async () => { |
| 91 | await db.workspacePages.bulkPut(pages as WorkspacePageRow[]); |
| 92 | }); |
| 93 | } |
| 94 | |
| 95 | async function patchPage(_workspaceId: string, pageId: string, updates: Partial<Page>): Promise<void> { |
| 96 | await db.transaction("rw", db.workspacePages, async () => { |
| 97 | const existing = await db.workspacePages.get(pageId); |
| 98 | if (!existing) return; |
| 99 | await db.workspacePages.put({ ...existing, ...updates }); |
| 100 | }); |
| 101 | } |
| 102 | |
| 103 | async function removePages(_workspaceId: string, pageIds: string[]): Promise<void> { |
| 104 | if (pageIds.length === 0) return; |
| 105 | await db.transaction("rw", [db.workspacePages, db.pageAccess], async () => { |
| 106 | await db.workspacePages.bulkDelete(pageIds); |
| 107 | await db.pageAccess.bulkDelete(pageIds); |
| 108 | }); |
| 109 | } |
| 110 | |
| 111 | async function removePage(_workspaceId: string, pageId: string): Promise<void> { |
| 112 | await db.transaction("rw", [db.workspacePages, db.pageAccess], async () => { |
| 113 | await db.workspacePages.delete(pageId); |
| 114 | await db.pageAccess.delete(pageId); |
| 115 | }); |
| 116 | } |
| 117 | |
| 118 | async function upsertPageAccess(pageId: string, mode: PageAccessMode): Promise<void> { |
| 119 | await db.pageAccess.put({ pageId, mode }); |
| 120 | } |
| 121 | |
| 122 | async function removePageAccess(pageId: string): Promise<void> { |
| 123 | await db.pageAccess.delete(pageId); |
| 124 | } |
| 125 | |
| 126 | async function removeReplica(workspaceId: string): Promise<void> { |
| 127 | await db.workspaceReplicas.delete(workspaceId); |
| 128 | } |
| 129 | |
| 130 | export const replicaCommands = { |
| 131 | replaceWorkspace, |
| 132 | patchWorkspaceHead, |
| 133 | replaceMembers, |
| 134 | addPage, |
| 135 | upsertPage, |
| 136 | upsertPages, |
| 137 | patchPage, |
| 138 | removePage, |
| 139 | removePages, |
| 140 | upsertPageAccess, |
| 141 | removePageAccess, |
| 142 | removeReplica, |
| 143 | }; |