Skip to content
File

Blob: tests/worker/helpers/seeds.ts

typescript299 lines
1import { ulid } from "ulid";
2import { and, eq } from "drizzle-orm";
3import {
4 invites,
5 memberships,
6 pageShares,
7 pages,
8 publishedPages,
9 tesseraIdentities,
10 uploads,
11 users,
12 workspaces,
13 workspaceSites,
14} from "@/worker/db/d1/schema";
15import { getDb } from "@tests/worker/helpers/db";
16import { TEST_TIMESTAMP } from "@tests/worker/helpers/fixtures";
17 
18export interface SeedUser {
19 id: string;
20 email: string;
21 name: string;
22}
23 
24export interface SeedUserOptions {
25 id?: string;
26 email?: string;
27 name?: string;
28 avatar_url?: string | null;
29}
30 
31export async function seedUser(opts: SeedUserOptions = {}): Promise<SeedUser> {
32 const id = opts.id ?? `user_${ulid()}`;
33 const email = opts.email ?? `${id}@example.com`;
34 const name = opts.name ?? "Test User";
35 
36 await getDb()
37 .insert(users)
38 .values({
39 id,
40 email,
41 name,
42 avatar_url: opts.avatar_url ?? null,
43 created_at: TEST_TIMESTAMP,
44 updated_at: TEST_TIMESTAMP,
45 });
46 
47 return { id, email, name };
48}
49 
50export interface SeedTesseraIdentityOptions {
51 sub: string;
52 user_id: string;
53 created_at?: string;
54 last_seen_at?: string | null;
55}
56 
57export async function seedTesseraIdentity(
58 opts: SeedTesseraIdentityOptions,
59): Promise<typeof tesseraIdentities.$inferSelect> {
60 const row: typeof tesseraIdentities.$inferSelect = {
61 sub: opts.sub,
62 user_id: opts.user_id,
63 created_at: opts.created_at ?? TEST_TIMESTAMP,
64 last_seen_at: opts.last_seen_at ?? null,
65 };
66 await getDb().insert(tesseraIdentities).values(row);
67 return row;
68}
69 
70export interface SeedWorkspace {
71 id: string;
72 slug: string;
73 name: string;
74 owner_id: string;
75}
76 
77export interface SeedWorkspaceOptions {
78 id?: string;
79 slug?: string;
80 name?: string;
81 owner_id: string;
82 icon?: string | null;
83 seedOwnerMembership?: boolean;
84}
85 
86export async function seedWorkspace(opts: SeedWorkspaceOptions): Promise<SeedWorkspace> {
87 const id = opts.id ?? `ws_${ulid()}`;
88 const slug = opts.slug ?? id.toLowerCase();
89 const name = opts.name ?? "Test Workspace";
90 
91 await getDb()
92 .insert(workspaces)
93 .values({
94 id,
95 slug,
96 name,
97 icon: opts.icon ?? null,
98 owner_id: opts.owner_id,
99 created_at: TEST_TIMESTAMP,
100 });
101 
102 if (opts.seedOwnerMembership !== false) {
103 await seedMembership({ user_id: opts.owner_id, workspace_id: id, role: "owner" });
104 }
105 
106 return { id, slug, name, owner_id: opts.owner_id };
107}
108 
109export interface SeedMembershipOptions {
110 user_id: string;
111 workspace_id: string;
112 role: typeof memberships.$inferSelect.role;
113 joined_at?: string;
114}
115 
116export async function seedMembership(opts: SeedMembershipOptions): Promise<typeof memberships.$inferSelect> {
117 const row = {
118 user_id: opts.user_id,
119 workspace_id: opts.workspace_id,
120 role: opts.role,
121 joined_at: opts.joined_at ?? TEST_TIMESTAMP,
122 };
123 await getDb().insert(memberships).values(row);
124 return row;
125}
126 
127export interface SeedPageOptions {
128 id?: string;
129 workspace_id: string;
130 created_by: string;
131 parent_id?: string | null;
132 kind?: "doc" | "canvas";
133 title?: string;
134 icon?: string | null;
135 cover_url?: string | null;
136 position?: number;
137 archived_at?: string | null;
138 archive_root_id?: string | null;
139 created_at?: string;
140 updated_at?: string;
141}
142 
143export async function seedPage(opts: SeedPageOptions): Promise<typeof pages.$inferSelect> {
144 // ULID (26 chars) fits the PresignRequest page_id.max(26) contract without prefix.
145 const id = opts.id ?? ulid();
146 const row: typeof pages.$inferSelect = {
147 id,
148 workspace_id: opts.workspace_id,
149 parent_id: opts.parent_id ?? null,
150 kind: opts.kind ?? "doc",
151 title: opts.title ?? "Test Page",
152 icon: opts.icon ?? null,
153 cover_url: opts.cover_url ?? null,
154 position: opts.position ?? 1,
155 created_by: opts.created_by,
156 created_at: opts.created_at ?? TEST_TIMESTAMP,
157 updated_at: opts.updated_at ?? TEST_TIMESTAMP,
158 archived_at: opts.archived_at ?? null,
159 archive_root_id: opts.archive_root_id ?? null,
160 };
161 await getDb().insert(pages).values(row);
162 return row;
163}
164 
165export interface SeedPageShareOptions {
166 id?: string;
167 page_id: string;
168 created_by: string;
169 permission: "view" | "edit";
170 grantee_type: "user" | "link";
171 grantee_id?: string | null;
172 link_token?: string | null;
173}
174 
175export async function seedPageShare(opts: SeedPageShareOptions): Promise<typeof pageShares.$inferSelect> {
176 const row: typeof pageShares.$inferSelect = {
177 id: opts.id ?? `share_${ulid()}`,
178 page_id: opts.page_id,
179 grantee_type: opts.grantee_type,
180 grantee_id: opts.grantee_id ?? null,
181 permission: opts.permission,
182 link_token: opts.link_token ?? null,
183 created_by: opts.created_by,
184 created_at: TEST_TIMESTAMP,
185 };
186 await getDb().insert(pageShares).values(row);
187 return row;
188}
189 
190export interface SeedWorkspaceSiteOptions {
191 workspace_id: string;
192 slug?: string;
193 home_page_id?: string | null;
194 published?: boolean;
195 published_at?: string | null;
196 created_at?: string;
197 updated_at?: string;
198}
199 
200export async function seedWorkspaceSite(opts: SeedWorkspaceSiteOptions): Promise<typeof workspaceSites.$inferSelect> {
201 const createdAt = opts.created_at ?? TEST_TIMESTAMP;
202 const publishedAt =
203 typeof opts.published_at === "undefined" ? (opts.published === false ? null : createdAt) : opts.published_at;
204 const row: typeof workspaceSites.$inferSelect = {
205 workspace_id: opts.workspace_id,
206 slug: opts.slug ?? "acme",
207 home_page_id: opts.home_page_id ?? null,
208 published_at: publishedAt,
209 created_at: createdAt,
210 updated_at: opts.updated_at ?? createdAt,
211 };
212 
213 await getDb().insert(workspaceSites).values(row);
214 return row;
215}
216 
217export interface SeedPublishedPageOptions {
218 workspace_id: string;
219 page_id: string;
220 published_by: string;
221 published_at?: string;
222}
223 
224export async function seedPublishedPage(opts: SeedPublishedPageOptions): Promise<typeof publishedPages.$inferSelect> {
225 const row: typeof publishedPages.$inferSelect = {
226 workspace_id: opts.workspace_id,
227 page_id: opts.page_id,
228 published_by: opts.published_by,
229 published_at: opts.published_at ?? TEST_TIMESTAMP,
230 };
231 
232 await getDb().insert(publishedPages).values(row).onConflictDoNothing();
233 return row;
234}
235 
236export async function deletePublishedPage(workspaceId: string, pageId: string): Promise<void> {
237 await getDb()
238 .delete(publishedPages)
239 .where(and(eq(publishedPages.workspace_id, workspaceId), eq(publishedPages.page_id, pageId)));
240}
241 
242export interface SeedInviteOptions {
243 id?: string;
244 workspace_id: string;
245 invited_by: string;
246 role?: "admin" | "member" | "guest";
247 email?: string | null;
248 token?: string;
249 expires_at?: string;
250 accepted_at?: string | null;
251 accepted_by?: string | null;
252 revoked_at?: string | null;
253}
254 
255export async function seedInvite(opts: SeedInviteOptions): Promise<typeof invites.$inferSelect> {
256 const row: typeof invites.$inferSelect = {
257 id: opts.id ?? `invite_${ulid()}`,
258 email: opts.email ?? null,
259 workspace_id: opts.workspace_id,
260 invited_by: opts.invited_by,
261 role: opts.role ?? "member",
262 token: opts.token ?? `inv_${ulid()}`,
263 accepted_at: opts.accepted_at ?? null,
264 accepted_by: opts.accepted_by ?? null,
265 revoked_at: opts.revoked_at ?? null,
266 expires_at: opts.expires_at ?? "2099-01-01T00:00:00.000Z",
267 created_at: TEST_TIMESTAMP,
268 };
269 await getDb().insert(invites).values(row);
270 return row;
271}
272 
273export interface SeedUploadOptions {
274 id?: string;
275 workspace_id: string;
276 uploaded_by: string;
277 page_id?: string | null;
278 filename?: string;
279 content_type?: string;
280 size_bytes?: number;
281 r2_key?: string;
282}
283 
284export async function seedUpload(opts: SeedUploadOptions): Promise<typeof uploads.$inferSelect> {
285 const row: typeof uploads.$inferSelect = {
286 id: opts.id ?? `upload_${ulid()}`,
287 workspace_id: opts.workspace_id,
288 page_id: opts.page_id ?? null,
289 uploaded_by: opts.uploaded_by,
290 filename: opts.filename ?? "test.png",
291 content_type: opts.content_type ?? "image/png",
292 size_bytes: opts.size_bytes ?? 128,
293 r2_key: opts.r2_key ?? `uploads/${opts.workspace_id}/${ulid()}.png`,
294 created_at: TEST_TIMESTAMP,
295 };
296 await getDb().insert(uploads).values(row);
297 return row;
298}