2026-05-31 21:46:54 -04:00
|
|
|
import { Pool, types } from 'pg';
|
|
|
|
|
|
|
|
|
|
// node-postgres returns BIGINT (int8, OID 20) as a *string* by default, because
|
|
|
|
|
// a 64-bit integer can exceed JS Number.MAX_SAFE_INTEGER. Our int8 columns
|
|
|
|
|
// (duration_ms, file_size, …) are always well within 2^53, so a string here is
|
|
|
|
|
// pure footgun: it breaks any consumer that does arithmetic or comparison on the
|
|
|
|
|
// value (e.g. `duration_ms + x` silently string-concatenates, sorts go
|
|
|
|
|
// lexicographic, `!ms`/`Math.round` edge cases). Parse int8 to a real Number so
|
|
|
|
|
// the API always emits numeric duration_ms/file_size in its JSON.
|
|
|
|
|
//
|
|
|
|
|
// 20 = int8/bigint OID. Values above Number.MAX_SAFE_INTEGER would lose
|
|
|
|
|
// precision, but no column in this schema ever reaches that range.
|
|
|
|
|
types.setTypeParser(20, (val) => (val === null ? null : parseInt(val, 10)));
|
2026-04-07 21:58:26 -04:00
|
|
|
|
2026-05-16 08:39:47 -04:00
|
|
|
// Prefer DATABASE_URL (set in docker-compose) over individual DB_* vars
|
|
|
|
|
const pool = process.env.DATABASE_URL
|
|
|
|
|
? new Pool({ connectionString: process.env.DATABASE_URL })
|
|
|
|
|
: new Pool({
|
|
|
|
|
user: process.env.DB_USER || 'postgres',
|
|
|
|
|
password: process.env.DB_PASSWORD,
|
|
|
|
|
host: process.env.DB_HOST || 'localhost',
|
|
|
|
|
port: parseInt(process.env.DB_PORT || '5432', 10),
|
|
|
|
|
database: process.env.DB_NAME || 'wild_dragon',
|
|
|
|
|
});
|
2026-04-07 21:58:26 -04:00
|
|
|
|
|
|
|
|
pool.on('error', (err) => {
|
|
|
|
|
console.error('Unexpected error on idle client', err);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export default pool;
|