From 64bbb221f7d5d47ae9c569a77f405531dc9050b9 Mon Sep 17 00:00:00 2001 From: Zac Gaetano Date: Sun, 31 May 2026 21:46:54 -0400 Subject: [PATCH] fix(api): parse Postgres bigint (int8) as Number, not string duration_ms/file_size are int8; node-postgres returned them as strings, a footgun for any consumer doing arithmetic/sorting/comparison (already hand-patched once in playout totals). Register a global int8 type parser so the API emits real numbers. All such values are < 2^53 (no precision loss). Co-Authored-By: Claude Opus 4.8 --- services/mam-api/src/db/pool.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/services/mam-api/src/db/pool.js b/services/mam-api/src/db/pool.js index 9cdafff..380bdd0 100644 --- a/services/mam-api/src/db/pool.js +++ b/services/mam-api/src/db/pool.js @@ -1,4 +1,16 @@ -import { Pool } from 'pg'; +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))); // Prefer DATABASE_URL (set in docker-compose) over individual DB_* vars const pool = process.env.DATABASE_URL