| 1 | import * as Cloudflare from "@/Cloudflare/index.ts"; |
| 2 | import * as SQL from "@/SQL/D1.ts"; |
| 3 | import * as Effect from "effect/Effect"; |
| 4 | import * as HttpServerRequest from "effect/http/HttpServerRequest"; |
| 5 | import * as HttpServerResponse from "effect/http/HttpServerResponse"; |
| 6 | import { makeLayerUsers, makeSqlRoutes } from "./routes.ts"; |
| 7 | |
| 8 | export const Database = Cloudflare.D1.Database("SqlD1Database"); |
| 9 | |
| 10 | const TABLE = "alchemy_sql_users"; |
| 11 | |
| 12 | const 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 | */ |
| 24 | const 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 | */ |
| 39 | export 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 | ) {} |