1import * as Alchemy from "alchemy";
2import * as Cloudflare from "alchemy/Cloudflare";
3import * as Drizzle from "alchemy/Drizzle";
4import * as Neon from "alchemy/Neon";
5import * as Effect from "effect/Effect";
6
7/**
8 * A Drizzle schema + Neon project + feature branch. The branch's
9 * `migrations` prop is wired to the schema resource, so the
10 * provider order becomes:
11 *
12 * 1. `Drizzle.Schema` regenerates pending migration SQL files.
13 * 2. `Neon.Branch` scans the directory and applies any new migrations
14 * transactionally.
15 */
16export const NeonDb = Effect.gen(function* () {
17 const { stage } = yield* Alchemy.Stack;
18
19 const schema = yield* Drizzle.Schema("app-schema", {
20 schema: "./src/schema.ts",
21 out: "./migrations",
22 });
23
24 const project = stage.startsWith("pr-")
25 ? yield* Neon.Project.ref("app-db", { stage: `staging-${stage}` })
26 : yield* Neon.Project("app-db", {
27 region: "aws-us-east-1",
28 });
29
30 const branch = yield* Neon.Branch("app-branch", {
31 project,
32 migrations: schema,
33 });
34
35 return { project, branch, schema };
36});
37
38export const Hyperdrive = Effect.gen(function* () {
39 const { branch } = yield* NeonDb;
40 return yield* Cloudflare.Hyperdrive.Connection("app-hyperdrive", {
41 origin: branch.origin,
42 });
43});