1import * as Cloudflare from "@/Cloudflare/index.ts";
2import * as SQL from "@/SQL/D1.ts";
3import * as Effect from "effect/Effect";
4import * as HttpServerRequest from "effect/http/HttpServerRequest";
5import * as HttpServerResponse from "effect/http/HttpServerResponse";
6import { makeLayerUsers, makeSqlRoutes } from "./routes.ts";
7
8export const Database = Cloudflare.D1.Database("SqlD1Database");
9
10const TABLE = "alchemy_sql_users";
11
12const DDL = `CREATE TABLE IF NOT EXISTS ${TABLE} (
13 id INTEGER PRIMARY KEY,
14 name TEXT NOT NULL,
15 email TEXT NOT NULL
16)`;
17
18/**
19 * Init effect for the whole route surface: binds the D1 database, builds the
20 * `SQL.D1` client and the `SQL.D1Layer`-backed users service, and returns
21 * the handler interface. Resources/bindings yielded here dedupe with any
22 * other usage in the Worker, so nothing needs to be threaded through `fetch`.
23 */
24const D1Routes = Effect.gen(function* () {
25 const d1 = yield* Cloudflare.D1.QueryDatabase(Database);
26 const sql = yield* SQL.D1(d1);
27 const layerUsers = yield* makeLayerUsers(TABLE).pipe(
28 Effect.provide(SQL.D1Layer(d1)),
29 );
30 return makeSqlRoutes({ sql, layerUsers, ddl: DDL, table: TABLE });
31});
32
33/**
34 * Effect-native Worker driving `SQL.D1` (the raw `@effect/sql-d1` client)
35 * over a bound D1 database. All routes come from the shared dialect-agnostic
36 * table in `routes.ts` — D1 has no dialect extras (`@effect/sql-d1` supports
37 * neither transactions nor `updateValues`).
38 */
39export default class SqlD1Worker extends Cloudflare.Worker<SqlD1Worker>()(
40 "SqlD1Worker",
41 {
42 main: import.meta.url,
43 },
44 Effect.gen(function* () {
45 const routes = yield* D1Routes;
46
47 return {
48 fetch: Effect.gen(function* () {
49 const request = yield* HttpServerRequest.HttpServerRequest;
50 const response = yield* routes.handle(request);
51 if (response !== undefined) {
52 return response;
53 }
54 return yield* HttpServerResponse.json(
55 { error: "not found" },
56 { status: 404 },
57 );
58 }).pipe(
59 Effect.catchCause((cause) =>
60 HttpServerResponse.json({ error: String(cause) }, { status: 500 }),
61 ),
62 ),
63 };
64 }).pipe(Effect.provide(Cloudflare.D1.QueryDatabaseBinding)),
65) {}