@@ -36,6 +36,7 @@ var Client = function (config) {
36
36
this . _connecting = false
37
37
this . _connected = false
38
38
this . _connectionError = false
39
+ this . _queryable = true
39
40
40
41
this . connection = c . connection || new Connection ( {
41
42
stream : c . stream ,
@@ -52,16 +53,31 @@ var Client = function (config) {
52
53
53
54
util . inherits ( Client , EventEmitter )
54
55
55
- Client . prototype . connect = function ( callback ) {
56
+ Client . prototype . _errorAllQueries = function ( err ) {
57
+ const enqueueError = ( query ) => {
58
+ process . nextTick ( ( ) => {
59
+ query . handleError ( err , this . connection )
60
+ } )
61
+ }
62
+
63
+ if ( this . activeQuery ) {
64
+ enqueueError ( this . activeQuery )
65
+ this . activeQuery = null
66
+ }
67
+
68
+ this . queryQueue . forEach ( enqueueError )
69
+ this . queryQueue . length = 0
70
+ }
71
+
72
+ Client . prototype . _connect = function ( callback ) {
56
73
var self = this
57
74
var con = this . connection
58
75
if ( this . _connecting || this . _connected ) {
59
76
const err = new Error ( 'Client has already been connected. You cannot reuse a client.' )
60
- if ( callback ) {
77
+ process . nextTick ( ( ) => {
61
78
callback ( err )
62
- return undefined
63
- }
64
- return Promise . reject ( err )
79
+ } )
80
+ return
65
81
}
66
82
this . _connecting = true
67
83
@@ -126,15 +142,25 @@ Client.prototype.connect = function (callback) {
126
142
}
127
143
128
144
const connectedErrorHandler = ( err ) => {
129
- if ( this . activeQuery ) {
130
- var activeQuery = self . activeQuery
131
- this . activeQuery = null
132
- return activeQuery . handleError ( err , con )
133
- }
145
+ this . _queryable = false
146
+ this . _errorAllQueries ( err )
134
147
this . emit ( 'error' , err )
135
148
}
136
149
150
+ const connectedErrorMessageHandler = ( msg ) => {
151
+ const activeQuery = this . activeQuery
152
+
153
+ if ( ! activeQuery ) {
154
+ connectedErrorHandler ( msg )
155
+ return
156
+ }
157
+
158
+ this . activeQuery = null
159
+ activeQuery . handleError ( msg , con )
160
+ }
161
+
137
162
con . on ( 'error' , connectingErrorHandler )
163
+ con . on ( 'errorMessage' , connectingErrorHandler )
138
164
139
165
// hook up query handling events to connection
140
166
// after the connection initially becomes ready for queries
@@ -143,7 +169,9 @@ Client.prototype.connect = function (callback) {
143
169
self . _connected = true
144
170
self . _attachListeners ( con )
145
171
con . removeListener ( 'error' , connectingErrorHandler )
172
+ con . removeListener ( 'errorMessage' , connectingErrorHandler )
146
173
con . on ( 'error' , connectedErrorHandler )
174
+ con . on ( 'errorMessage' , connectedErrorMessageHandler )
147
175
148
176
// process possible callback argument to Client#connect
149
177
if ( callback ) {
@@ -166,43 +194,53 @@ Client.prototype.connect = function (callback) {
166
194
} )
167
195
168
196
con . once ( 'end' , ( ) => {
169
- if ( this . activeQuery ) {
170
- var disconnectError = new Error ( 'Connection terminated' )
171
- this . activeQuery . handleError ( disconnectError , con )
172
- this . activeQuery = null
173
- }
197
+ const error = this . _ending
198
+ ? new Error ( 'Connection terminated' )
199
+ : new Error ( 'Connection terminated unexpectedly' )
200
+
201
+ this . _errorAllQueries ( error )
202
+
174
203
if ( ! this . _ending ) {
175
204
// if the connection is ended without us calling .end()
176
205
// on this client then we have an unexpected disconnection
177
206
// treat this as an error unless we've already emitted an error
178
207
// during connection.
179
- const error = new Error ( 'Connection terminated unexpectedly' )
180
208
if ( this . _connecting && ! this . _connectionError ) {
181
209
if ( callback ) {
182
210
callback ( error )
183
211
} else {
184
- this . emit ( 'error' , error )
212
+ connectedErrorHandler ( error )
185
213
}
186
214
} else if ( ! this . _connectionError ) {
187
- this . emit ( 'error' , error )
215
+ connectedErrorHandler ( error )
188
216
}
189
217
}
190
- this . emit ( 'end' )
218
+
219
+ process . nextTick ( ( ) => {
220
+ this . emit ( 'end' )
221
+ } )
191
222
} )
192
223
193
224
con . on ( 'notice' , function ( msg ) {
194
225
self . emit ( 'notice' , msg )
195
226
} )
227
+ }
196
228
197
- if ( ! callback ) {
198
- return new global . Promise ( ( resolve , reject ) => {
199
- this . once ( 'error' , reject )
200
- this . once ( 'connect' , ( ) => {
201
- this . removeListener ( 'error' , reject )
229
+ Client . prototype . connect = function ( callback ) {
230
+ if ( callback ) {
231
+ this . _connect ( callback )
232
+ return
233
+ }
234
+
235
+ return new Promise ( ( resolve , reject ) => {
236
+ this . _connect ( ( error ) => {
237
+ if ( error ) {
238
+ reject ( error )
239
+ } else {
202
240
resolve ( )
203
- } )
241
+ }
204
242
} )
205
- }
243
+ } )
206
244
}
207
245
208
246
Client . prototype . _attachListeners = function ( con ) {
@@ -340,7 +378,15 @@ Client.prototype._pulseQueryQueue = function () {
340
378
if ( this . activeQuery ) {
341
379
this . readyForQuery = false
342
380
this . hasExecuted = true
343
- this . activeQuery . submit ( this . connection )
381
+
382
+ const queryError = this . activeQuery . submit ( this . connection )
383
+ if ( queryError ) {
384
+ process . nextTick ( ( ) => {
385
+ this . activeQuery . handleError ( queryError , this . connection )
386
+ this . readyForQuery = true
387
+ this . _pulseQueryQueue ( )
388
+ } )
389
+ }
344
390
} else if ( this . hasExecuted ) {
345
391
this . activeQuery = null
346
392
this . emit ( 'drain' )
@@ -379,25 +425,40 @@ Client.prototype.query = function (config, values, callback) {
379
425
query . _result . _getTypeParser = this . _types . getTypeParser . bind ( this . _types )
380
426
}
381
427
428
+ if ( ! this . _queryable ) {
429
+ process . nextTick ( ( ) => {
430
+ query . handleError ( new Error ( 'Client has encountered a connection error and is not queryable' ) , this . connection )
431
+ } )
432
+ return result
433
+ }
434
+
435
+ if ( this . _ending ) {
436
+ process . nextTick ( ( ) => {
437
+ query . handleError ( new Error ( 'Client was closed and is not queryable' ) , this . connection )
438
+ } )
439
+ return result
440
+ }
441
+
382
442
this . queryQueue . push ( query )
383
443
this . _pulseQueryQueue ( )
384
444
return result
385
445
}
386
446
387
447
Client . prototype . end = function ( cb ) {
388
448
this . _ending = true
449
+
389
450
if ( this . activeQuery ) {
390
451
// if we have an active query we need to force a disconnect
391
452
// on the socket - otherwise a hung query could block end forever
392
- this . connection . stream . destroy ( new Error ( 'Connection terminated by user' ) )
393
- return cb ? cb ( ) : Promise . resolve ( )
453
+ this . connection . stream . destroy ( )
454
+ } else {
455
+ this . connection . end ( )
394
456
}
457
+
395
458
if ( cb ) {
396
- this . connection . end ( )
397
459
this . connection . once ( 'end' , cb )
398
460
} else {
399
- return new global . Promise ( ( resolve , reject ) => {
400
- this . connection . end ( )
461
+ return new Promise ( ( resolve ) => {
401
462
this . connection . once ( 'end' , resolve )
402
463
} )
403
464
}
0 commit comments