SPB Git forge

spb/market-atlas

Public
12commits 1branches 0releases
1.1 MBsize
maindefault branch
10 days agolast push
TypeScript 96.7% SQL 1.6% CSS 0.8% JavaScript 0.5%
1.6 KB · 50 lines typescript
Raw Blame History
1import pg from "pg";2import { config } from "../config.js";3import { logger } from "../logger.js";45const { Pool, types } = pg;6// timestamptz stays a Date (pg default → ISO in JSON); numeric/int8 as numbers where safe.7types.setTypeParser(20, (v) => Number(v));8types.setTypeParser(1700, (v) => Number(v));910export const pool = new Pool({11  connectionString: config.databaseUrl,12  max: config.role === "api" ? 8 : 16,13  idleTimeoutMillis: 30_000,14  statement_timeout: 60_000,15  options: "-c lock_timeout=15000", // never let a lock wait starve the pool (health checks must keep answering)16  application_name: `market-atlas-${config.role}`,17});1819pool.on("error", (err) => logger.error({ err }, "pg pool error"));2021export type Queryable = pg.Pool | pg.PoolClient;2223export async function query<T extends pg.QueryResultRow = pg.QueryResultRow>(text: string, params: unknown[] = [], client: Queryable = pool) {24  return client.query<T>(text, params as never[]);25}2627export async function withTransaction<T>(fn: (client: pg.PoolClient) => Promise<T>): Promise<T> {28  const client = await pool.connect();29  try {30    await client.query("begin");31    const out = await fn(client);32    await client.query("commit");33    return out;34  } catch (err) {35    await client.query("rollback").catch(() => {});36    throw err;37  } finally {38    client.release();39  }40}4142export const tsToMs = (v: unknown): number | null => {43  if (v == null) return null;44  if (v instanceof Date) return v.getTime();45  const ms = Date.parse(String(v));46  return Number.isFinite(ms) ? ms : null;47};4849export const msToTs = (ms: number | null | undefined): string | null => (ms == null ? null : new Date(ms).toISOString());50