Skip to content

Commit 11955a0

Browse files
author
HZ111 / Dev2
committed
Add property usePrebuiltEmptyResultObjects to Query constructor which generates pre-shaped result rows
1 parent a2a355a commit 11955a0

File tree

3 files changed

+69
-6
lines changed

3 files changed

+69
-6
lines changed

packages/pg/lib/query.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,14 @@ class Query extends EventEmitter {
2424
if (process.domain && config.callback) {
2525
this.callback = process.domain.bind(config.callback)
2626
}
27+
this.usePrebuiltEmptyResultObjects = config.usePrebuiltEmptyResultObjects == true
2728
this._result = new Result(this._rowMode, this.types)
28-
2929
// potential for multiple results
3030
this._results = this._result
3131
this.isPreparedStatement = false
3232
this._canceledDueToError = false
3333
this._promise = null
34+
this._prebuiltEmptyResultObject = null
3435
}
3536

3637
requiresPreparation() {
@@ -64,6 +65,7 @@ class Query extends EventEmitter {
6465
}
6566
this._result = new Result(this._rowMode, this.types)
6667
this._results.push(this._result)
68+
this._prebuiltEmptyResultObject = null
6769
}
6870
}
6971

@@ -83,8 +85,12 @@ class Query extends EventEmitter {
8385
return
8486
}
8587

88+
if (this.usePrebuiltEmptyResultObjects && !this._prebuiltEmptyResultObject) {
89+
this._createPrebuiltEmptyResultObject()
90+
}
91+
8692
try {
87-
row = this._result.parseRow(msg.fields)
93+
row = this._result.parseRow(msg.fields, this.usePrebuiltEmptyResultObjects ? { ... this._prebuiltEmptyResultObject } : {})
8894
} catch (err) {
8995
this._canceledDueToError = err
9096
return
@@ -138,7 +144,7 @@ class Query extends EventEmitter {
138144
try {
139145
this.callback(null, this._results)
140146
}
141-
catch(err) {
147+
catch (err) {
142148
process.nextTick(() => {
143149
throw err
144150
})
@@ -236,6 +242,13 @@ class Query extends EventEmitter {
236242
handleCopyData(msg, connection) {
237243
// noop
238244
}
245+
_createPrebuiltEmptyResultObject() {
246+
var row = {};
247+
for (var i = 0; i < this._result.fields.length; i++) {
248+
row[this._result.fields[i].name] = null
249+
}
250+
this._prebuiltEmptyResultObject = row
251+
}
239252
}
240253

241-
module.exports = Query
254+
module.exports = Query

packages/pg/lib/result.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,7 @@ class Result {
5959
return row
6060
}
6161

62-
parseRow(rowData) {
63-
var row = {}
62+
parseRow(rowData, row = {}) {
6463
for (var i = 0, len = rowData.length; i < len; i++) {
6564
var rawValue = rowData[i]
6665
var field = this.fields[i].name
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
'use strict'
2+
const helper = require('../test-helper')
3+
4+
const suite = new helper.Suite()
5+
6+
// https://github.com/brianc/node-postgres/issues/2716
7+
suite.testAsync('rows returned from pg have a clean shape which allows faster access and copying', async () => {
8+
const amountOfCols = 100
9+
const testCopies = 10000
10+
const expectedFasterFactor = 50
11+
12+
const client = new helper.pg.Client()
13+
await client.connect()
14+
15+
16+
const queryFields = []
17+
for (let i = 1; i <= amountOfCols; i++) {
18+
queryFields.push(`${i} as col${i}`)
19+
}
20+
const query = `SELECT ${queryFields.join(', ')}`
21+
const resultWithoutShape = await client.query({
22+
text: query,
23+
usePrebuiltEmptyResultObjects: false
24+
})
25+
const rowFromPgWithoutShape = resultWithoutShape.rows[0]
26+
const resultWithShape = await client.query({
27+
text: query,
28+
usePrebuiltEmptyResultObjects: true
29+
})
30+
const rowFromPgWithShape = resultWithShape.rows[0]
31+
32+
33+
const beforeWithout = process.hrtime.bigint()
34+
for (let i = 0; i < testCopies; i++) {
35+
let copy = { ...rowFromPgWithoutShape }
36+
}
37+
const afterWithout = process.hrtime.bigint()
38+
const withoutResult = afterWithout - beforeWithout
39+
40+
const beforeWith = process.hrtime.bigint()
41+
for (let i = 0; i < testCopies; i++) {
42+
let copy = { ...rowFromPgWithShape }
43+
}
44+
const afterWith = process.hrtime.bigint()
45+
const withResult = afterWith - beforeWith
46+
47+
const factorFaster = withoutResult / withResult
48+
assert(factorFaster > expectedFasterFactor)
49+
50+
await client.end()
51+
})

0 commit comments

Comments
 (0)