From 1d18ccec17d7e9f26fbeadfaf0d60027d1c7f3a3 Mon Sep 17 00:00:00 2001 From: Charmander <~@charmander.me> Date: Tue, 11 Aug 2026 20:54:42 -0700 Subject: [PATCH] Normalize query config without copying it --- packages/pg/lib/internal/utils.js | 22 +++++++++++++ packages/pg/lib/native/query.js | 17 +++++----- packages/pg/lib/query.js | 20 ++++++------ packages/pg/lib/utils.js | 5 ++- packages/pg/package.json | 3 +- packages/pg/test/unit/utils-tests.js | 46 ++++++++++++---------------- 6 files changed, 69 insertions(+), 44 deletions(-) create mode 100644 packages/pg/lib/internal/utils.js diff --git a/packages/pg/lib/internal/utils.js b/packages/pg/lib/internal/utils.js new file mode 100644 index 000000000..85be1612e --- /dev/null +++ b/packages/pg/lib/internal/utils.js @@ -0,0 +1,22 @@ +'use strict' + +exports.normalizeQueryConfig = (config, values, callback) => { + let text = undefined + + if (typeof config === 'string') { + text = config + config = {} + } + + if (typeof values === 'function') { + callback = values + values = undefined + } + + return { + config, + text: text ?? config.text, + values: values || config.values, + callback: callback || config.callback, + } +} diff --git a/packages/pg/lib/native/query.js b/packages/pg/lib/native/query.js index 8cb561979..74c696fef 100644 --- a/packages/pg/lib/native/query.js +++ b/packages/pg/lib/native/query.js @@ -2,16 +2,19 @@ const EventEmitter = require('events').EventEmitter const util = require('util') -const utils = require('../utils') +const { prepareValue } = require('../utils') +const { normalizeQueryConfig } = require('../internal/utils.js') const NativeQuery = (module.exports = function (config, values, callback) { EventEmitter.call(this) - config = utils.normalizeQueryConfig(config, values, callback) - this.text = config.text - this.values = config.values + ;({ + config, + text: this.text, + values: this.values, + callback: this.callback, + } = normalizeQueryConfig(config, values, callback)) this.name = config.name this.queryMode = config.queryMode - this.callback = config.callback this.state = 'new' this._arrayMode = config.rowMode === 'array' @@ -133,7 +136,7 @@ NativeQuery.prototype.submit = function (client) { console.error('You supplied %s (%s)', this.name, this.name.length) console.error('This can cause conflicts and silent errors executing queries') } - const values = (this.values || []).map(utils.prepareValue) + const values = (this.values || []).map(prepareValue) // check if the client has already executed this named query // if so...just execute it again - skip the planning phase @@ -155,7 +158,7 @@ NativeQuery.prototype.submit = function (client) { const err = new Error('Query values must be an array') return after(err) } - const vals = this.values.map(utils.prepareValue) + const vals = this.values.map(prepareValue) client.native.query(this.text, vals, after) } else if (this.queryMode === 'extended') { client.native.query(this.text, [], after) diff --git a/packages/pg/lib/query.js b/packages/pg/lib/query.js index 6b9214199..e837a3ed8 100644 --- a/packages/pg/lib/query.js +++ b/packages/pg/lib/query.js @@ -3,16 +3,19 @@ const { EventEmitter } = require('events') const Result = require('./result') -const utils = require('./utils') +const { prepareValue } = require('./utils') +const { normalizeQueryConfig } = require('./internal/utils.js') class Query extends EventEmitter { constructor(config, values, callback) { super() + ;({ + config, + text: this.text, + values: this.values, + callback: this.callback, + } = normalizeQueryConfig(config, values, callback)) - config = utils.normalizeQueryConfig(config, values, callback) - - this.text = config.text - this.values = config.values this.rows = config.rows this.types = config.types this.name = config.name @@ -20,10 +23,9 @@ class Query extends EventEmitter { this.binary = config.binary // use unique portal name each time this.portal = config.portal || '' - this.callback = config.callback this._rowMode = config.rowMode - if (process.domain && config.callback) { - this.callback = process.domain.bind(config.callback) + if (process.domain && this.callback) { + this.callback = process.domain.bind(this.callback) } this._result = new Result(this._rowMode, this.types) @@ -228,7 +230,7 @@ class Query extends EventEmitter { statement: this.name, values: this.values, binary: this.binary, - valueMapper: utils.prepareValue, + valueMapper: prepareValue, }) } catch (err) { // we should close parse to avoid leaking connections diff --git a/packages/pg/lib/utils.js b/packages/pg/lib/utils.js index ba51c82c8..e9c6248f3 100644 --- a/packages/pg/lib/utils.js +++ b/packages/pg/lib/utils.js @@ -219,7 +219,10 @@ module.exports = { // by accident, eg: from calling values.map(utils.prepareValue) return prepareValue(value) }, - normalizeQueryConfig, + normalizeQueryConfig: nodeUtils.deprecate( + normalizeQueryConfig, + 'normalizeQueryConfig is an unused internal function and will be removed in pg@9.0' + ), escapeIdentifier, escapeLiteral, } diff --git a/packages/pg/package.json b/packages/pg/package.json index d028179ca..3bf46e037 100644 --- a/packages/pg/package.json +++ b/packages/pg/package.json @@ -29,7 +29,8 @@ "default": "./package.json" }, "./lib/*": "./lib/*.js", - "./lib/*.js": "./lib/*.js" + "./lib/*.js": "./lib/*.js", + "./lib/internal/*": null }, "dependencies": { "pg-connection-string": "^2.14.0", diff --git a/packages/pg/test/unit/utils-tests.js b/packages/pg/test/unit/utils-tests.js index ff0d92944..8989ec1da 100644 --- a/packages/pg/test/unit/utils-tests.js +++ b/packages/pg/test/unit/utils-tests.js @@ -1,6 +1,7 @@ 'use strict' const helper = require('./test-helper') const utils = require('./../../lib/utils') +const { normalizeQueryConfig } = require('../../lib/internal/utils.js') const defaults = require('./../../lib').defaults const assert = require('assert') const suite = new helper.Suite() @@ -13,36 +14,34 @@ test('ensure types is exported on root object', function () { assert(pg.types.setTypeParser) }) +const text = 'TEXT' +const callback = function () {} +const values = [10] + test('normalizing query configs', function () { let config - const callback = function () {} - config = utils.normalizeQueryConfig({ text: 'TEXT' }) - assert.same(config, { text: 'TEXT' }) + config = { text } + assert.same(normalizeQueryConfig(config), { config, text, values: undefined, callback: undefined }) - config = utils.normalizeQueryConfig({ text: 'TEXT' }, [10]) - assert.deepEqual(config, { text: 'TEXT', values: [10] }) + assert.same(normalizeQueryConfig(config, values), { config, text, values, callback: undefined }) - config = utils.normalizeQueryConfig({ text: 'TEXT', values: [10] }) - assert.deepEqual(config, { text: 'TEXT', values: [10] }) + config = { text, values } + assert.same(normalizeQueryConfig(config), { config, text, values, callback: undefined }) - config = utils.normalizeQueryConfig('TEXT', [10], callback) - assert.deepEqual(config, { text: 'TEXT', values: [10], callback: callback }) + const normalized = normalizeQueryConfig(text, values, callback) + assert.same(normalized, { text, values, callback }) + assert.deepStrictEqual(normalized.config, {}) - config = utils.normalizeQueryConfig({ text: 'TEXT', values: [10] }, callback) - assert.deepEqual(config, { text: 'TEXT', values: [10], callback: callback }) + assert.same(normalizeQueryConfig({ text, values }, callback), { text, values, callback }) }) test('normalizeQueryConfig does not mutate the passed-in config object', function () { // Regression test for https://github.com/brianc/node-postgres/issues/2651. - const original = { text: 'TEXT' } - const callback = function () {} - - const normalized = utils.normalizeQueryConfig(original, [10], callback) - - assert.equal(original.callback, undefined) - assert.equal(original.values, undefined) - assert.deepEqual(normalized, { text: 'TEXT', values: [10], callback: callback }) + const original = { text } + const normalized = utils.normalizeQueryConfig(original, values, callback) + assert.deepStrictEqual(original, { text }) + assert.same(normalized, { text, values, callback }) }) test('normalizeQueryConfig preserves inherited config properties', function () { @@ -57,15 +56,10 @@ test('normalizeQueryConfig preserves inherited config properties', function () { } const original = new QueryConfig() - const callback = function () {} - - const normalized = utils.normalizeQueryConfig(original, [10], callback) - + const normalized = utils.normalizeQueryConfig(original, values, callback) assert.equal(original.callback, undefined) assert.equal(original.values, undefined) - assert.equal(normalized.text, 'TEXT') - assert.deepEqual(normalized.values, [10]) - assert.equal(normalized.callback, callback) + assert.same(normalized, { text, values, callback }) }) test('prepareValues: buffer prepared properly', function () {