import { drizzle } from 'drizzle-orm/postgres-js'; import postgres from 'postgres'; import * as schema from './schema'; const connectionString = process.env.DATABASE_URL!; // Connection pool for queries. // // `statement_timeout` and `idle_in_transaction_session_timeout` are set // per-connection via `connection.options` (postgres.js exposes the // startup-parameter list there). Without these, a slow query or a // transaction left open by a crashed handler holds a connection slot // indefinitely and eventually exhausts the pool (max=20). The 30s // statement cap is well above expected query latency; tune up if a // legitimate report needs longer. // // `max_lifetime` recycles connections every 30 minutes so any // per-connection state drift (prepared statements, GUCs) doesn't // accumulate forever. const queryClient = postgres(connectionString, { max: 20, idle_timeout: 20, connect_timeout: 10, max_lifetime: 60 * 30, connection: { // ms values per postgres.js types; these become Postgres GUC settings // applied at session start. statement_timeout: 30_000, idle_in_transaction_session_timeout: 10_000, }, }); export const db = drizzle(queryClient, { schema, logger: process.env.NODE_ENV === 'development', }); /** Close the underlying connection pool. Used by the vitest teardown so * the parent process can exit cleanly. */ export async function closeDb(): Promise { await queryClient.end({ timeout: 5 }); } export type Database = typeof db;