Skip to content
File

Blob: src/client/stores/db/workspace-replica.ts

typescript144 lines
1import type { Page, Workspace, WorkspaceMember, WorkspaceRole } from "@/shared/types";
2import {
3 db,
4 type PageAccessMode,
5 type WorkspaceAccessMode,
6 type WorkspacePageRow,
7 type WorkspaceReplicaRow,
8} from "./bland-db";
9 
10interface ReplaceWorkspaceInput {
11 workspace: Workspace;
12 accessMode: WorkspaceAccessMode;
13 workspaceRole: WorkspaceRole | null;
14 pages: Page[];
15 members: WorkspaceMember[];
16}
17 
18function 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 
32async 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 
47async 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 
64async 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 
73async function addPage(_workspaceId: string, page: Page): Promise<void> {
74 await db.workspacePages.put(page as WorkspacePageRow);
75}
76 
77async 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 
88async 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 
95async 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 
103async 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 
111async 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 
118async function upsertPageAccess(pageId: string, mode: PageAccessMode): Promise<void> {
119 await db.pageAccess.put({ pageId, mode });
120}
121 
122async function removePageAccess(pageId: string): Promise<void> {
123 await db.pageAccess.delete(pageId);
124}
125 
126async function removeReplica(workspaceId: string): Promise<void> {
127 await db.workspaceReplicas.delete(workspaceId);
128}
129 
130export 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};