From e1492780842b442bd39a843930926bcd7cb60e1a Mon Sep 17 00:00:00 2001 From: Diogenes Date: Thu, 1 Oct 2026 14:28:27 -0300 Subject: [PATCH] fix(db): stringify interpolated values for Postgres like SQLite's toBindable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bun.sql binds plain objects to text parameters via String() → '[object Object]', so every *_json column write stored garbage on Postgres while the SQLite adapter JSON.stringify'd the same values. --- server/db/postgres.ts | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/server/db/postgres.ts b/server/db/postgres.ts index 23eefb67e..2d7c4321f 100644 --- a/server/db/postgres.ts +++ b/server/db/postgres.ts @@ -58,11 +58,30 @@ function resultRowCount(result: Row[]): number { * under the surrounding `sql.begin()`. */ function wrapSql(sql: SQL, ownsPool = false): DbClient { + /** + * Convert an interpolated JS value into something Bun.sql can bind for + * Postgres, mirroring SQLite's toBindable so `*_json` columns round-trip + * identically on both dialects. + * + * - Plain objects / arrays → JSON.stringify (stored as TEXT) + * - Date → ISO 8601 string + * - Uint8Array / Buffer → pass through (bound to bytea) + * - string, number → pass through + * - null / undefined → null + */ + const serialize = (value: unknown): unknown => { + if (value === null || value === undefined) return null + if (value instanceof Uint8Array) return value + if (value instanceof Date) return value.toISOString() + if (typeof value === 'object') return JSON.stringify(value) + return value + } + const fn = (async >( strings: TemplateStringsArray, ...values: unknown[] ): Promise> => { - const rows = await sql(strings, ...values) + const rows = await sql(strings, ...values.map(serialize)) return { rows: rows.map(normalizePostgresRow), rowCount: resultRowCount(rows) } }) as DbClient @@ -71,7 +90,7 @@ function wrapSql(sql: SQL, ownsPool = false): DbClient { params?: unknown[], ): Promise> => { const rows = params !== undefined - ? await sql.unsafe(rawSql, params as unknown[]) + ? await sql.unsafe(rawSql, params.map(serialize)) : await sql.unsafe(rawSql) return { rows: rows.map(normalizePostgresRow), rowCount: resultRowCount(rows) } }