pg 8.3.0 → 8.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -1,11 +1,4 @@
1
1
  'use strict'
2
- /**
3
- * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
4
- * All rights reserved.
5
- *
6
- * This source code is licensed under the MIT license found in the
7
- * README.md file in the root directory of this source tree.
8
- */
9
2
 
10
3
  var EventEmitter = require('events').EventEmitter
11
4
  var util = require('util')
@@ -19,576 +12,590 @@ var Query = require('./query')
19
12
  var defaults = require('./defaults')
20
13
  var Connection = require('./connection')
21
14
 
22
- var Client = function (config) {
23
- EventEmitter.call(this)
24
-
25
- this.connectionParameters = new ConnectionParameters(config)
26
- this.user = this.connectionParameters.user
27
- this.database = this.connectionParameters.database
28
- this.port = this.connectionParameters.port
29
- this.host = this.connectionParameters.host
30
-
31
- // "hiding" the password so it doesn't show up in stack traces
32
- // or if the client is console.logged
33
- Object.defineProperty(this, 'password', {
34
- configurable: true,
35
- enumerable: false,
36
- writable: true,
37
- value: this.connectionParameters.password,
38
- })
39
-
40
- this.replication = this.connectionParameters.replication
41
-
42
- var c = config || {}
43
-
44
- this._Promise = c.Promise || global.Promise
45
- this._types = new TypeOverrides(c.types)
46
- this._ending = false
47
- this._connecting = false
48
- this._connected = false
49
- this._connectionError = false
50
- this._queryable = true
51
-
52
- this.connection =
53
- c.connection ||
54
- new Connection({
55
- stream: c.stream,
56
- ssl: this.connectionParameters.ssl,
57
- keepAlive: c.keepAlive || false,
58
- keepAliveInitialDelayMillis: c.keepAliveInitialDelayMillis || 0,
59
- encoding: this.connectionParameters.client_encoding || 'utf8',
15
+ class Client extends EventEmitter {
16
+ constructor(config) {
17
+ super()
18
+
19
+ this.connectionParameters = new ConnectionParameters(config)
20
+ this.user = this.connectionParameters.user
21
+ this.database = this.connectionParameters.database
22
+ this.port = this.connectionParameters.port
23
+ this.host = this.connectionParameters.host
24
+
25
+ // "hiding" the password so it doesn't show up in stack traces
26
+ // or if the client is console.logged
27
+ Object.defineProperty(this, 'password', {
28
+ configurable: true,
29
+ enumerable: false,
30
+ writable: true,
31
+ value: this.connectionParameters.password,
60
32
  })
61
- this.queryQueue = []
62
- this.binary = c.binary || defaults.binary
63
- this.processID = null
64
- this.secretKey = null
65
- this.ssl = this.connectionParameters.ssl || false
66
- this._connectionTimeoutMillis = c.connectionTimeoutMillis || 0
67
- }
68
-
69
- util.inherits(Client, EventEmitter)
70
33
 
71
- Client.prototype._errorAllQueries = function (err) {
72
- const enqueueError = (query) => {
73
- process.nextTick(() => {
74
- query.handleError(err, this.connection)
75
- })
34
+ this.replication = this.connectionParameters.replication
35
+
36
+ var c = config || {}
37
+
38
+ this._Promise = c.Promise || global.Promise
39
+ this._types = new TypeOverrides(c.types)
40
+ this._ending = false
41
+ this._connecting = false
42
+ this._connected = false
43
+ this._connectionError = false
44
+ this._queryable = true
45
+
46
+ this.connection =
47
+ c.connection ||
48
+ new Connection({
49
+ stream: c.stream,
50
+ ssl: this.connectionParameters.ssl,
51
+ keepAlive: c.keepAlive || false,
52
+ keepAliveInitialDelayMillis: c.keepAliveInitialDelayMillis || 0,
53
+ encoding: this.connectionParameters.client_encoding || 'utf8',
54
+ })
55
+ this.queryQueue = []
56
+ this.binary = c.binary || defaults.binary
57
+ this.processID = null
58
+ this.secretKey = null
59
+ this.ssl = this.connectionParameters.ssl || false
60
+ this._connectionTimeoutMillis = c.connectionTimeoutMillis || 0
76
61
  }
77
62
 
78
- if (this.activeQuery) {
79
- enqueueError(this.activeQuery)
80
- this.activeQuery = null
63
+ _errorAllQueries(err) {
64
+ const enqueueError = (query) => {
65
+ process.nextTick(() => {
66
+ query.handleError(err, this.connection)
67
+ })
68
+ }
69
+
70
+ if (this.activeQuery) {
71
+ enqueueError(this.activeQuery)
72
+ this.activeQuery = null
73
+ }
74
+
75
+ this.queryQueue.forEach(enqueueError)
76
+ this.queryQueue.length = 0
81
77
  }
82
78
 
83
- this.queryQueue.forEach(enqueueError)
84
- this.queryQueue.length = 0
85
- }
79
+ _connect(callback) {
80
+ var self = this
81
+ var con = this.connection
82
+ this._connectionCallback = callback
83
+
84
+ if (this._connecting || this._connected) {
85
+ const err = new Error('Client has already been connected. You cannot reuse a client.')
86
+ process.nextTick(() => {
87
+ callback(err)
88
+ })
89
+ return
90
+ }
91
+ this._connecting = true
92
+
93
+ this.connectionTimeoutHandle
94
+ if (this._connectionTimeoutMillis > 0) {
95
+ this.connectionTimeoutHandle = setTimeout(() => {
96
+ con._ending = true
97
+ con.stream.destroy(new Error('timeout expired'))
98
+ }, this._connectionTimeoutMillis)
99
+ }
100
+
101
+ if (this.host && this.host.indexOf('/') === 0) {
102
+ con.connect(this.host + '/.s.PGSQL.' + this.port)
103
+ } else {
104
+ con.connect(this.port, this.host)
105
+ }
106
+
107
+ // once connection is established send startup message
108
+ con.on('connect', function () {
109
+ if (self.ssl) {
110
+ con.requestSsl()
111
+ } else {
112
+ con.startup(self.getStartupConf())
113
+ }
114
+ })
115
+
116
+ con.on('sslconnect', function () {
117
+ con.startup(self.getStartupConf())
118
+ })
119
+
120
+ this._attachListeners(con)
86
121
 
87
- Client.prototype._connect = function (callback) {
88
- var self = this
89
- var con = this.connection
90
- if (this._connecting || this._connected) {
91
- const err = new Error('Client has already been connected. You cannot reuse a client.')
92
- process.nextTick(() => {
93
- callback(err)
122
+ con.once('end', () => {
123
+ const error = this._ending ? new Error('Connection terminated') : new Error('Connection terminated unexpectedly')
124
+
125
+ clearTimeout(this.connectionTimeoutHandle)
126
+ this._errorAllQueries(error)
127
+
128
+ if (!this._ending) {
129
+ // if the connection is ended without us calling .end()
130
+ // on this client then we have an unexpected disconnection
131
+ // treat this as an error unless we've already emitted an error
132
+ // during connection.
133
+ if (this._connecting && !this._connectionError) {
134
+ if (this._connectionCallback) {
135
+ this._connectionCallback(error)
136
+ } else {
137
+ this._handleErrorEvent(error)
138
+ }
139
+ } else if (!this._connectionError) {
140
+ this._handleErrorEvent(error)
141
+ }
142
+ }
143
+
144
+ process.nextTick(() => {
145
+ this.emit('end')
146
+ })
94
147
  })
95
- return
96
148
  }
97
- this._connecting = true
98
149
 
99
- var connectionTimeoutHandle
100
- if (this._connectionTimeoutMillis > 0) {
101
- connectionTimeoutHandle = setTimeout(() => {
102
- con._ending = true
103
- con.stream.destroy(new Error('timeout expired'))
104
- }, this._connectionTimeoutMillis)
150
+ connect(callback) {
151
+ if (callback) {
152
+ this._connect(callback)
153
+ return
154
+ }
155
+
156
+ return new this._Promise((resolve, reject) => {
157
+ this._connect((error) => {
158
+ if (error) {
159
+ reject(error)
160
+ } else {
161
+ resolve()
162
+ }
163
+ })
164
+ })
105
165
  }
106
166
 
107
- if (this.host && this.host.indexOf('/') === 0) {
108
- con.connect(this.host + '/.s.PGSQL.' + this.port)
109
- } else {
110
- con.connect(this.port, this.host)
167
+ _attachListeners(con) {
168
+ // password request handling
169
+ con.on('authenticationCleartextPassword', this._handleAuthCleartextPassword.bind(this))
170
+ // password request handling
171
+ con.on('authenticationMD5Password', this._handleAuthMD5Password.bind(this))
172
+ // password request handling (SASL)
173
+ con.on('authenticationSASL', this._handleAuthSASL.bind(this))
174
+ con.on('authenticationSASLContinue', this._handleAuthSASLContinue.bind(this))
175
+ con.on('authenticationSASLFinal', this._handleAuthSASLFinal.bind(this))
176
+ con.on('backendKeyData', this._handleBackendKeyData.bind(this))
177
+ con.on('error', this._handleErrorEvent.bind(this))
178
+ con.on('errorMessage', this._handleErrorMessage.bind(this))
179
+ con.on('readyForQuery', this._handleReadyForQuery.bind(this))
180
+ con.on('notice', this._handleNotice.bind(this))
181
+ con.on('rowDescription', this._handleRowDescription.bind(this))
182
+ con.on('dataRow', this._handleDataRow.bind(this))
183
+ con.on('portalSuspended', this._handlePortalSuspended.bind(this))
184
+ con.on('emptyQuery', this._handleEmptyQuery.bind(this))
185
+ con.on('commandComplete', this._handleCommandComplete.bind(this))
186
+ con.on('parseComplete', this._handleParseComplete.bind(this))
187
+ con.on('copyInResponse', this._handleCopyInResponse.bind(this))
188
+ con.on('copyData', this._handleCopyData.bind(this))
189
+ con.on('notification', this._handleNotification.bind(this))
111
190
  }
112
191
 
113
- // once connection is established send startup message
114
- con.on('connect', function () {
115
- if (self.ssl) {
116
- con.requestSsl()
117
- } else {
118
- con.startup(self.getStartupConf())
119
- }
120
- })
121
-
122
- con.on('sslconnect', function () {
123
- con.startup(self.getStartupConf())
124
- })
125
-
126
- function checkPgPass(cb) {
127
- return function (msg) {
128
- if (typeof self.password === 'function') {
129
- self._Promise
130
- .resolve()
131
- .then(() => self.password())
132
- .then((pass) => {
133
- if (pass !== undefined) {
134
- if (typeof pass !== 'string') {
135
- con.emit('error', new TypeError('Password must be a string'))
136
- return
137
- }
138
- self.connectionParameters.password = self.password = pass
139
- } else {
140
- self.connectionParameters.password = self.password = null
192
+ // TODO(bmc): deprecate pgpass "built in" integration since this.password can be a function
193
+ // it can be supplied by the user if required - this is a breaking change!
194
+ _checkPgPass(cb) {
195
+ const con = this.connection
196
+ if (typeof this.password === 'function') {
197
+ this._Promise
198
+ .resolve()
199
+ .then(() => this.password())
200
+ .then((pass) => {
201
+ if (pass !== undefined) {
202
+ if (typeof pass !== 'string') {
203
+ con.emit('error', new TypeError('Password must be a string'))
204
+ return
141
205
  }
142
- cb(msg)
143
- })
144
- .catch((err) => {
145
- con.emit('error', err)
146
- })
147
- } else if (self.password !== null) {
148
- cb(msg)
149
- } else {
150
- pgPass(self.connectionParameters, function (pass) {
151
- if (undefined !== pass) {
152
- self.connectionParameters.password = self.password = pass
206
+ this.connectionParameters.password = this.password = pass
207
+ } else {
208
+ this.connectionParameters.password = this.password = null
153
209
  }
154
- cb(msg)
210
+ cb()
155
211
  })
156
- }
212
+ .catch((err) => {
213
+ con.emit('error', err)
214
+ })
215
+ } else if (this.password !== null) {
216
+ cb()
217
+ } else {
218
+ pgPass(this.connectionParameters, function (pass) {
219
+ if (undefined !== pass) {
220
+ this.connectionParameters.password = this.password = pass
221
+ }
222
+ cb()
223
+ })
157
224
  }
158
225
  }
159
226
 
160
- // password request handling
161
- con.on(
162
- 'authenticationCleartextPassword',
163
- checkPgPass(function () {
164
- con.password(self.password)
227
+ _handleAuthCleartextPassword(msg) {
228
+ this._checkPgPass(() => {
229
+ this.connection.password(this.password)
165
230
  })
166
- )
231
+ }
167
232
 
168
- // password request handling
169
- con.on(
170
- 'authenticationMD5Password',
171
- checkPgPass(function (msg) {
172
- con.password(utils.postgresMd5PasswordHash(self.user, self.password, msg.salt))
233
+ _handleAuthMD5Password(msg) {
234
+ this._checkPgPass(() => {
235
+ const hashedPassword = utils.postgresMd5PasswordHash(this.user, this.password, msg.salt)
236
+ this.connection.password(hashedPassword)
173
237
  })
174
- )
175
-
176
- // password request handling (SASL)
177
- var saslSession
178
- con.on(
179
- 'authenticationSASL',
180
- checkPgPass(function (msg) {
181
- saslSession = sasl.startSession(msg.mechanisms)
238
+ }
182
239
 
183
- con.sendSASLInitialResponseMessage(saslSession.mechanism, saslSession.response)
240
+ _handleAuthSASL(msg) {
241
+ this._checkPgPass(() => {
242
+ this.saslSession = sasl.startSession(msg.mechanisms)
243
+ this.connection.sendSASLInitialResponseMessage(this.saslSession.mechanism, this.saslSession.response)
184
244
  })
185
- )
186
-
187
- // password request handling (SASL)
188
- con.on('authenticationSASLContinue', function (msg) {
189
- sasl.continueSession(saslSession, self.password, msg.data)
245
+ }
190
246
 
191
- con.sendSCRAMClientFinalMessage(saslSession.response)
192
- })
247
+ _handleAuthSASLContinue(msg) {
248
+ sasl.continueSession(this.saslSession, this.password, msg.data)
249
+ this.connection.sendSCRAMClientFinalMessage(this.saslSession.response)
250
+ }
193
251
 
194
- // password request handling (SASL)
195
- con.on('authenticationSASLFinal', function (msg) {
196
- sasl.finalizeSession(saslSession, msg.data)
252
+ _handleAuthSASLFinal(msg) {
253
+ sasl.finalizeSession(this.saslSession, msg.data)
254
+ this.saslSession = null
255
+ }
197
256
 
198
- saslSession = null
199
- })
257
+ _handleBackendKeyData(msg) {
258
+ this.processID = msg.processID
259
+ this.secretKey = msg.secretKey
260
+ }
200
261
 
201
- con.once('backendKeyData', function (msg) {
202
- self.processID = msg.processID
203
- self.secretKey = msg.secretKey
204
- })
262
+ _handleReadyForQuery(msg) {
263
+ if (this._connecting) {
264
+ this._connecting = false
265
+ this._connected = true
266
+ clearTimeout(this.connectionTimeoutHandle)
267
+
268
+ // process possible callback argument to Client#connect
269
+ if (this._connectionCallback) {
270
+ this._connectionCallback(null, this)
271
+ // remove callback for proper error handling
272
+ // after the connect event
273
+ this._connectionCallback = null
274
+ }
275
+ this.emit('connect')
276
+ }
277
+ const { activeQuery } = this
278
+ this.activeQuery = null
279
+ this.readyForQuery = true
280
+ if (activeQuery) {
281
+ activeQuery.handleReadyForQuery(this.connection)
282
+ }
283
+ this._pulseQueryQueue()
284
+ }
205
285
 
206
- const connectingErrorHandler = (err) => {
286
+ // if we receieve an error event or error message
287
+ // during the connection process we handle it here
288
+ _handleErrorWhileConnecting(err) {
207
289
  if (this._connectionError) {
290
+ // TODO(bmc): this is swallowing errors - we shouldn't do this
208
291
  return
209
292
  }
210
293
  this._connectionError = true
211
- clearTimeout(connectionTimeoutHandle)
212
- if (callback) {
213
- return callback(err)
294
+ clearTimeout(this.connectionTimeoutHandle)
295
+ if (this._connectionCallback) {
296
+ return this._connectionCallback(err)
214
297
  }
215
298
  this.emit('error', err)
216
299
  }
217
300
 
218
- const connectedErrorHandler = (err) => {
301
+ // if we're connected and we receive an error event from the connection
302
+ // this means the socket is dead - do a hard abort of all queries and emit
303
+ // the socket error on the client as well
304
+ _handleErrorEvent(err) {
305
+ if (this._connecting) {
306
+ return this._handleErrorWhileConnecting(err)
307
+ }
219
308
  this._queryable = false
220
309
  this._errorAllQueries(err)
221
310
  this.emit('error', err)
222
311
  }
223
312
 
224
- const connectedErrorMessageHandler = (msg) => {
313
+ // handle error messages from the postgres backend
314
+ _handleErrorMessage(msg) {
315
+ if (this._connecting) {
316
+ return this._handleErrorWhileConnecting(msg)
317
+ }
225
318
  const activeQuery = this.activeQuery
226
319
 
227
320
  if (!activeQuery) {
228
- connectedErrorHandler(msg)
321
+ this._handleErrorEvent(msg)
229
322
  return
230
323
  }
231
324
 
232
325
  this.activeQuery = null
233
- activeQuery.handleError(msg, con)
326
+ activeQuery.handleError(msg, this.connection)
234
327
  }
235
328
 
236
- con.on('error', connectingErrorHandler)
237
- con.on('errorMessage', connectingErrorHandler)
329
+ _handleRowDescription(msg) {
330
+ // delegate rowDescription to active query
331
+ this.activeQuery.handleRowDescription(msg)
332
+ }
238
333
 
239
- // hook up query handling events to connection
240
- // after the connection initially becomes ready for queries
241
- con.once('readyForQuery', function () {
242
- self._connecting = false
243
- self._connected = true
244
- self._attachListeners(con)
245
- con.removeListener('error', connectingErrorHandler)
246
- con.removeListener('errorMessage', connectingErrorHandler)
247
- con.on('error', connectedErrorHandler)
248
- con.on('errorMessage', connectedErrorMessageHandler)
249
- clearTimeout(connectionTimeoutHandle)
334
+ _handleDataRow(msg) {
335
+ // delegate dataRow to active query
336
+ this.activeQuery.handleDataRow(msg)
337
+ }
250
338
 
251
- // process possible callback argument to Client#connect
252
- if (callback) {
253
- callback(null, self)
254
- // remove callback for proper error handling
255
- // after the connect event
256
- callback = null
257
- }
258
- self.emit('connect')
259
- })
260
-
261
- con.on('readyForQuery', function () {
262
- var activeQuery = self.activeQuery
263
- self.activeQuery = null
264
- self.readyForQuery = true
265
- if (activeQuery) {
266
- activeQuery.handleReadyForQuery(con)
267
- }
268
- self._pulseQueryQueue()
269
- })
339
+ _handlePortalSuspended(msg) {
340
+ // delegate portalSuspended to active query
341
+ this.activeQuery.handlePortalSuspended(this.connection)
342
+ }
270
343
 
271
- con.once('end', () => {
272
- const error = this._ending ? new Error('Connection terminated') : new Error('Connection terminated unexpectedly')
344
+ _handleEmptyQuery(msg) {
345
+ // delegate emptyQuery to active query
346
+ this.activeQuery.handleEmptyQuery(this.connection)
347
+ }
273
348
 
274
- clearTimeout(connectionTimeoutHandle)
275
- this._errorAllQueries(error)
349
+ _handleCommandComplete(msg) {
350
+ // delegate commandComplete to active query
351
+ this.activeQuery.handleCommandComplete(msg, this.connection)
352
+ }
276
353
 
277
- if (!this._ending) {
278
- // if the connection is ended without us calling .end()
279
- // on this client then we have an unexpected disconnection
280
- // treat this as an error unless we've already emitted an error
281
- // during connection.
282
- if (this._connecting && !this._connectionError) {
283
- if (callback) {
284
- callback(error)
285
- } else {
286
- connectedErrorHandler(error)
287
- }
288
- } else if (!this._connectionError) {
289
- connectedErrorHandler(error)
290
- }
354
+ _handleParseComplete(msg) {
355
+ // if a prepared statement has a name and properly parses
356
+ // we track that its already been executed so we don't parse
357
+ // it again on the same client
358
+ if (this.activeQuery.name) {
359
+ this.connection.parsedStatements[this.activeQuery.name] = this.activeQuery.text
291
360
  }
292
-
293
- process.nextTick(() => {
294
- this.emit('end')
295
- })
296
- })
297
-
298
- con.on('notice', function (msg) {
299
- self.emit('notice', msg)
300
- })
301
- }
302
-
303
- Client.prototype.connect = function (callback) {
304
- if (callback) {
305
- this._connect(callback)
306
- return
307
361
  }
308
362
 
309
- return new this._Promise((resolve, reject) => {
310
- this._connect((error) => {
311
- if (error) {
312
- reject(error)
313
- } else {
314
- resolve()
315
- }
316
- })
317
- })
318
- }
319
-
320
- Client.prototype._attachListeners = function (con) {
321
- const self = this
322
- // delegate rowDescription to active query
323
- con.on('rowDescription', function (msg) {
324
- self.activeQuery.handleRowDescription(msg)
325
- })
326
-
327
- // delegate dataRow to active query
328
- con.on('dataRow', function (msg) {
329
- self.activeQuery.handleDataRow(msg)
330
- })
331
-
332
- // delegate portalSuspended to active query
333
- // eslint-disable-next-line no-unused-vars
334
- con.on('portalSuspended', function (msg) {
335
- self.activeQuery.handlePortalSuspended(con)
336
- })
337
-
338
- // delegate emptyQuery to active query
339
- // eslint-disable-next-line no-unused-vars
340
- con.on('emptyQuery', function (msg) {
341
- self.activeQuery.handleEmptyQuery(con)
342
- })
343
-
344
- // delegate commandComplete to active query
345
- con.on('commandComplete', function (msg) {
346
- self.activeQuery.handleCommandComplete(msg, con)
347
- })
348
-
349
- // if a prepared statement has a name and properly parses
350
- // we track that its already been executed so we don't parse
351
- // it again on the same client
352
- // eslint-disable-next-line no-unused-vars
353
- con.on('parseComplete', function (msg) {
354
- if (self.activeQuery.name) {
355
- con.parsedStatements[self.activeQuery.name] = self.activeQuery.text
356
- }
357
- })
358
-
359
- // eslint-disable-next-line no-unused-vars
360
- con.on('copyInResponse', function (msg) {
361
- self.activeQuery.handleCopyInResponse(self.connection)
362
- })
363
-
364
- con.on('copyData', function (msg) {
365
- self.activeQuery.handleCopyData(msg, self.connection)
366
- })
367
-
368
- con.on('notification', function (msg) {
369
- self.emit('notification', msg)
370
- })
371
- }
372
-
373
- Client.prototype.getStartupConf = function () {
374
- var params = this.connectionParameters
375
-
376
- var data = {
377
- user: params.user,
378
- database: params.database,
363
+ _handleCopyInResponse(msg) {
364
+ this.activeQuery.handleCopyInResponse(this.connection)
379
365
  }
380
366
 
381
- var appName = params.application_name || params.fallback_application_name
382
- if (appName) {
383
- data.application_name = appName
384
- }
385
- if (params.replication) {
386
- data.replication = '' + params.replication
387
- }
388
- if (params.statement_timeout) {
389
- data.statement_timeout = String(parseInt(params.statement_timeout, 10))
367
+ _handleCopyData(msg) {
368
+ this.activeQuery.handleCopyData(msg, this.connection)
390
369
  }
391
- if (params.idle_in_transaction_session_timeout) {
392
- data.idle_in_transaction_session_timeout = String(parseInt(params.idle_in_transaction_session_timeout, 10))
370
+
371
+ _handleNotification(msg) {
372
+ this.emit('notification', msg)
393
373
  }
394
- if (params.options) {
395
- data.options = params.options
374
+
375
+ _handleNotice(msg) {
376
+ this.emit('notice', msg)
396
377
  }
397
378
 
398
- return data
399
- }
379
+ getStartupConf() {
380
+ var params = this.connectionParameters
400
381
 
401
- Client.prototype.cancel = function (client, query) {
402
- if (client.activeQuery === query) {
403
- var con = this.connection
382
+ var data = {
383
+ user: params.user,
384
+ database: params.database,
385
+ }
404
386
 
405
- if (this.host && this.host.indexOf('/') === 0) {
406
- con.connect(this.host + '/.s.PGSQL.' + this.port)
407
- } else {
408
- con.connect(this.port, this.host)
387
+ var appName = params.application_name || params.fallback_application_name
388
+ if (appName) {
389
+ data.application_name = appName
390
+ }
391
+ if (params.replication) {
392
+ data.replication = '' + params.replication
393
+ }
394
+ if (params.statement_timeout) {
395
+ data.statement_timeout = String(parseInt(params.statement_timeout, 10))
396
+ }
397
+ if (params.idle_in_transaction_session_timeout) {
398
+ data.idle_in_transaction_session_timeout = String(parseInt(params.idle_in_transaction_session_timeout, 10))
399
+ }
400
+ if (params.options) {
401
+ data.options = params.options
409
402
  }
410
403
 
411
- // once connection is established send cancel message
412
- con.on('connect', function () {
413
- con.cancel(client.processID, client.secretKey)
414
- })
415
- } else if (client.queryQueue.indexOf(query) !== -1) {
416
- client.queryQueue.splice(client.queryQueue.indexOf(query), 1)
404
+ return data
417
405
  }
418
- }
419
-
420
- Client.prototype.setTypeParser = function (oid, format, parseFn) {
421
- return this._types.setTypeParser(oid, format, parseFn)
422
- }
423
406
 
424
- Client.prototype.getTypeParser = function (oid, format) {
425
- return this._types.getTypeParser(oid, format)
426
- }
407
+ cancel(client, query) {
408
+ if (client.activeQuery === query) {
409
+ var con = this.connection
427
410
 
428
- // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c
429
- Client.prototype.escapeIdentifier = function (str) {
430
- return '"' + str.replace(/"/g, '""') + '"'
431
- }
411
+ if (this.host && this.host.indexOf('/') === 0) {
412
+ con.connect(this.host + '/.s.PGSQL.' + this.port)
413
+ } else {
414
+ con.connect(this.port, this.host)
415
+ }
432
416
 
433
- // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c
434
- Client.prototype.escapeLiteral = function (str) {
435
- var hasBackslash = false
436
- var escaped = "'"
437
-
438
- for (var i = 0; i < str.length; i++) {
439
- var c = str[i]
440
- if (c === "'") {
441
- escaped += c + c
442
- } else if (c === '\\') {
443
- escaped += c + c
444
- hasBackslash = true
445
- } else {
446
- escaped += c
417
+ // once connection is established send cancel message
418
+ con.on('connect', function () {
419
+ con.cancel(client.processID, client.secretKey)
420
+ })
421
+ } else if (client.queryQueue.indexOf(query) !== -1) {
422
+ client.queryQueue.splice(client.queryQueue.indexOf(query), 1)
447
423
  }
448
424
  }
449
425
 
450
- escaped += "'"
451
-
452
- if (hasBackslash === true) {
453
- escaped = ' E' + escaped
426
+ setTypeParser(oid, format, parseFn) {
427
+ return this._types.setTypeParser(oid, format, parseFn)
454
428
  }
455
429
 
456
- return escaped
457
- }
430
+ getTypeParser(oid, format) {
431
+ return this._types.getTypeParser(oid, format)
432
+ }
458
433
 
459
- Client.prototype._pulseQueryQueue = function () {
460
- if (this.readyForQuery === true) {
461
- this.activeQuery = this.queryQueue.shift()
462
- if (this.activeQuery) {
463
- this.readyForQuery = false
464
- this.hasExecuted = true
434
+ // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c
435
+ escapeIdentifier(str) {
436
+ return '"' + str.replace(/"/g, '""') + '"'
437
+ }
465
438
 
466
- const queryError = this.activeQuery.submit(this.connection)
467
- if (queryError) {
468
- process.nextTick(() => {
469
- this.activeQuery.handleError(queryError, this.connection)
470
- this.readyForQuery = true
471
- this._pulseQueryQueue()
472
- })
439
+ // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c
440
+ escapeLiteral(str) {
441
+ var hasBackslash = false
442
+ var escaped = "'"
443
+
444
+ for (var i = 0; i < str.length; i++) {
445
+ var c = str[i]
446
+ if (c === "'") {
447
+ escaped += c + c
448
+ } else if (c === '\\') {
449
+ escaped += c + c
450
+ hasBackslash = true
451
+ } else {
452
+ escaped += c
473
453
  }
474
- } else if (this.hasExecuted) {
475
- this.activeQuery = null
476
- this.emit('drain')
477
454
  }
455
+
456
+ escaped += "'"
457
+
458
+ if (hasBackslash === true) {
459
+ escaped = ' E' + escaped
460
+ }
461
+
462
+ return escaped
478
463
  }
479
- }
480
464
 
481
- Client.prototype.query = function (config, values, callback) {
482
- // can take in strings, config object or query object
483
- var query
484
- var result
485
- var readTimeout
486
- var readTimeoutTimer
487
- var queryCallback
488
-
489
- if (config === null || config === undefined) {
490
- throw new TypeError('Client was passed a null or undefined query')
491
- } else if (typeof config.submit === 'function') {
492
- readTimeout = config.query_timeout || this.connectionParameters.query_timeout
493
- result = query = config
494
- if (typeof values === 'function') {
495
- query.callback = query.callback || values
496
- }
497
- } else {
498
- readTimeout = this.connectionParameters.query_timeout
499
- query = new Query(config, values, callback)
500
- if (!query.callback) {
501
- result = new this._Promise((resolve, reject) => {
502
- query.callback = (err, res) => (err ? reject(err) : resolve(res))
503
- })
465
+ _pulseQueryQueue() {
466
+ if (this.readyForQuery === true) {
467
+ this.activeQuery = this.queryQueue.shift()
468
+ if (this.activeQuery) {
469
+ this.readyForQuery = false
470
+ this.hasExecuted = true
471
+
472
+ const queryError = this.activeQuery.submit(this.connection)
473
+ if (queryError) {
474
+ process.nextTick(() => {
475
+ this.activeQuery.handleError(queryError, this.connection)
476
+ this.readyForQuery = true
477
+ this._pulseQueryQueue()
478
+ })
479
+ }
480
+ } else if (this.hasExecuted) {
481
+ this.activeQuery = null
482
+ this.emit('drain')
483
+ }
504
484
  }
505
485
  }
506
486
 
507
- if (readTimeout) {
508
- queryCallback = query.callback
487
+ query(config, values, callback) {
488
+ // can take in strings, config object or query object
489
+ var query
490
+ var result
491
+ var readTimeout
492
+ var readTimeoutTimer
493
+ var queryCallback
494
+
495
+ if (config === null || config === undefined) {
496
+ throw new TypeError('Client was passed a null or undefined query')
497
+ } else if (typeof config.submit === 'function') {
498
+ readTimeout = config.query_timeout || this.connectionParameters.query_timeout
499
+ result = query = config
500
+ if (typeof values === 'function') {
501
+ query.callback = query.callback || values
502
+ }
503
+ } else {
504
+ readTimeout = this.connectionParameters.query_timeout
505
+ query = new Query(config, values, callback)
506
+ if (!query.callback) {
507
+ result = new this._Promise((resolve, reject) => {
508
+ query.callback = (err, res) => (err ? reject(err) : resolve(res))
509
+ })
510
+ }
511
+ }
509
512
 
510
- readTimeoutTimer = setTimeout(() => {
511
- var error = new Error('Query read timeout')
513
+ if (readTimeout) {
514
+ queryCallback = query.callback
512
515
 
513
- process.nextTick(() => {
514
- query.handleError(error, this.connection)
515
- })
516
+ readTimeoutTimer = setTimeout(() => {
517
+ var error = new Error('Query read timeout')
518
+
519
+ process.nextTick(() => {
520
+ query.handleError(error, this.connection)
521
+ })
522
+
523
+ queryCallback(error)
524
+
525
+ // we already returned an error,
526
+ // just do nothing if query completes
527
+ query.callback = () => {}
516
528
 
517
- queryCallback(error)
529
+ // Remove from queue
530
+ var index = this.queryQueue.indexOf(query)
531
+ if (index > -1) {
532
+ this.queryQueue.splice(index, 1)
533
+ }
518
534
 
519
- // we already returned an error,
520
- // just do nothing if query completes
521
- query.callback = () => {}
535
+ this._pulseQueryQueue()
536
+ }, readTimeout)
522
537
 
523
- // Remove from queue
524
- var index = this.queryQueue.indexOf(query)
525
- if (index > -1) {
526
- this.queryQueue.splice(index, 1)
538
+ query.callback = (err, res) => {
539
+ clearTimeout(readTimeoutTimer)
540
+ queryCallback(err, res)
527
541
  }
542
+ }
528
543
 
529
- this._pulseQueryQueue()
530
- }, readTimeout)
544
+ if (this.binary && !query.binary) {
545
+ query.binary = true
546
+ }
531
547
 
532
- query.callback = (err, res) => {
533
- clearTimeout(readTimeoutTimer)
534
- queryCallback(err, res)
548
+ if (query._result && !query._result._types) {
549
+ query._result._types = this._types
535
550
  }
536
- }
537
551
 
538
- if (this.binary && !query.binary) {
539
- query.binary = true
540
- }
552
+ if (!this._queryable) {
553
+ process.nextTick(() => {
554
+ query.handleError(new Error('Client has encountered a connection error and is not queryable'), this.connection)
555
+ })
556
+ return result
557
+ }
541
558
 
542
- if (query._result && !query._result._types) {
543
- query._result._types = this._types
544
- }
559
+ if (this._ending) {
560
+ process.nextTick(() => {
561
+ query.handleError(new Error('Client was closed and is not queryable'), this.connection)
562
+ })
563
+ return result
564
+ }
545
565
 
546
- if (!this._queryable) {
547
- process.nextTick(() => {
548
- query.handleError(new Error('Client has encountered a connection error and is not queryable'), this.connection)
549
- })
566
+ this.queryQueue.push(query)
567
+ this._pulseQueryQueue()
550
568
  return result
551
569
  }
552
570
 
553
- if (this._ending) {
554
- process.nextTick(() => {
555
- query.handleError(new Error('Client was closed and is not queryable'), this.connection)
556
- })
557
- return result
558
- }
571
+ end(cb) {
572
+ this._ending = true
559
573
 
560
- this.queryQueue.push(query)
561
- this._pulseQueryQueue()
562
- return result
563
- }
574
+ // if we have never connected, then end is a noop, callback immediately
575
+ if (!this.connection._connecting) {
576
+ if (cb) {
577
+ cb()
578
+ } else {
579
+ return this._Promise.resolve()
580
+ }
581
+ }
564
582
 
565
- Client.prototype.end = function (cb) {
566
- this._ending = true
583
+ if (this.activeQuery || !this._queryable) {
584
+ // if we have an active query we need to force a disconnect
585
+ // on the socket - otherwise a hung query could block end forever
586
+ this.connection.stream.destroy()
587
+ } else {
588
+ this.connection.end()
589
+ }
567
590
 
568
- // if we have never connected, then end is a noop, callback immediately
569
- if (!this.connection._connecting) {
570
591
  if (cb) {
571
- cb()
592
+ this.connection.once('end', cb)
572
593
  } else {
573
- return this._Promise.resolve()
594
+ return new this._Promise((resolve) => {
595
+ this.connection.once('end', resolve)
596
+ })
574
597
  }
575
598
  }
576
-
577
- if (this.activeQuery || !this._queryable) {
578
- // if we have an active query we need to force a disconnect
579
- // on the socket - otherwise a hung query could block end forever
580
- this.connection.stream.destroy()
581
- } else {
582
- this.connection.end()
583
- }
584
-
585
- if (cb) {
586
- this.connection.once('end', cb)
587
- } else {
588
- return new this._Promise((resolve) => {
589
- this.connection.once('end', resolve)
590
- })
591
- }
592
599
  }
593
600
 
594
601
  // expose a Query constructor