1import * as Cloudflare from "alchemy/Cloudflare";
2import * as Drizzle from "alchemy/Drizzle";
3import { eq } from "drizzle-orm";
4import * as Effect from "effect/Effect";
5import * as HttpServerRequest from "effect/http/HttpServerRequest";
6import * as HttpServerResponse from "effect/http/HttpServerResponse";
7import { Database } from "./Db.ts";
8import { relations, Users } from "./schema.ts";
9
10export default class Api extends Cloudflare.Worker<Api>()(
11 "Api",
12 {
13 main: import.meta.url,
14 },
15 Effect.gen(function* () {
16 const database = yield* Database;
17 const d1 = yield* Cloudflare.D1.QueryDatabase(database);
18
19 // drizzle-orm's `effect-d1` driver over the native D1 binding.
20 const db = yield* Drizzle.D1(d1, { relations });
21
22 return {
23 fetch: Effect.gen(function* () {
24 const request = yield* HttpServerRequest.HttpServerRequest;
25 switch (request.method) {
26 case "GET": {
27 if (request.url === "/") {
28 const users = yield* db.select().from(Users);
29 return yield* HttpServerResponse.json({ users });
30 }
31 const id = Number(request.url.split("/").pop());
32 if (Number.isNaN(id)) {
33 return yield* HttpServerResponse.json(
34 { error: "Invalid user ID" },
35 { status: 400 },
36 );
37 }
38 const user = yield* db.query.Users.findFirst({
39 where: { id },
40 with: { posts: true },
41 });
42 return yield* HttpServerResponse.json({ user });
43 }
44 case "POST": {
45 const user = yield* db
46 .insert(Users)
47 .values({
48 name: crypto.randomUUID(),
49 email: crypto.randomUUID(),
50 })
51 .returning();
52 return yield* HttpServerResponse.json({ user });
53 }
54 case "DELETE": {
55 const id = Number(request.url.split("/").pop());
56 if (Number.isNaN(id)) {
57 return yield* HttpServerResponse.json(
58 { error: "Invalid user ID" },
59 { status: 400 },
60 );
61 }
62 const [user] = yield* db
63 .delete(Users)
64 .where(eq(Users.id, id))
65 .returning();
66 return yield* HttpServerResponse.json({ user });
67 }
68 default: {
69 return yield* HttpServerResponse.json(
70 { error: "Method not allowed" },
71 { status: 405 },
72 );
73 }
74 }
75 }).pipe(
76 Effect.catchCause((cause) =>
77 HttpServerResponse.json({ error: String(cause) }, { status: 500 }),
78 ),
79 ),
80 };
81 }).pipe(Effect.provide(Cloudflare.D1.QueryDatabaseBinding)),
82) {}