SPB Git
1.6 KB · 24 lines typescript
1import { drizzle } from "drizzle-orm/postgres-js";2import postgres from "postgres";3import * as schema from "./schema";45type Sql = ReturnType<typeof postgres>;6const g = globalThis as unknown as { __toolsSql?: Sql; __toolsSqlPublic?: Sql; __toolsDrizzleSql?: Sql };7const opts = { max: 6, idle_timeout: 30, prepare: false, transform: { undefined: null }, onnotice: () => {} } as const;8function need(name: string) { const v = process.env[name]; if (!v) throw new Error(`${name} is not set`); return v; }910/** Full-privilege raw client (admin API, worker, scripts). Never import from public route modules. */11export const sql: Sql = g.__toolsSql ?? postgres(need("DATABASE_URL"), opts);12/** Read-only raw client for everything public: `tools_reader` role in production (SELECT on public views only). */13export const sqlPublic: Sql = g.__toolsSqlPublic ?? postgres(process.env.DATABASE_URL_PUBLIC ?? need("DATABASE_URL"), { ...opts, max: 12 });14// Drizzle's postgres-js driver rewires the client's date/json serializers for its own mapping, which breaks raw tagged-template15// queries that pass Date objects — so Drizzle gets its own dedicated connection pool.16const drizzleSql: Sql = g.__toolsDrizzleSql ?? postgres(need("DATABASE_URL"), { ...opts, max: 4 });17if (process.env.NODE_ENV !== "production") { g.__toolsSql = sql; g.__toolsSqlPublic = sqlPublic; g.__toolsDrizzleSql = drizzleSql; }1819export const db = drizzle(drizzleSql, { schema, casing: "snake_case" });20export { schema };21export type DB = typeof db;22/** Close every pool (scripts/tests). */23export async function closeDb() { await Promise.all([sql.end(), sqlPublic.end(), drizzleSql.end()]); }24
Files · laptop-initial-20261102
Menu

Theme