1import type { AsyncWorkerEnv } from "./stack.ts";
2
3const STYLE = "async";
4
5/**
6 * Async (non-Effect) Worker fixture. The shared D1 database is declared on
7 * the Worker `env` as `DB` (see `stack.ts`); `InferEnv` maps the
8 * `Cloudflare.D1.Database` marker to the native `cf.D1Database`, so the
9 * handler calls `env.DB.prepare(...)` / `env.DB.exec(...)` / `env.DB.batch(...)`
10 * directly — proving the engine injected the native binding into `env`.
11 *
12 * Drives the same SQL surface as the effect-worker, stamping rows with
13 * `style = "async"`. Mirrors the route contract in `routes.ts`.
14 */
15export default {
16 async fetch(request: Request, env: AsyncWorkerEnv): Promise<Response> {
17 const url = new URL(request.url, "http://x");
18 const db = env.DB;
19
20 if (request.method === "POST" && url.pathname === "/init") {
21 const result = await db.exec(
22 "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, style TEXT NOT NULL, name TEXT NOT NULL)",
23 );
24 return Response.json({ count: result.count, duration: result.duration });
25 }
26
27 if (request.method === "POST" && url.pathname === "/seed") {
28 const insert = db.prepare(
29 "INSERT OR REPLACE INTO users (id, style, name) VALUES (?, ?, ?)",
30 );
31 const results = await db.batch([
32 insert.bind(1, STYLE, "alice"),
33 insert.bind(2, STYLE, "bob"),
34 insert.bind(3, STYLE, "carol"),
35 ]);
36 return Response.json({
37 batches: results.length,
38 success: results.every((r) => r.success),
39 });
40 }
41
42 if (request.method === "POST" && url.pathname === "/users") {
43 const body = (await request.json()) as { id: number; name: string };
44 const result = await db
45 .prepare(
46 "INSERT OR REPLACE INTO users (id, style, name) VALUES (?, ?, ?)",
47 )
48 .bind(body.id, STYLE, body.name)
49 .run();
50 return Response.json({
51 success: result.success,
52 meta: { changes: result.meta.changes },
53 });
54 }
55
56 if (request.method === "GET" && url.pathname === "/users") {
57 const result = await db
58 .prepare("SELECT id, name FROM users WHERE style = ? ORDER BY id")
59 .bind(STYLE)
60 .all<{ id: number; name: string }>();
61 return Response.json({
62 success: result.success,
63 results: result.results,
64 });
65 }
66
67 const userMatch = url.pathname.match(/^\/users\/(\d+)$/);
68 if (request.method === "GET" && userMatch) {
69 const id = Number(userMatch[1]);
70 const row = await db
71 .prepare("SELECT id, name FROM users WHERE id = ? AND style = ?")
72 .bind(id, STYLE)
73 .first<{ id: number; name: string }>();
74 return Response.json({ row });
75 }
76
77 if (request.method === "GET" && url.pathname === "/raw") {
78 const result = await db
79 .prepare("SELECT COUNT(*) as count FROM users WHERE style = ?")
80 .bind(STYLE)
81 .first<{ count: number }>();
82 return Response.json({ count: result?.count ?? 0 });
83 }
84
85 return new Response("Not Found", { status: 404 });
86 },
87};