1import * as Cloudflare from "@/Cloudflare/index.ts";
2import * as Drizzle from "@/Drizzle/index.ts";
3import * as SQL from "@/SQL/D1.ts";
4import * as Effect from "effect/Effect";
5import * as HttpServerRequest from "effect/http/HttpServerRequest";
6import * as HttpServerResponse from "effect/http/HttpServerResponse";
7import { DrizzleDb } from "./drizzle-database.ts";
8import { Posts, relations, Users } from "./drizzle-schema.ts";
9
10/**
11 * Effect-native Worker exercising BOTH D1 client layers over one database:
12 *
13 * - `Drizzle.D1(d1, { relations })` — the drizzle-orm `effect-d1` driver
14 * (typed query builder + relational queries);
15 * - `SQL.D1(d1)` — the raw `@effect/sql-d1` client
16 * (tagged-template SQL).
17 */
18export default class D1DrizzleWorker extends Cloudflare.Worker<D1DrizzleWorker>()(
19 "D1DrizzleWorker",
20 {
21 main: import.meta.url,
22 },
23 Effect.gen(function* () {
24 const database = yield* DrizzleDb;
25 const d1 = yield* Cloudflare.D1.QueryDatabase(database);
26 const db = yield* Drizzle.D1(d1, { relations });
27 const sql = yield* SQL.D1(d1);
28
29 return {
30 fetch: Effect.gen(function* () {
31 const request = yield* HttpServerRequest.HttpServerRequest;
32 const segments = request.url.split("/").filter(Boolean);
33
34 if (request.method === "POST" && request.url === "/users") {
35 const body = (yield* request.json) as {
36 name: string;
37 email: string;
38 };
39 const [user] = yield* db
40 .insert(Users)
41 .values({ name: body.name, email: body.email })
42 .returning();
43 return yield* HttpServerResponse.json({ user });
44 }
45
46 if (request.method === "POST" && request.url === "/posts") {
47 const body = (yield* request.json) as {
48 userId: number;
49 title: string;
50 };
51 const [post] = yield* db
52 .insert(Posts)
53 .values({ userId: body.userId, title: body.title })
54 .returning();
55 return yield* HttpServerResponse.json({ post });
56 }
57
58 if (request.method === "GET" && request.url === "/users") {
59 const users = yield* db.select().from(Users);
60 return yield* HttpServerResponse.json({ users });
61 }
62
63 // GET /users/:id — relational query (RQB v2) joining posts.
64 if (
65 request.method === "GET" &&
66 segments[0] === "users" &&
67 segments.length === 2
68 ) {
69 const id = Number(segments[1]);
70 const user = yield* db.query.Users.findFirst({
71 where: { id },
72 with: { posts: true },
73 });
74 return yield* HttpServerResponse.json({ user });
75 }
76
77 // GET /sql/users — the raw @effect/sql-d1 client.
78 if (request.method === "GET" && request.url === "/sql/users") {
79 const rows = yield* sql`SELECT id, name, email FROM users`;
80 return yield* HttpServerResponse.json({ rows });
81 }
82
83 return yield* HttpServerResponse.json(
84 { error: "not found" },
85 { status: 404 },
86 );
87 }).pipe(
88 Effect.catchCause((cause) =>
89 HttpServerResponse.json({ error: String(cause) }, { status: 500 }),
90 ),
91 ),
92 };
93 }).pipe(Effect.provide(Cloudflare.D1.QueryDatabaseBinding)),
94) {}