1import * as Cloudflare from "alchemy/Cloudflare";
2import * as Effect from "effect/Effect";
3import * as HttpApiBuilder from "effect/http-api/HttpApiBuilder";
4import { BackendApi, Note, NotesList } from "./BackendApi";
5import { DB } from "./Bindings";
6
7export const BackendHandlers = HttpApiBuilder.group(
8 BackendApi,
9 "Backend",
10 Effect.fn(function* (handlers) {
11 const db = yield* Cloudflare.D1.QueryDatabase(DB);
12
13 return handlers
14 .handle("listNotes", () =>
15 db
16 .prepare(
17 "SELECT id, title, source, created_at FROM notes ORDER BY created_at DESC",
18 )
19 .all<{
20 id: string;
21 title: string;
22 source: string;
23 created_at: number;
24 }>()
25 .pipe(
26 Effect.map(
27 ({ results }) =>
28 new NotesList({
29 notes: (results ?? []).map(
30 (row) =>
31 new Note({
32 id: row.id,
33 title: row.title,
34 source: row.source,
35 createdAt: row.created_at,
36 }),
37 ),
38 }),
39 ),
40 Effect.orDie,
41 ),
42 )
43 .handle("createNote", ({ payload }) =>
44 Effect.gen(function* () {
45 const note = new Note({
46 id: crypto.randomUUID(),
47 title: payload.title,
48 source: "effect-httpapi",
49 createdAt: Date.now(),
50 });
51 yield* db
52 .prepare(
53 "INSERT INTO notes (id, title, source, created_at) VALUES (?, ?, ?, ?)",
54 )
55 .bind(note.id, note.title, note.source, note.createdAt)
56 .run();
57 return note;
58 }).pipe(Effect.orDie),
59 )
60 .handle("deleteNote", ({ params }) =>
61 db
62 .prepare("DELETE FROM notes WHERE id = ?")
63 .bind(params.id)
64 .run()
65 .pipe(Effect.asVoid, Effect.orDie),
66 );
67 }),
68);