1import type { PgClient } from "@effect/sql-pg/PgClient";
2import * as Cloudflare from "alchemy/Cloudflare";
3import * as Drizzle from "alchemy/Drizzle";
4import * as Planetscale from "alchemy/Planetscale";
5import * as Alchemy from "alchemy";
6import * as RemovalPolicy from "alchemy/RemovalPolicy";
7import type { EffectPgDatabase } from "drizzle-orm/effect-postgres";
8import * as Context from "effect/Context";
9import * as Effect from "effect/Effect";
10import * as Layer from "effect/Layer";
11
12import { relayDatabaseMode } from "./dbConfig.ts";
13
14export class RelayDb extends Context.Service<
15 RelayDb,
16 EffectPgDatabase & {
17 readonly $client: PgClient;
18 }
19>()("t3code-relay/db/RelayDb") {}
20
21export class RelayTransactions extends Context.Service<
22 RelayTransactions,
23 {
24 readonly withTransaction: RelayDb["Service"]["$client"]["withTransaction"];
25 }
26>()("t3code-relay/db/RelayTransactions") {
27 static readonly layer = Layer.effect(
28 RelayTransactions,
29 Effect.gen(function* () {
30 const db = yield* RelayDb;
31 return RelayTransactions.of({
32 withTransaction: db.$client.withTransaction,
33 });
34 }),
35 );
36}
37
38export const PlanetscaleDatabase = Effect.gen(function* () {
39 const { stage } = yield* Alchemy.Stack;
40 const schema = yield* Drizzle.Schema("RelaySchema", {
41 schema: "./src/persistence/schema.ts",
42 out: "./migrations/postgres",
43 dialect: "postgres",
44 });
45
46 const mode = relayDatabaseMode(stage);
47 const database =
48 mode === "shared-database"
49 ? yield* Planetscale.PostgresDatabase("RelayPostgresDatabase", {
50 name: "t3coderelay",
51 region: { slug: "us-west" },
52 clusterSize: "PS_80",
53 migrations: { dir: schema.out, table: "relay_migrations" },
54 replicas: 2,
55 }).pipe(RemovalPolicy.retain())
56 : yield* Planetscale.PostgresDatabase.ref("RelayPostgresDatabase", {
57 stage: "prod",
58 });
59 const branch =
60 mode === "stage-branch"
61 ? yield* Planetscale.PostgresBranch("RelayPostgresBranch", {
62 database,
63 migrations: { dir: schema.out, table: "relay_migrations" },
64 })
65 : undefined;
66
67 const runtimeRole = yield* Planetscale.PostgresRole("RelayPostgresRuntimeRole", {
68 database,
69 ...(branch ? { branch } : {}),
70 inheritedRoles: ["pg_read_all_data", "pg_write_all_data"],
71 });
72
73 return { branch, database, runtimeRole };
74});
75
76export const RelayHyperdrive = Effect.gen(function* () {
77 const { runtimeRole } = yield* PlanetscaleDatabase;
78 return yield* Cloudflare.Hyperdrive.Connection("RelayHyperdrive", {
79 origin: runtimeRole.origin,
80 caching: {
81 disabled: true,
82 },
83 originConnectionLimit: 40,
84 });
85});