import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; import * as FileSystem from "effect/FileSystem"; import * as Path from "effect/Path"; import * as SqlClient from "effect/unstable/sql/SqlClient"; import type { SqlError } from "effect/unstable/sql/SqlError"; import { runMigrations } from "../Migrations.ts"; import { ServerConfig } from "../../config.ts"; type RuntimeSqliteLayerConfig = { readonly filename: string; readonly spanAttributes?: Record; }; type Loader = { layer: (config: RuntimeSqliteLayerConfig) => Layer.Layer; }; const defaultSqliteClientLoaders = { bun: () => import("@effect/sql-sqlite-bun/SqliteClient"), node: () => import("@t3tools/shared/nodeSqliteClient"), } satisfies Record Promise>; const makeRuntimeSqliteLayer = Effect.fn("makeRuntimeSqliteLayer")(function* ( config: RuntimeSqliteLayerConfig, ) { const runtime = process.versions.bun !== undefined ? "bun" : "node"; const loader = defaultSqliteClientLoaders[runtime]; const clientModule = yield* Effect.promise(loader); return clientModule.layer(config); }, Layer.unwrap); const setup = Layer.effectDiscard( Effect.gen(function* () { const sql = yield* SqlClient.SqlClient; // CLI and server write from separate processes; wait rather than fail with SQLITE_BUSY. yield* sql`PRAGMA busy_timeout = 5000;`; yield* sql`PRAGMA foreign_keys = ON;`; yield* sql`PRAGMA journal_mode = WAL;`; yield* runMigrations(); }), ); export const makeSqlitePersistenceLive = Effect.fn("makeSqlitePersistenceLive")(function* ( dbPath: string, ) { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; yield* fs.makeDirectory(path.dirname(dbPath), { recursive: true }); return Layer.provideMerge( setup, makeRuntimeSqliteLayer({ filename: dbPath, spanAttributes: { "db.name": path.basename(dbPath), "service.name": "t3-server", }, }), ); }, Layer.unwrap); export const SqlitePersistenceMemory = Layer.provideMerge( setup, makeRuntimeSqliteLayer({ filename: ":memory:" }), ); export const layerConfig = Layer.unwrap( Effect.gen(function* () { const { dbPath } = yield* ServerConfig; return makeSqlitePersistenceLive(dbPath); }), );