From 7b9e1d94b3915da5085cf0fccff392db380f54fe Mon Sep 17 00:00:00 2001 From: Karl Horky Date: Wed, 27 May 2026 19:17:03 +0200 Subject: [PATCH 1/6] Transform JSON / JSONB parameter keys --- cf/src/connection.js | 2 +- cf/src/types.js | 8 +++++- cjs/src/connection.js | 2 +- cjs/src/types.js | 8 +++++- cjs/tests/index.js | 61 ++++++++++++++++++++++++++++++++++++++++++ deno/src/connection.js | 2 +- deno/src/types.js | 8 +++++- deno/tests/index.js | 61 ++++++++++++++++++++++++++++++++++++++++++ deno/types/index.d.ts | 30 ++++++++++++++------- src/connection.js | 2 +- src/types.js | 8 +++++- tests/index.js | 61 ++++++++++++++++++++++++++++++++++++++++++ types/index.d.ts | 30 ++++++++++++++------- 13 files changed, 257 insertions(+), 26 deletions(-) diff --git a/cf/src/connection.js b/cf/src/connection.js index 8e79170a..e1c1f1d2 100644 --- a/cf/src/connection.js +++ b/cf/src/connection.js @@ -959,7 +959,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose type = types[i] parameters[i] = x = type in options.serializers - ? options.serializers[type](x) + ? options.serializers[type](x, options) : '' + x prev = b.i diff --git a/cf/src/types.js b/cf/src/types.js index aa2ead29..dab82b02 100644 --- a/cf/src/types.js +++ b/cf/src/types.js @@ -17,7 +17,7 @@ export const types = { json: { to: 114, from: [114, 3802], - serialize: x => JSON.stringify(x), + serialize: (x, options) => JSON.stringify(options && options.transform.value.to ? options.transform.value.to(x, { type: 3802 }) : x), parse: x => JSON.parse(x) }, boolean: { @@ -349,20 +349,26 @@ function createJsonTransform(fn) { toCamel.column = { from: toCamel } toCamel.value = { from: createJsonTransform(toCamel) } fromCamel.column = { to: fromCamel } +fromCamel.value = { to: createJsonTransform(fromCamel) } export const camel = { ...toCamel } camel.column.to = fromCamel +camel.value.to = fromCamel.value.to toPascal.column = { from: toPascal } toPascal.value = { from: createJsonTransform(toPascal) } fromPascal.column = { to: fromPascal } +fromPascal.value = { to: createJsonTransform(fromPascal) } export const pascal = { ...toPascal } pascal.column.to = fromPascal +pascal.value.to = fromPascal.value.to toKebab.column = { from: toKebab } toKebab.value = { from: createJsonTransform(toKebab) } fromKebab.column = { to: fromKebab } +fromKebab.value = { to: createJsonTransform(fromKebab) } export const kebab = { ...toKebab } kebab.column.to = fromKebab +kebab.value.to = fromKebab.value.to diff --git a/cjs/src/connection.js b/cjs/src/connection.js index 07f67167..4fe328aa 100644 --- a/cjs/src/connection.js +++ b/cjs/src/connection.js @@ -957,7 +957,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose type = types[i] parameters[i] = x = type in options.serializers - ? options.serializers[type](x) + ? options.serializers[type](x, options) : '' + x prev = b.i diff --git a/cjs/src/types.js b/cjs/src/types.js index 0578284c..79971466 100644 --- a/cjs/src/types.js +++ b/cjs/src/types.js @@ -16,7 +16,7 @@ const types = module.exports.types = { json: { to: 114, from: [114, 3802], - serialize: x => JSON.stringify(x), + serialize: (x, options) => JSON.stringify(options && options.transform.value.to ? options.transform.value.to(x, { type: 3802 }) : x), parse: x => JSON.parse(x) }, boolean: { @@ -348,20 +348,26 @@ function createJsonTransform(fn) { toCamel.column = { from: toCamel } toCamel.value = { from: createJsonTransform(toCamel) } fromCamel.column = { to: fromCamel } +fromCamel.value = { to: createJsonTransform(fromCamel) } const camel = module.exports.camel = { ...toCamel } camel.column.to = fromCamel +camel.value.to = fromCamel.value.to toPascal.column = { from: toPascal } toPascal.value = { from: createJsonTransform(toPascal) } fromPascal.column = { to: fromPascal } +fromPascal.value = { to: createJsonTransform(fromPascal) } const pascal = module.exports.pascal = { ...toPascal } pascal.column.to = fromPascal +pascal.value.to = fromPascal.value.to toKebab.column = { from: toKebab } toKebab.value = { from: createJsonTransform(toKebab) } fromKebab.column = { to: fromKebab } +fromKebab.value = { to: createJsonTransform(fromKebab) } const kebab = module.exports.kebab = { ...toKebab } kebab.column.to = fromKebab +kebab.value.to = fromKebab.value.to diff --git a/cjs/tests/index.js b/cjs/tests/index.js index 85d1aa46..44fd1ca5 100644 --- a/cjs/tests/index.js +++ b/cjs/tests/index.js @@ -106,6 +106,67 @@ t('Json', async() => { return ['hello,42', [x.a, x.b].join()] }) +t('Json transform parameter keys', async() => { + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql`select ${ sql.json({ firstName: 'Ada' }) }->>'first_name' as x`)[0].x + return ['Ada', x] +}) + +t('Json transform nested parameter keys', async() => { + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql` + select ${ sql.json({ userNames: [{ firstName: 'Ada' }, { firstName: 'Grace' }] }) }#>>'{user_names,1,first_name}' as x + `)[0].x + return ['Grace', x] +}) + +t('Json transform result keys', async() => { + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql`select '{"first_name":"Ada"}'::jsonb as x`)[0].x + return ['Ada', x.firstName] +}) + +t('Json without transform keeps parameter keys', async() => { + const x = (await sql`select ${ sql.json({ firstName: 'Ada' }) }->>'firstName' as x`)[0].x + return ['Ada', x] +}) + +t('Json transform implicit json parameters', async() => { + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql`select ${ { firstName: 'Ada' } }::jsonb->>'first_name' as x`)[0].x + return ['Ada', x] +}) + +t('Json transform implicit json type parameters', async() => { + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql`select ${ { firstName: 'Ada' } }::json->>'first_name' as x`)[0].x + return ['Ada', x] +}) + +t('Json transform typed json parameters', async() => { + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql`select ${ sql.typed({ firstName: 'Ada' }, 114) }->>'first_name' as x`)[0].x + return ['Ada', x] +}) + t('implicit json', async() => { const x = (await sql`select ${ { a: 'hello', b: 42 } }::json as x`)[0].x return ['hello,42', [x.a, x.b].join()] diff --git a/deno/src/connection.js b/deno/src/connection.js index 796725de..8f63335d 100644 --- a/deno/src/connection.js +++ b/deno/src/connection.js @@ -960,7 +960,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose type = types[i] parameters[i] = x = type in options.serializers - ? options.serializers[type](x) + ? options.serializers[type](x, options) : '' + x prev = b.i diff --git a/deno/src/types.js b/deno/src/types.js index ea0da6a2..54e99acd 100644 --- a/deno/src/types.js +++ b/deno/src/types.js @@ -17,7 +17,7 @@ export const types = { json: { to: 114, from: [114, 3802], - serialize: x => JSON.stringify(x), + serialize: (x, options) => JSON.stringify(options && options.transform.value.to ? options.transform.value.to(x, { type: 3802 }) : x), parse: x => JSON.parse(x) }, boolean: { @@ -349,20 +349,26 @@ function createJsonTransform(fn) { toCamel.column = { from: toCamel } toCamel.value = { from: createJsonTransform(toCamel) } fromCamel.column = { to: fromCamel } +fromCamel.value = { to: createJsonTransform(fromCamel) } export const camel = { ...toCamel } camel.column.to = fromCamel +camel.value.to = fromCamel.value.to toPascal.column = { from: toPascal } toPascal.value = { from: createJsonTransform(toPascal) } fromPascal.column = { to: fromPascal } +fromPascal.value = { to: createJsonTransform(fromPascal) } export const pascal = { ...toPascal } pascal.column.to = fromPascal +pascal.value.to = fromPascal.value.to toKebab.column = { from: toKebab } toKebab.value = { from: createJsonTransform(toKebab) } fromKebab.column = { to: fromKebab } +fromKebab.value = { to: createJsonTransform(fromKebab) } export const kebab = { ...toKebab } kebab.column.to = fromKebab +kebab.value.to = fromKebab.value.to diff --git a/deno/tests/index.js b/deno/tests/index.js index cc2a2518..f8cfe666 100644 --- a/deno/tests/index.js +++ b/deno/tests/index.js @@ -108,6 +108,67 @@ t('Json', async() => { return ['hello,42', [x.a, x.b].join()] }) +t('Json transform parameter keys', async() => { + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql`select ${ sql.json({ firstName: 'Ada' }) }->>'first_name' as x`)[0].x + return ['Ada', x] +}) + +t('Json transform nested parameter keys', async() => { + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql` + select ${ sql.json({ userNames: [{ firstName: 'Ada' }, { firstName: 'Grace' }] }) }#>>'{user_names,1,first_name}' as x + `)[0].x + return ['Grace', x] +}) + +t('Json transform result keys', async() => { + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql`select '{"first_name":"Ada"}'::jsonb as x`)[0].x + return ['Ada', x.firstName] +}) + +t('Json without transform keeps parameter keys', async() => { + const x = (await sql`select ${ sql.json({ firstName: 'Ada' }) }->>'firstName' as x`)[0].x + return ['Ada', x] +}) + +t('Json transform implicit json parameters', async() => { + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql`select ${ { firstName: 'Ada' } }::jsonb->>'first_name' as x`)[0].x + return ['Ada', x] +}) + +t('Json transform implicit json type parameters', async() => { + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql`select ${ { firstName: 'Ada' } }::json->>'first_name' as x`)[0].x + return ['Ada', x] +}) + +t('Json transform typed json parameters', async() => { + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql`select ${ sql.typed({ firstName: 'Ada' }, 114) }->>'first_name' as x`)[0].x + return ['Ada', x] +}) + t('implicit json', async() => { const x = (await sql`select ${ { a: 'hello', b: 42 } }::json as x`)[0].x return ['hello,42', [x.a, x.b].join()] diff --git a/deno/types/index.d.ts b/deno/types/index.d.ts index 85112eda..c363b1f6 100644 --- a/deno/types/index.d.ts +++ b/deno/types/index.d.ts @@ -236,7 +236,7 @@ declare namespace postgres { function toPascal(str: string): string; namespace toPascal { namespace column { function from(str: string): string; } - namespace value { function from(str: unknown, column: Column): string } + namespace value { function from(str: unknown, column: Column): unknown } } /** * Convert a PascalCase string to snake_case. @@ -246,6 +246,7 @@ declare namespace postgres { function fromPascal(str: string): string; namespace fromPascal { namespace column { function to(str: string): string } + namespace value { function to(str: unknown, column: Column): unknown } } /** * Convert snake_case to and from PascalCase. @@ -255,7 +256,10 @@ declare namespace postgres { function from(str: string): string; function to(str: string): string; } - namespace value { function from(str: unknown, column: Column): string } + namespace value { + function from(str: unknown, column: Column): unknown; + function to(str: unknown, column: Column): unknown; + } } /** * Convert a snake_case string to camelCase. @@ -265,7 +269,7 @@ declare namespace postgres { function toCamel(str: string): string; namespace toCamel { namespace column { function from(str: string): string; } - namespace value { function from(str: unknown, column: Column): string } + namespace value { function from(str: unknown, column: Column): unknown } } /** * Convert a camelCase string to snake_case. @@ -275,6 +279,7 @@ declare namespace postgres { function fromCamel(str: string): string; namespace fromCamel { namespace column { function to(str: string): string } + namespace value { function to(str: unknown, column: Column): unknown } } /** * Convert snake_case to and from camelCase. @@ -284,7 +289,10 @@ declare namespace postgres { function from(str: string): string; function to(str: string): string; } - namespace value { function from(str: unknown, column: Column): string } + namespace value { + function from(str: unknown, column: Column): unknown; + function to(str: unknown, column: Column): unknown; + } } /** * Convert a snake_case string to kebab-case. @@ -294,7 +302,7 @@ declare namespace postgres { function toKebab(str: string): string; namespace toKebab { namespace column { function from(str: string): string; } - namespace value { function from(str: unknown, column: Column): string } + namespace value { function from(str: unknown, column: Column): unknown } } /** * Convert a kebab-case string to snake_case. @@ -304,6 +312,7 @@ declare namespace postgres { function fromKebab(str: string): string; namespace fromKebab { namespace column { function to(str: string): string } + namespace value { function to(str: unknown, column: Column): unknown } } /** * Convert snake_case to and from kebab-case. @@ -313,7 +322,10 @@ declare namespace postgres { function from(str: string): string; function to(str: string): string; } - namespace value { function from(str: unknown, column: Column): string } + namespace value { + function from(str: unknown, column: Column): unknown; + function to(str: unknown, column: Column): unknown; + } } const BigInt: PostgresType; @@ -321,7 +333,7 @@ declare namespace postgres { interface PostgresType { to: number; from: number[]; - serialize: (value: T) => unknown; + serialize: (value: T, options?: ParsedOptions) => unknown; parse: (raw: any) => T; } @@ -386,7 +398,7 @@ declare namespace postgres { pass: null; /** @inheritdoc */ transform: Transform; - serializers: Record unknown>; + serializers: Record unknown>; parsers: Record unknown>; } @@ -404,7 +416,7 @@ declare namespace postgres { /** Transform function for values in result rows */ from: ((value: any, column?: Column) => any) | undefined; /** Transform function for interpolated values passed to tagged template literal */ - to: undefined; // (value: any) => any + to: ((value: any, column?: Column) => any) | undefined; }; row: { /** Transform function for entire result rows */ diff --git a/src/connection.js b/src/connection.js index 1b1cccde..858535c2 100644 --- a/src/connection.js +++ b/src/connection.js @@ -957,7 +957,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose type = types[i] parameters[i] = x = type in options.serializers - ? options.serializers[type](x) + ? options.serializers[type](x, options) : '' + x prev = b.i diff --git a/src/types.js b/src/types.js index 7c7c2b93..ce12ef74 100644 --- a/src/types.js +++ b/src/types.js @@ -16,7 +16,7 @@ export const types = { json: { to: 114, from: [114, 3802], - serialize: x => JSON.stringify(x), + serialize: (x, options) => JSON.stringify(options && options.transform.value.to ? options.transform.value.to(x, { type: 3802 }) : x), parse: x => JSON.parse(x) }, boolean: { @@ -348,20 +348,26 @@ function createJsonTransform(fn) { toCamel.column = { from: toCamel } toCamel.value = { from: createJsonTransform(toCamel) } fromCamel.column = { to: fromCamel } +fromCamel.value = { to: createJsonTransform(fromCamel) } export const camel = { ...toCamel } camel.column.to = fromCamel +camel.value.to = fromCamel.value.to toPascal.column = { from: toPascal } toPascal.value = { from: createJsonTransform(toPascal) } fromPascal.column = { to: fromPascal } +fromPascal.value = { to: createJsonTransform(fromPascal) } export const pascal = { ...toPascal } pascal.column.to = fromPascal +pascal.value.to = fromPascal.value.to toKebab.column = { from: toKebab } toKebab.value = { from: createJsonTransform(toKebab) } fromKebab.column = { to: fromKebab } +fromKebab.value = { to: createJsonTransform(fromKebab) } export const kebab = { ...toKebab } kebab.column.to = fromKebab +kebab.value.to = fromKebab.value.to diff --git a/tests/index.js b/tests/index.js index 23e6c4d4..0687cdac 100644 --- a/tests/index.js +++ b/tests/index.js @@ -106,6 +106,67 @@ t('Json', async() => { return ['hello,42', [x.a, x.b].join()] }) +t('Json transform parameter keys', async() => { + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql`select ${ sql.json({ firstName: 'Ada' }) }->>'first_name' as x`)[0].x + return ['Ada', x] +}) + +t('Json transform nested parameter keys', async() => { + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql` + select ${ sql.json({ userNames: [{ firstName: 'Ada' }, { firstName: 'Grace' }] }) }#>>'{user_names,1,first_name}' as x + `)[0].x + return ['Grace', x] +}) + +t('Json transform result keys', async() => { + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql`select '{"first_name":"Ada"}'::jsonb as x`)[0].x + return ['Ada', x.firstName] +}) + +t('Json without transform keeps parameter keys', async() => { + const x = (await sql`select ${ sql.json({ firstName: 'Ada' }) }->>'firstName' as x`)[0].x + return ['Ada', x] +}) + +t('Json transform implicit json parameters', async() => { + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql`select ${ { firstName: 'Ada' } }::jsonb->>'first_name' as x`)[0].x + return ['Ada', x] +}) + +t('Json transform implicit json type parameters', async() => { + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql`select ${ { firstName: 'Ada' } }::json->>'first_name' as x`)[0].x + return ['Ada', x] +}) + +t('Json transform typed json parameters', async() => { + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql`select ${ sql.typed({ firstName: 'Ada' }, 114) }->>'first_name' as x`)[0].x + return ['Ada', x] +}) + t('implicit json', async() => { const x = (await sql`select ${ { a: 'hello', b: 42 } }::json as x`)[0].x return ['hello,42', [x.a, x.b].join()] diff --git a/types/index.d.ts b/types/index.d.ts index 13c3432f..627d3ebd 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -234,7 +234,7 @@ declare namespace postgres { function toPascal(str: string): string; namespace toPascal { namespace column { function from(str: string): string; } - namespace value { function from(str: unknown, column: Column): string } + namespace value { function from(str: unknown, column: Column): unknown } } /** * Convert a PascalCase string to snake_case. @@ -244,6 +244,7 @@ declare namespace postgres { function fromPascal(str: string): string; namespace fromPascal { namespace column { function to(str: string): string } + namespace value { function to(str: unknown, column: Column): unknown } } /** * Convert snake_case to and from PascalCase. @@ -253,7 +254,10 @@ declare namespace postgres { function from(str: string): string; function to(str: string): string; } - namespace value { function from(str: unknown, column: Column): string } + namespace value { + function from(str: unknown, column: Column): unknown; + function to(str: unknown, column: Column): unknown; + } } /** * Convert a snake_case string to camelCase. @@ -263,7 +267,7 @@ declare namespace postgres { function toCamel(str: string): string; namespace toCamel { namespace column { function from(str: string): string; } - namespace value { function from(str: unknown, column: Column): string } + namespace value { function from(str: unknown, column: Column): unknown } } /** * Convert a camelCase string to snake_case. @@ -273,6 +277,7 @@ declare namespace postgres { function fromCamel(str: string): string; namespace fromCamel { namespace column { function to(str: string): string } + namespace value { function to(str: unknown, column: Column): unknown } } /** * Convert snake_case to and from camelCase. @@ -282,7 +287,10 @@ declare namespace postgres { function from(str: string): string; function to(str: string): string; } - namespace value { function from(str: unknown, column: Column): string } + namespace value { + function from(str: unknown, column: Column): unknown; + function to(str: unknown, column: Column): unknown; + } } /** * Convert a snake_case string to kebab-case. @@ -292,7 +300,7 @@ declare namespace postgres { function toKebab(str: string): string; namespace toKebab { namespace column { function from(str: string): string; } - namespace value { function from(str: unknown, column: Column): string } + namespace value { function from(str: unknown, column: Column): unknown } } /** * Convert a kebab-case string to snake_case. @@ -302,6 +310,7 @@ declare namespace postgres { function fromKebab(str: string): string; namespace fromKebab { namespace column { function to(str: string): string } + namespace value { function to(str: unknown, column: Column): unknown } } /** * Convert snake_case to and from kebab-case. @@ -311,7 +320,10 @@ declare namespace postgres { function from(str: string): string; function to(str: string): string; } - namespace value { function from(str: unknown, column: Column): string } + namespace value { + function from(str: unknown, column: Column): unknown; + function to(str: unknown, column: Column): unknown; + } } const BigInt: PostgresType; @@ -319,7 +331,7 @@ declare namespace postgres { interface PostgresType { to: number; from: number[]; - serialize: (value: T) => unknown; + serialize: (value: T, options?: ParsedOptions) => unknown; parse: (raw: any) => T; } @@ -384,7 +396,7 @@ declare namespace postgres { pass: null; /** @inheritdoc */ transform: Transform; - serializers: Record unknown>; + serializers: Record unknown>; parsers: Record unknown>; } @@ -402,7 +414,7 @@ declare namespace postgres { /** Transform function for values in result rows */ from: ((value: any, column?: Column) => any) | undefined; /** Transform function for interpolated values passed to tagged template literal */ - to: undefined; // (value: any) => any + to: ((value: any, column?: Column) => any) | undefined; }; row: { /** Transform function for entire result rows */ From 7c2916c199330a53f9d15ec7303f2fa49becfbe1 Mon Sep 17 00:00:00 2001 From: Karl Horky Date: Wed, 27 May 2026 19:28:44 +0200 Subject: [PATCH 2/6] Make test data consistent with existing test data --- cjs/tests/index.js | 28 ++++++++++++++-------------- deno/tests/index.js | 28 ++++++++++++++-------------- tests/index.js | 28 ++++++++++++++-------------- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/cjs/tests/index.js b/cjs/tests/index.js index 44fd1ca5..f2d440a0 100644 --- a/cjs/tests/index.js +++ b/cjs/tests/index.js @@ -111,8 +111,8 @@ t('Json transform parameter keys', async() => { ...options, transform: postgres.camel }) - const x = (await sql`select ${ sql.json({ firstName: 'Ada' }) }->>'first_name' as x`)[0].x - return ['Ada', x] + const x = (await sql`select ${ sql.json({ aTest: 1 }) }->>'a_test' as x`)[0].x + return ['1', x] }) t('Json transform nested parameter keys', async() => { @@ -121,9 +121,9 @@ t('Json transform nested parameter keys', async() => { transform: postgres.camel }) const x = (await sql` - select ${ sql.json({ userNames: [{ firstName: 'Ada' }, { firstName: 'Grace' }] }) }#>>'{user_names,1,first_name}' as x + select ${ sql.json({ aTest: [{ bTest: 1 }, { bTest: 2 }] }) }#>>'{a_test,1,b_test}' as x `)[0].x - return ['Grace', x] + return ['2', x] }) t('Json transform result keys', async() => { @@ -131,13 +131,13 @@ t('Json transform result keys', async() => { ...options, transform: postgres.camel }) - const x = (await sql`select '{"first_name":"Ada"}'::jsonb as x`)[0].x - return ['Ada', x.firstName] + const x = (await sql`select '{"a_test":1}'::jsonb as x`)[0].x + return [1, x.aTest] }) t('Json without transform keeps parameter keys', async() => { - const x = (await sql`select ${ sql.json({ firstName: 'Ada' }) }->>'firstName' as x`)[0].x - return ['Ada', x] + const x = (await sql`select ${ sql.json({ aTest: 1 }) }->>'aTest' as x`)[0].x + return ['1', x] }) t('Json transform implicit json parameters', async() => { @@ -145,8 +145,8 @@ t('Json transform implicit json parameters', async() => { ...options, transform: postgres.camel }) - const x = (await sql`select ${ { firstName: 'Ada' } }::jsonb->>'first_name' as x`)[0].x - return ['Ada', x] + const x = (await sql`select ${ { aTest: 1 } }::jsonb->>'a_test' as x`)[0].x + return ['1', x] }) t('Json transform implicit json type parameters', async() => { @@ -154,8 +154,8 @@ t('Json transform implicit json type parameters', async() => { ...options, transform: postgres.camel }) - const x = (await sql`select ${ { firstName: 'Ada' } }::json->>'first_name' as x`)[0].x - return ['Ada', x] + const x = (await sql`select ${ { aTest: 1 } }::json->>'a_test' as x`)[0].x + return ['1', x] }) t('Json transform typed json parameters', async() => { @@ -163,8 +163,8 @@ t('Json transform typed json parameters', async() => { ...options, transform: postgres.camel }) - const x = (await sql`select ${ sql.typed({ firstName: 'Ada' }, 114) }->>'first_name' as x`)[0].x - return ['Ada', x] + const x = (await sql`select ${ sql.typed({ aTest: 1 }, 114) }->>'a_test' as x`)[0].x + return ['1', x] }) t('implicit json', async() => { diff --git a/deno/tests/index.js b/deno/tests/index.js index f8cfe666..9442e1eb 100644 --- a/deno/tests/index.js +++ b/deno/tests/index.js @@ -113,8 +113,8 @@ t('Json transform parameter keys', async() => { ...options, transform: postgres.camel }) - const x = (await sql`select ${ sql.json({ firstName: 'Ada' }) }->>'first_name' as x`)[0].x - return ['Ada', x] + const x = (await sql`select ${ sql.json({ aTest: 1 }) }->>'a_test' as x`)[0].x + return ['1', x] }) t('Json transform nested parameter keys', async() => { @@ -123,9 +123,9 @@ t('Json transform nested parameter keys', async() => { transform: postgres.camel }) const x = (await sql` - select ${ sql.json({ userNames: [{ firstName: 'Ada' }, { firstName: 'Grace' }] }) }#>>'{user_names,1,first_name}' as x + select ${ sql.json({ aTest: [{ bTest: 1 }, { bTest: 2 }] }) }#>>'{a_test,1,b_test}' as x `)[0].x - return ['Grace', x] + return ['2', x] }) t('Json transform result keys', async() => { @@ -133,13 +133,13 @@ t('Json transform result keys', async() => { ...options, transform: postgres.camel }) - const x = (await sql`select '{"first_name":"Ada"}'::jsonb as x`)[0].x - return ['Ada', x.firstName] + const x = (await sql`select '{"a_test":1}'::jsonb as x`)[0].x + return [1, x.aTest] }) t('Json without transform keeps parameter keys', async() => { - const x = (await sql`select ${ sql.json({ firstName: 'Ada' }) }->>'firstName' as x`)[0].x - return ['Ada', x] + const x = (await sql`select ${ sql.json({ aTest: 1 }) }->>'aTest' as x`)[0].x + return ['1', x] }) t('Json transform implicit json parameters', async() => { @@ -147,8 +147,8 @@ t('Json transform implicit json parameters', async() => { ...options, transform: postgres.camel }) - const x = (await sql`select ${ { firstName: 'Ada' } }::jsonb->>'first_name' as x`)[0].x - return ['Ada', x] + const x = (await sql`select ${ { aTest: 1 } }::jsonb->>'a_test' as x`)[0].x + return ['1', x] }) t('Json transform implicit json type parameters', async() => { @@ -156,8 +156,8 @@ t('Json transform implicit json type parameters', async() => { ...options, transform: postgres.camel }) - const x = (await sql`select ${ { firstName: 'Ada' } }::json->>'first_name' as x`)[0].x - return ['Ada', x] + const x = (await sql`select ${ { aTest: 1 } }::json->>'a_test' as x`)[0].x + return ['1', x] }) t('Json transform typed json parameters', async() => { @@ -165,8 +165,8 @@ t('Json transform typed json parameters', async() => { ...options, transform: postgres.camel }) - const x = (await sql`select ${ sql.typed({ firstName: 'Ada' }, 114) }->>'first_name' as x`)[0].x - return ['Ada', x] + const x = (await sql`select ${ sql.typed({ aTest: 1 }, 114) }->>'a_test' as x`)[0].x + return ['1', x] }) t('implicit json', async() => { diff --git a/tests/index.js b/tests/index.js index 0687cdac..dd873ff8 100644 --- a/tests/index.js +++ b/tests/index.js @@ -111,8 +111,8 @@ t('Json transform parameter keys', async() => { ...options, transform: postgres.camel }) - const x = (await sql`select ${ sql.json({ firstName: 'Ada' }) }->>'first_name' as x`)[0].x - return ['Ada', x] + const x = (await sql`select ${ sql.json({ aTest: 1 }) }->>'a_test' as x`)[0].x + return ['1', x] }) t('Json transform nested parameter keys', async() => { @@ -121,9 +121,9 @@ t('Json transform nested parameter keys', async() => { transform: postgres.camel }) const x = (await sql` - select ${ sql.json({ userNames: [{ firstName: 'Ada' }, { firstName: 'Grace' }] }) }#>>'{user_names,1,first_name}' as x + select ${ sql.json({ aTest: [{ bTest: 1 }, { bTest: 2 }] }) }#>>'{a_test,1,b_test}' as x `)[0].x - return ['Grace', x] + return ['2', x] }) t('Json transform result keys', async() => { @@ -131,13 +131,13 @@ t('Json transform result keys', async() => { ...options, transform: postgres.camel }) - const x = (await sql`select '{"first_name":"Ada"}'::jsonb as x`)[0].x - return ['Ada', x.firstName] + const x = (await sql`select '{"a_test":1}'::jsonb as x`)[0].x + return [1, x.aTest] }) t('Json without transform keeps parameter keys', async() => { - const x = (await sql`select ${ sql.json({ firstName: 'Ada' }) }->>'firstName' as x`)[0].x - return ['Ada', x] + const x = (await sql`select ${ sql.json({ aTest: 1 }) }->>'aTest' as x`)[0].x + return ['1', x] }) t('Json transform implicit json parameters', async() => { @@ -145,8 +145,8 @@ t('Json transform implicit json parameters', async() => { ...options, transform: postgres.camel }) - const x = (await sql`select ${ { firstName: 'Ada' } }::jsonb->>'first_name' as x`)[0].x - return ['Ada', x] + const x = (await sql`select ${ { aTest: 1 } }::jsonb->>'a_test' as x`)[0].x + return ['1', x] }) t('Json transform implicit json type parameters', async() => { @@ -154,8 +154,8 @@ t('Json transform implicit json type parameters', async() => { ...options, transform: postgres.camel }) - const x = (await sql`select ${ { firstName: 'Ada' } }::json->>'first_name' as x`)[0].x - return ['Ada', x] + const x = (await sql`select ${ { aTest: 1 } }::json->>'a_test' as x`)[0].x + return ['1', x] }) t('Json transform typed json parameters', async() => { @@ -163,8 +163,8 @@ t('Json transform typed json parameters', async() => { ...options, transform: postgres.camel }) - const x = (await sql`select ${ sql.typed({ firstName: 'Ada' }, 114) }->>'first_name' as x`)[0].x - return ['Ada', x] + const x = (await sql`select ${ sql.typed({ aTest: 1 }, 114) }->>'a_test' as x`)[0].x + return ['1', x] }) t('implicit json', async() => { From 43bb705ff1598d97cfd624b8e614013e67171562 Mon Sep 17 00:00:00 2001 From: Karl Horky Date: Wed, 27 May 2026 21:41:30 +0200 Subject: [PATCH 3/6] Preserve non-plain JSON parameter values --- cf/src/connection.js | 2 +- cf/src/types.js | 6 ++++-- cjs/src/connection.js | 2 +- cjs/src/types.js | 6 ++++-- cjs/tests/index.js | 10 ++++++++++ deno/src/connection.js | 2 +- deno/src/types.js | 6 ++++-- deno/tests/index.js | 10 ++++++++++ deno/types/index.d.ts | 4 ++-- src/connection.js | 2 +- src/types.js | 6 ++++-- tests/index.js | 10 ++++++++++ types/index.d.ts | 4 ++-- 13 files changed, 54 insertions(+), 16 deletions(-) diff --git a/cf/src/connection.js b/cf/src/connection.js index e1c1f1d2..bd9b9a58 100644 --- a/cf/src/connection.js +++ b/cf/src/connection.js @@ -959,7 +959,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose type = types[i] parameters[i] = x = type in options.serializers - ? options.serializers[type](x, options) + ? options.serializers[type](x, options, type) : '' + x prev = b.i diff --git a/cf/src/types.js b/cf/src/types.js index dab82b02..79b642ad 100644 --- a/cf/src/types.js +++ b/cf/src/types.js @@ -17,7 +17,7 @@ export const types = { json: { to: 114, from: [114, 3802], - serialize: (x, options) => JSON.stringify(options && options.transform.value.to ? options.transform.value.to(x, { type: 3802 }) : x), + serialize: (x, options, type) => JSON.stringify(options && options.transform.value.to ? options.transform.value.to(x, { type }) : x), parse: x => JSON.parse(x) }, boolean: { @@ -341,7 +341,9 @@ function createJsonTransform(fn) { return typeof x === 'object' && x !== null && (column.type === 114 || column.type === 3802) ? Array.isArray(x) ? x.map(x => jsonTransform(x, column)) - : Object.entries(x).reduce((acc, [k, v]) => Object.assign(acc, { [fn(k)]: jsonTransform(v, column) }), {}) + : Object.getPrototypeOf(x) === Object.prototype || Object.getPrototypeOf(x) === null + ? Object.entries(x).reduce((acc, [k, v]) => Object.assign(acc, { [fn(k)]: jsonTransform(v, column) }), {}) + : x : x } } diff --git a/cjs/src/connection.js b/cjs/src/connection.js index 4fe328aa..a120bd0c 100644 --- a/cjs/src/connection.js +++ b/cjs/src/connection.js @@ -957,7 +957,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose type = types[i] parameters[i] = x = type in options.serializers - ? options.serializers[type](x, options) + ? options.serializers[type](x, options, type) : '' + x prev = b.i diff --git a/cjs/src/types.js b/cjs/src/types.js index 79971466..67facb87 100644 --- a/cjs/src/types.js +++ b/cjs/src/types.js @@ -16,7 +16,7 @@ const types = module.exports.types = { json: { to: 114, from: [114, 3802], - serialize: (x, options) => JSON.stringify(options && options.transform.value.to ? options.transform.value.to(x, { type: 3802 }) : x), + serialize: (x, options, type) => JSON.stringify(options && options.transform.value.to ? options.transform.value.to(x, { type }) : x), parse: x => JSON.parse(x) }, boolean: { @@ -340,7 +340,9 @@ function createJsonTransform(fn) { return typeof x === 'object' && x !== null && (column.type === 114 || column.type === 3802) ? Array.isArray(x) ? x.map(x => jsonTransform(x, column)) - : Object.entries(x).reduce((acc, [k, v]) => Object.assign(acc, { [fn(k)]: jsonTransform(v, column) }), {}) + : Object.getPrototypeOf(x) === Object.prototype || Object.getPrototypeOf(x) === null + ? Object.entries(x).reduce((acc, [k, v]) => Object.assign(acc, { [fn(k)]: jsonTransform(v, column) }), {}) + : x : x } } diff --git a/cjs/tests/index.js b/cjs/tests/index.js index f2d440a0..97378295 100644 --- a/cjs/tests/index.js +++ b/cjs/tests/index.js @@ -167,6 +167,16 @@ t('Json transform typed json parameters', async() => { return ['1', x] }) +t('Json transform toJSON parameter values', async() => { + const now = new Date() + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql`select ${ sql.json({ aTest: now }) }->>'a_test' as x`)[0].x + return [now.toJSON(), x] +}) + t('implicit json', async() => { const x = (await sql`select ${ { a: 'hello', b: 42 } }::json as x`)[0].x return ['hello,42', [x.a, x.b].join()] diff --git a/deno/src/connection.js b/deno/src/connection.js index 8f63335d..7dd619de 100644 --- a/deno/src/connection.js +++ b/deno/src/connection.js @@ -960,7 +960,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose type = types[i] parameters[i] = x = type in options.serializers - ? options.serializers[type](x, options) + ? options.serializers[type](x, options, type) : '' + x prev = b.i diff --git a/deno/src/types.js b/deno/src/types.js index 54e99acd..0167d171 100644 --- a/deno/src/types.js +++ b/deno/src/types.js @@ -17,7 +17,7 @@ export const types = { json: { to: 114, from: [114, 3802], - serialize: (x, options) => JSON.stringify(options && options.transform.value.to ? options.transform.value.to(x, { type: 3802 }) : x), + serialize: (x, options, type) => JSON.stringify(options && options.transform.value.to ? options.transform.value.to(x, { type }) : x), parse: x => JSON.parse(x) }, boolean: { @@ -341,7 +341,9 @@ function createJsonTransform(fn) { return typeof x === 'object' && x !== null && (column.type === 114 || column.type === 3802) ? Array.isArray(x) ? x.map(x => jsonTransform(x, column)) - : Object.entries(x).reduce((acc, [k, v]) => Object.assign(acc, { [fn(k)]: jsonTransform(v, column) }), {}) + : Object.getPrototypeOf(x) === Object.prototype || Object.getPrototypeOf(x) === null + ? Object.entries(x).reduce((acc, [k, v]) => Object.assign(acc, { [fn(k)]: jsonTransform(v, column) }), {}) + : x : x } } diff --git a/deno/tests/index.js b/deno/tests/index.js index 9442e1eb..f957f6b5 100644 --- a/deno/tests/index.js +++ b/deno/tests/index.js @@ -169,6 +169,16 @@ t('Json transform typed json parameters', async() => { return ['1', x] }) +t('Json transform toJSON parameter values', async() => { + const now = new Date() + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql`select ${ sql.json({ aTest: now }) }->>'a_test' as x`)[0].x + return [now.toJSON(), x] +}) + t('implicit json', async() => { const x = (await sql`select ${ { a: 'hello', b: 42 } }::json as x`)[0].x return ['hello,42', [x.a, x.b].join()] diff --git a/deno/types/index.d.ts b/deno/types/index.d.ts index c363b1f6..608d4c19 100644 --- a/deno/types/index.d.ts +++ b/deno/types/index.d.ts @@ -333,7 +333,7 @@ declare namespace postgres { interface PostgresType { to: number; from: number[]; - serialize: (value: T, options?: ParsedOptions) => unknown; + serialize: (value: T, options?: ParsedOptions, type?: number) => unknown; parse: (raw: any) => T; } @@ -398,7 +398,7 @@ declare namespace postgres { pass: null; /** @inheritdoc */ transform: Transform; - serializers: Record unknown>; + serializers: Record unknown>; parsers: Record unknown>; } diff --git a/src/connection.js b/src/connection.js index 858535c2..f126036f 100644 --- a/src/connection.js +++ b/src/connection.js @@ -957,7 +957,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose type = types[i] parameters[i] = x = type in options.serializers - ? options.serializers[type](x, options) + ? options.serializers[type](x, options, type) : '' + x prev = b.i diff --git a/src/types.js b/src/types.js index ce12ef74..20f775df 100644 --- a/src/types.js +++ b/src/types.js @@ -16,7 +16,7 @@ export const types = { json: { to: 114, from: [114, 3802], - serialize: (x, options) => JSON.stringify(options && options.transform.value.to ? options.transform.value.to(x, { type: 3802 }) : x), + serialize: (x, options, type) => JSON.stringify(options && options.transform.value.to ? options.transform.value.to(x, { type }) : x), parse: x => JSON.parse(x) }, boolean: { @@ -340,7 +340,9 @@ function createJsonTransform(fn) { return typeof x === 'object' && x !== null && (column.type === 114 || column.type === 3802) ? Array.isArray(x) ? x.map(x => jsonTransform(x, column)) - : Object.entries(x).reduce((acc, [k, v]) => Object.assign(acc, { [fn(k)]: jsonTransform(v, column) }), {}) + : Object.getPrototypeOf(x) === Object.prototype || Object.getPrototypeOf(x) === null + ? Object.entries(x).reduce((acc, [k, v]) => Object.assign(acc, { [fn(k)]: jsonTransform(v, column) }), {}) + : x : x } } diff --git a/tests/index.js b/tests/index.js index dd873ff8..fbf9f339 100644 --- a/tests/index.js +++ b/tests/index.js @@ -167,6 +167,16 @@ t('Json transform typed json parameters', async() => { return ['1', x] }) +t('Json transform toJSON parameter values', async() => { + const now = new Date() + const sql = postgres({ + ...options, + transform: postgres.camel + }) + const x = (await sql`select ${ sql.json({ aTest: now }) }->>'a_test' as x`)[0].x + return [now.toJSON(), x] +}) + t('implicit json', async() => { const x = (await sql`select ${ { a: 'hello', b: 42 } }::json as x`)[0].x return ['hello,42', [x.a, x.b].join()] diff --git a/types/index.d.ts b/types/index.d.ts index 627d3ebd..3a2c025d 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -331,7 +331,7 @@ declare namespace postgres { interface PostgresType { to: number; from: number[]; - serialize: (value: T, options?: ParsedOptions) => unknown; + serialize: (value: T, options?: ParsedOptions, type?: number) => unknown; parse: (raw: any) => T; } @@ -396,7 +396,7 @@ declare namespace postgres { pass: null; /** @inheritdoc */ transform: Transform; - serializers: Record unknown>; + serializers: Record unknown>; parsers: Record unknown>; } From e3059aa718dab4db8e6af9caecb4d9f2637acf36 Mon Sep 17 00:00:00 2001 From: Karl Horky Date: Wed, 27 May 2026 22:11:05 +0200 Subject: [PATCH 4/6] Apply value transforms before serialization --- cf/src/connection.js | 3 ++- cf/src/types.js | 2 +- cjs/src/connection.js | 3 ++- cjs/src/types.js | 2 +- deno/src/connection.js | 3 ++- deno/src/types.js | 2 +- deno/types/index.d.ts | 4 ++-- src/connection.js | 3 ++- src/types.js | 2 +- types/index.d.ts | 4 ++-- 10 files changed, 16 insertions(+), 12 deletions(-) diff --git a/cf/src/connection.js b/cf/src/connection.js index bd9b9a58..1b768cfc 100644 --- a/cf/src/connection.js +++ b/cf/src/connection.js @@ -958,8 +958,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose return b.i32(0xFFFFFFFF) type = types[i] + x = options.transform.value.to ? options.transform.value.to(x, { type }) : x parameters[i] = x = type in options.serializers - ? options.serializers[type](x, options, type) + ? options.serializers[type](x) : '' + x prev = b.i diff --git a/cf/src/types.js b/cf/src/types.js index 79b642ad..712ee1b4 100644 --- a/cf/src/types.js +++ b/cf/src/types.js @@ -17,7 +17,7 @@ export const types = { json: { to: 114, from: [114, 3802], - serialize: (x, options, type) => JSON.stringify(options && options.transform.value.to ? options.transform.value.to(x, { type }) : x), + serialize: x => JSON.stringify(x), parse: x => JSON.parse(x) }, boolean: { diff --git a/cjs/src/connection.js b/cjs/src/connection.js index a120bd0c..4ce3f9b3 100644 --- a/cjs/src/connection.js +++ b/cjs/src/connection.js @@ -956,8 +956,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose return b.i32(0xFFFFFFFF) type = types[i] + x = options.transform.value.to ? options.transform.value.to(x, { type }) : x parameters[i] = x = type in options.serializers - ? options.serializers[type](x, options, type) + ? options.serializers[type](x) : '' + x prev = b.i diff --git a/cjs/src/types.js b/cjs/src/types.js index 67facb87..44a35068 100644 --- a/cjs/src/types.js +++ b/cjs/src/types.js @@ -16,7 +16,7 @@ const types = module.exports.types = { json: { to: 114, from: [114, 3802], - serialize: (x, options, type) => JSON.stringify(options && options.transform.value.to ? options.transform.value.to(x, { type }) : x), + serialize: x => JSON.stringify(x), parse: x => JSON.parse(x) }, boolean: { diff --git a/deno/src/connection.js b/deno/src/connection.js index 7dd619de..bce667e3 100644 --- a/deno/src/connection.js +++ b/deno/src/connection.js @@ -959,8 +959,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose return b.i32(0xFFFFFFFF) type = types[i] + x = options.transform.value.to ? options.transform.value.to(x, { type }) : x parameters[i] = x = type in options.serializers - ? options.serializers[type](x, options, type) + ? options.serializers[type](x) : '' + x prev = b.i diff --git a/deno/src/types.js b/deno/src/types.js index 0167d171..6e57930b 100644 --- a/deno/src/types.js +++ b/deno/src/types.js @@ -17,7 +17,7 @@ export const types = { json: { to: 114, from: [114, 3802], - serialize: (x, options, type) => JSON.stringify(options && options.transform.value.to ? options.transform.value.to(x, { type }) : x), + serialize: x => JSON.stringify(x), parse: x => JSON.parse(x) }, boolean: { diff --git a/deno/types/index.d.ts b/deno/types/index.d.ts index 608d4c19..36613696 100644 --- a/deno/types/index.d.ts +++ b/deno/types/index.d.ts @@ -333,7 +333,7 @@ declare namespace postgres { interface PostgresType { to: number; from: number[]; - serialize: (value: T, options?: ParsedOptions, type?: number) => unknown; + serialize: (value: T) => unknown; parse: (raw: any) => T; } @@ -398,7 +398,7 @@ declare namespace postgres { pass: null; /** @inheritdoc */ transform: Transform; - serializers: Record unknown>; + serializers: Record unknown>; parsers: Record unknown>; } diff --git a/src/connection.js b/src/connection.js index f126036f..0513ce4e 100644 --- a/src/connection.js +++ b/src/connection.js @@ -956,8 +956,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose return b.i32(0xFFFFFFFF) type = types[i] + x = options.transform.value.to ? options.transform.value.to(x, { type }) : x parameters[i] = x = type in options.serializers - ? options.serializers[type](x, options, type) + ? options.serializers[type](x) : '' + x prev = b.i diff --git a/src/types.js b/src/types.js index 20f775df..58ce74cb 100644 --- a/src/types.js +++ b/src/types.js @@ -16,7 +16,7 @@ export const types = { json: { to: 114, from: [114, 3802], - serialize: (x, options, type) => JSON.stringify(options && options.transform.value.to ? options.transform.value.to(x, { type }) : x), + serialize: x => JSON.stringify(x), parse: x => JSON.parse(x) }, boolean: { diff --git a/types/index.d.ts b/types/index.d.ts index 3a2c025d..c165c452 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -331,7 +331,7 @@ declare namespace postgres { interface PostgresType { to: number; from: number[]; - serialize: (value: T, options?: ParsedOptions, type?: number) => unknown; + serialize: (value: T) => unknown; parse: (raw: any) => T; } @@ -396,7 +396,7 @@ declare namespace postgres { pass: null; /** @inheritdoc */ transform: Transform; - serializers: Record unknown>; + serializers: Record unknown>; parsers: Record unknown>; } From 690f730802493226888b933e681c36673bef5de6 Mon Sep 17 00:00:00 2001 From: Karl Horky Date: Wed, 27 May 2026 22:22:08 +0200 Subject: [PATCH 5/6] Move negative test up --- cjs/tests/index.js | 10 +++++----- deno/tests/index.js | 10 +++++----- tests/index.js | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/cjs/tests/index.js b/cjs/tests/index.js index 97378295..52d737a9 100644 --- a/cjs/tests/index.js +++ b/cjs/tests/index.js @@ -115,6 +115,11 @@ t('Json transform parameter keys', async() => { return ['1', x] }) +t('Json without transform keeps parameter keys', async() => { + const x = (await sql`select ${ sql.json({ aTest: 1 }) }->>'aTest' as x`)[0].x + return ['1', x] +}) + t('Json transform nested parameter keys', async() => { const sql = postgres({ ...options, @@ -135,11 +140,6 @@ t('Json transform result keys', async() => { return [1, x.aTest] }) -t('Json without transform keeps parameter keys', async() => { - const x = (await sql`select ${ sql.json({ aTest: 1 }) }->>'aTest' as x`)[0].x - return ['1', x] -}) - t('Json transform implicit json parameters', async() => { const sql = postgres({ ...options, diff --git a/deno/tests/index.js b/deno/tests/index.js index f957f6b5..2e49c075 100644 --- a/deno/tests/index.js +++ b/deno/tests/index.js @@ -117,6 +117,11 @@ t('Json transform parameter keys', async() => { return ['1', x] }) +t('Json without transform keeps parameter keys', async() => { + const x = (await sql`select ${ sql.json({ aTest: 1 }) }->>'aTest' as x`)[0].x + return ['1', x] +}) + t('Json transform nested parameter keys', async() => { const sql = postgres({ ...options, @@ -137,11 +142,6 @@ t('Json transform result keys', async() => { return [1, x.aTest] }) -t('Json without transform keeps parameter keys', async() => { - const x = (await sql`select ${ sql.json({ aTest: 1 }) }->>'aTest' as x`)[0].x - return ['1', x] -}) - t('Json transform implicit json parameters', async() => { const sql = postgres({ ...options, diff --git a/tests/index.js b/tests/index.js index fbf9f339..58a2cc1d 100644 --- a/tests/index.js +++ b/tests/index.js @@ -115,6 +115,11 @@ t('Json transform parameter keys', async() => { return ['1', x] }) +t('Json without transform keeps parameter keys', async() => { + const x = (await sql`select ${ sql.json({ aTest: 1 }) }->>'aTest' as x`)[0].x + return ['1', x] +}) + t('Json transform nested parameter keys', async() => { const sql = postgres({ ...options, @@ -135,11 +140,6 @@ t('Json transform result keys', async() => { return [1, x.aTest] }) -t('Json without transform keeps parameter keys', async() => { - const x = (await sql`select ${ sql.json({ aTest: 1 }) }->>'aTest' as x`)[0].x - return ['1', x] -}) - t('Json transform implicit json parameters', async() => { const sql = postgres({ ...options, From 5d73037d48a2c9afea66ca9490dffa287fe5fe96 Mon Sep 17 00:00:00 2001 From: Karl Horky Date: Wed, 27 May 2026 22:54:38 +0200 Subject: [PATCH 6/6] Order tests with interpolation first --- cjs/tests/index.js | 18 +++++++++--------- deno/tests/index.js | 18 +++++++++--------- tests/index.js | 18 +++++++++--------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/cjs/tests/index.js b/cjs/tests/index.js index 52d737a9..83970b5d 100644 --- a/cjs/tests/index.js +++ b/cjs/tests/index.js @@ -131,16 +131,16 @@ t('Json transform nested parameter keys', async() => { return ['2', x] }) -t('Json transform result keys', async() => { +t('Json transform typed json parameters', async() => { const sql = postgres({ ...options, transform: postgres.camel }) - const x = (await sql`select '{"a_test":1}'::jsonb as x`)[0].x - return [1, x.aTest] + const x = (await sql`select ${ sql.typed({ aTest: 1 }, 114) }->>'a_test' as x`)[0].x + return ['1', x] }) -t('Json transform implicit json parameters', async() => { +t('Json transform implicit jsonb parameters', async() => { const sql = postgres({ ...options, transform: postgres.camel @@ -149,7 +149,7 @@ t('Json transform implicit json parameters', async() => { return ['1', x] }) -t('Json transform implicit json type parameters', async() => { +t('Json transform implicit json parameters', async() => { const sql = postgres({ ...options, transform: postgres.camel @@ -158,16 +158,16 @@ t('Json transform implicit json type parameters', async() => { return ['1', x] }) -t('Json transform typed json parameters', async() => { +t('Json transform result keys', async() => { const sql = postgres({ ...options, transform: postgres.camel }) - const x = (await sql`select ${ sql.typed({ aTest: 1 }, 114) }->>'a_test' as x`)[0].x - return ['1', x] + const x = (await sql`select '{"a_test":1}'::jsonb as x`)[0].x + return [1, x.aTest] }) -t('Json transform toJSON parameter values', async() => { +t('Json transform does not transform parameter values with .toJSON()', async() => { const now = new Date() const sql = postgres({ ...options, diff --git a/deno/tests/index.js b/deno/tests/index.js index 2e49c075..4542db42 100644 --- a/deno/tests/index.js +++ b/deno/tests/index.js @@ -133,16 +133,16 @@ t('Json transform nested parameter keys', async() => { return ['2', x] }) -t('Json transform result keys', async() => { +t('Json transform typed json parameters', async() => { const sql = postgres({ ...options, transform: postgres.camel }) - const x = (await sql`select '{"a_test":1}'::jsonb as x`)[0].x - return [1, x.aTest] + const x = (await sql`select ${ sql.typed({ aTest: 1 }, 114) }->>'a_test' as x`)[0].x + return ['1', x] }) -t('Json transform implicit json parameters', async() => { +t('Json transform implicit jsonb parameters', async() => { const sql = postgres({ ...options, transform: postgres.camel @@ -151,7 +151,7 @@ t('Json transform implicit json parameters', async() => { return ['1', x] }) -t('Json transform implicit json type parameters', async() => { +t('Json transform implicit json parameters', async() => { const sql = postgres({ ...options, transform: postgres.camel @@ -160,16 +160,16 @@ t('Json transform implicit json type parameters', async() => { return ['1', x] }) -t('Json transform typed json parameters', async() => { +t('Json transform result keys', async() => { const sql = postgres({ ...options, transform: postgres.camel }) - const x = (await sql`select ${ sql.typed({ aTest: 1 }, 114) }->>'a_test' as x`)[0].x - return ['1', x] + const x = (await sql`select '{"a_test":1}'::jsonb as x`)[0].x + return [1, x.aTest] }) -t('Json transform toJSON parameter values', async() => { +t('Json transform does not transform parameter values with .toJSON()', async() => { const now = new Date() const sql = postgres({ ...options, diff --git a/tests/index.js b/tests/index.js index 58a2cc1d..55b54ad7 100644 --- a/tests/index.js +++ b/tests/index.js @@ -131,16 +131,16 @@ t('Json transform nested parameter keys', async() => { return ['2', x] }) -t('Json transform result keys', async() => { +t('Json transform typed json parameters', async() => { const sql = postgres({ ...options, transform: postgres.camel }) - const x = (await sql`select '{"a_test":1}'::jsonb as x`)[0].x - return [1, x.aTest] + const x = (await sql`select ${ sql.typed({ aTest: 1 }, 114) }->>'a_test' as x`)[0].x + return ['1', x] }) -t('Json transform implicit json parameters', async() => { +t('Json transform implicit jsonb parameters', async() => { const sql = postgres({ ...options, transform: postgres.camel @@ -149,7 +149,7 @@ t('Json transform implicit json parameters', async() => { return ['1', x] }) -t('Json transform implicit json type parameters', async() => { +t('Json transform implicit json parameters', async() => { const sql = postgres({ ...options, transform: postgres.camel @@ -158,16 +158,16 @@ t('Json transform implicit json type parameters', async() => { return ['1', x] }) -t('Json transform typed json parameters', async() => { +t('Json transform result keys', async() => { const sql = postgres({ ...options, transform: postgres.camel }) - const x = (await sql`select ${ sql.typed({ aTest: 1 }, 114) }->>'a_test' as x`)[0].x - return ['1', x] + const x = (await sql`select '{"a_test":1}'::jsonb as x`)[0].x + return [1, x.aTest] }) -t('Json transform toJSON parameter values', async() => { +t('Json transform does not transform parameter values with .toJSON()', async() => { const now = new Date() const sql = postgres({ ...options,