Summary
Reading an int8 / bigint column returns a string at runtime, while the codec's declared output type is number. This is a silent type-soundness bug: every consumer sees number in TypeScript but receives a string value.
Evidence
PgInt8Codec (packages/3-targets/3-targets/postgres/src/core/codecs.ts) is declared with wire/input type number and decode(wire: number): Promise<number> as a bare pass-through (no coercion).
CodecTypes['pg/int8@1']['output'] therefore resolves to number, and generated contracts declare bigint-backed fields as number | null.
- At runtime, node-postgres decodes
int8/bigint columns as strings (to avoid >2^53 precision loss). The pass-through decode returns that string verbatim.
Result: create({ big: 10000000000 }) then read yields "10000000000" (string), not 10000000000 (number).
Reproduction
Round-trip any BigInt field and compare the read-back value: it is a string, though typed number.
Observed in the test-porting integration tests ported-datatypes.test.ts (entries #68, #69, #78, #79, #80).
Correct fix (decided)
int8/bigint should be modelled as JS bigint for BOTH the declared codec output type AND the runtime value:
PgInt8Codec.decode should return a JS bigint (parsing the node-postgres string), and its declared input/output types should be bigint (not number).
- This preserves full 64-bit precision and makes the declared type match the runtime value.
Affected tests
test/integration/test/sql-orm-client/ported-datatypes.test.ts — #68, #69 (round-trip) and #78, #79, #80 (int8 filters). They are marked it.fails referencing this issue; once fixed, update their assertions to bigint values and remove the .fails markers.
Provenance
Found while porting upstream data-type behaviours into prisma-next (tests-ports.md).
Summary
Reading an
int8/bigintcolumn returns a string at runtime, while the codec's declared output type isnumber. This is a silent type-soundness bug: every consumer seesnumberin TypeScript but receives astringvalue.Evidence
PgInt8Codec(packages/3-targets/3-targets/postgres/src/core/codecs.ts) is declared with wire/input typenumberanddecode(wire: number): Promise<number>as a bare pass-through (no coercion).CodecTypes['pg/int8@1']['output']therefore resolves tonumber, and generated contracts declarebigint-backed fields asnumber | null.int8/bigintcolumns as strings (to avoid >2^53 precision loss). The pass-throughdecodereturns that string verbatim.Result:
create({ big: 10000000000 })then read yields"10000000000"(string), not10000000000(number).Reproduction
Round-trip any
BigIntfield and compare the read-back value: it is a string, though typednumber.Observed in the test-porting integration tests
ported-datatypes.test.ts(entries #68, #69, #78, #79, #80).Correct fix (decided)
int8/bigintshould be modelled as JSbigintfor BOTH the declared codec output type AND the runtime value:PgInt8Codec.decodeshould return a JSbigint(parsing the node-postgres string), and its declared input/output types should bebigint(notnumber).Affected tests
test/integration/test/sql-orm-client/ported-datatypes.test.ts— #68, #69 (round-trip) and #78, #79, #80 (int8 filters). They are markedit.failsreferencing this issue; once fixed, update their assertions tobigintvalues and remove the.failsmarkers.Provenance
Found while porting upstream data-type behaviours into prisma-next (
tests-ports.md).