Skip to content

Commit 66e1e76

Browse files
committed
More refactoring
1 parent 04e5297 commit 66e1e76

File tree

2 files changed

+136
-127
lines changed

2 files changed

+136
-127
lines changed

packages/pg/bench.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ const run = async () => {
6161
queries = await bench(client, insert, seconds * 1000)
6262
console.log('insert queries:', queries)
6363
console.log('qps', queries / seconds)
64-
console.log('on my laptop best so far seen 5799 qps')
64+
console.log('on my laptop best so far seen 6303 qps')
6565

6666
console.log('')
6767
console.log('Warming up bytea test')

packages/pg/lib/client.js

+135-126
Original file line numberDiff line numberDiff line change
@@ -122,94 +122,25 @@ class Client extends EventEmitter {
122122
con.startup(self.getStartupConf())
123123
})
124124

125-
function checkPgPass(cb) {
126-
return function (msg) {
127-
if (typeof self.password === 'function') {
128-
self._Promise
129-
.resolve()
130-
.then(() => self.password())
131-
.then((pass) => {
132-
if (pass !== undefined) {
133-
if (typeof pass !== 'string') {
134-
con.emit('error', new TypeError('Password must be a string'))
135-
return
136-
}
137-
self.connectionParameters.password = self.password = pass
138-
} else {
139-
self.connectionParameters.password = self.password = null
140-
}
141-
cb(msg)
142-
})
143-
.catch((err) => {
144-
con.emit('error', err)
145-
})
146-
} else if (self.password !== null) {
147-
cb(msg)
148-
} else {
149-
pgPass(self.connectionParameters, function (pass) {
150-
if (undefined !== pass) {
151-
self.connectionParameters.password = self.password = pass
152-
}
153-
cb(msg)
154-
})
155-
}
156-
}
157-
}
158-
159125
// password request handling
160-
con.on(
161-
'authenticationCleartextPassword',
162-
checkPgPass(function () {
163-
con.password(self.password)
164-
})
165-
)
166-
126+
con.on('authenticationCleartextPassword', this.handleAuthenticationCleartextPassword.bind(this))
167127
// password request handling
168-
con.on(
169-
'authenticationMD5Password',
170-
checkPgPass(function (msg) {
171-
con.password(utils.postgresMd5PasswordHash(self.user, self.password, msg.salt))
172-
})
173-
)
174-
175-
// password request handling (SASL)
176-
var saslSession
177-
con.on(
178-
'authenticationSASL',
179-
checkPgPass(function (msg) {
180-
saslSession = sasl.startSession(msg.mechanisms)
181-
182-
con.sendSASLInitialResponseMessage(saslSession.mechanism, saslSession.response)
183-
})
184-
)
185-
186-
// password request handling (SASL)
187-
con.on('authenticationSASLContinue', function (msg) {
188-
sasl.continueSession(saslSession, self.password, msg.data)
189-
190-
con.sendSCRAMClientFinalMessage(saslSession.response)
191-
})
192-
128+
con.on('authenticationMD5Password', this.handleAuthenticationMD5Password.bind(this))
193129
// password request handling (SASL)
194-
con.on('authenticationSASLFinal', function (msg) {
195-
sasl.finalizeSession(saslSession, msg.data)
196-
197-
saslSession = null
198-
})
199-
200-
con.once('backendKeyData', function (msg) {
201-
self.processID = msg.processID
202-
self.secretKey = msg.secretKey
203-
})
130+
con.on('authenticationSASL', this.handleAuthenticationSASL.bind(this))
131+
con.on('authenticationSASLContinue', this.handleAuthenticationSASLContinue.bind(this))
132+
con.on('authenticationSASLFinal', this.handleAuthenticationSASLFinal.bind(this))
133+
con.once('backendKeyData', this.handleBackendKeyData.bind(this))
204134

135+
this._connectionCallback = callback
205136
const connectingErrorHandler = (err) => {
206137
if (this._connectionError) {
207138
return
208139
}
209140
this._connectionError = true
210141
clearTimeout(connectionTimeoutHandle)
211-
if (callback) {
212-
return callback(err)
142+
if (this._connectionCallback) {
143+
return this._connectionCallback(err)
213144
}
214145
this.emit('error', err)
215146
}
@@ -237,35 +168,28 @@ class Client extends EventEmitter {
237168

238169
// hook up query handling events to connection
239170
// after the connection initially becomes ready for queries
240-
con.once('readyForQuery', function () {
171+
con.once('readyForQuery', () => {
241172
self._connecting = false
242173
self._connected = true
243-
self._attachListeners(con)
244174
con.removeListener('error', connectingErrorHandler)
245175
con.removeListener('errorMessage', connectingErrorHandler)
246176
con.on('error', connectedErrorHandler)
247177
con.on('errorMessage', connectedErrorMessageHandler)
248178
clearTimeout(connectionTimeoutHandle)
249179

250180
// process possible callback argument to Client#connect
251-
if (callback) {
252-
callback(null, self)
181+
if (this._connectionCallback) {
182+
this._connectionCallback(null, self)
253183
// remove callback for proper error handling
254184
// after the connect event
255-
callback = null
185+
this._connectionCallback = null
256186
}
257187
self.emit('connect')
258188
})
259189

260-
con.on('readyForQuery', function () {
261-
var activeQuery = self.activeQuery
262-
self.activeQuery = null
263-
self.readyForQuery = true
264-
if (activeQuery) {
265-
activeQuery.handleReadyForQuery(con)
266-
}
267-
self._pulseQueryQueue()
268-
})
190+
con.on('readyForQuery', this.handleReadyForQuery.bind(this))
191+
con.on('notice', this.handleNotice.bind(this))
192+
self._attachListeners(con)
269193

270194
con.once('end', () => {
271195
const error = this._ending ? new Error('Connection terminated') : new Error('Connection terminated unexpectedly')
@@ -279,8 +203,8 @@ class Client extends EventEmitter {
279203
// treat this as an error unless we've already emitted an error
280204
// during connection.
281205
if (this._connecting && !this._connectionError) {
282-
if (callback) {
283-
callback(error)
206+
if (this._connectionCallback) {
207+
this._connectionCallback(error)
284208
} else {
285209
connectedErrorHandler(error)
286210
}
@@ -293,10 +217,6 @@ class Client extends EventEmitter {
293217
this.emit('end')
294218
})
295219
})
296-
297-
con.on('notice', function (msg) {
298-
self.emit('notice', msg)
299-
})
300220
}
301221

302222
connect(callback) {
@@ -317,47 +237,132 @@ class Client extends EventEmitter {
317237
}
318238

319239
_attachListeners(con) {
320-
const self = this
321-
// delegate rowDescription to active query
322-
con.on('rowDescription', function (msg) {
323-
self.activeQuery.handleRowDescription(msg)
240+
con.on('rowDescription', this.handleRowDescription.bind(this))
241+
con.on('dataRow', this.handleDataRow.bind(this))
242+
con.on('portalSuspended', this.handlePortalSuspended.bind(this))
243+
con.on('emptyQuery', this.handleEmptyQuery.bind(this))
244+
con.on('commandComplete', this.handleCommandComplete.bind(this))
245+
con.on('parseComplete', this.handleParseComplete.bind(this))
246+
con.on('copyInResponse', this.handleCopyInResponse.bind(this))
247+
con.on('copyData', this.handleCopyData.bind(this))
248+
con.on('notification', this.handleNotification.bind(this))
249+
}
250+
251+
// TODO(bmc): deprecate pgpass "built in" integration since this.password can be a function
252+
// it can be supplied by the user if required - this is a breaking change!
253+
_checkPgPass(cb) {
254+
return function (msg) {
255+
if (typeof this.password === 'function') {
256+
this._Promise
257+
.resolve()
258+
.then(() => this.password())
259+
.then((pass) => {
260+
if (pass !== undefined) {
261+
if (typeof pass !== 'string') {
262+
con.emit('error', new TypeError('Password must be a string'))
263+
return
264+
}
265+
this.connectionParameters.password = this.password = pass
266+
} else {
267+
this.connectionParameters.password = this.password = null
268+
}
269+
cb(msg)
270+
})
271+
.catch((err) => {
272+
con.emit('error', err)
273+
})
274+
} else if (this.password !== null) {
275+
cb(msg)
276+
} else {
277+
pgPass(this.connectionParameters, function (pass) {
278+
if (undefined !== pass) {
279+
this.connectionParameters.password = this.password = pass
280+
}
281+
cb(msg)
282+
})
283+
}
284+
}
285+
}
286+
287+
handleAuthenticationCleartextPassword(msg) {
288+
this._checkPgPass(() => {
289+
this.connection.password(this.password)
324290
})
291+
}
325292

326-
// delegate dataRow to active query
327-
con.on('dataRow', function (msg) {
328-
self.activeQuery.handleDataRow(msg)
293+
handleAuthenticationMD5Password(msg) {
294+
this._checkPgPass((msg) => {
295+
const hashedPassword = utils.postgresMd5PasswordHash(this.user, this.password, msg.salt)
296+
this.connection.password(hashedPassword)
329297
})
298+
}
330299

331-
// delegate portalSuspended to active query
332-
// eslint-disable-next-line no-unused-vars
333-
con.on('portalSuspended', function (msg) {
334-
self.activeQuery.handlePortalSuspended(con)
300+
handleAuthenticationSASL(msg) {
301+
this._checkPgPass((msg) => {
302+
this.saslSession = sasl.startSession(msg.mechanisms)
303+
const con = this.connection
304+
con.sendSASLInitialResponseMessage(saslSession.mechanism, saslSession.response)
335305
})
306+
}
336307

308+
handleAuthenticationSASLContinue(msg) {
309+
const { saslSession } = this
310+
sasl.continueSession(saslSession, self.password, msg.data)
311+
con.sendSCRAMClientFinalMessage(saslSession.response)
312+
}
313+
314+
handleAuthenticationSASLFinal(msg) {
315+
sasl.finalizeSession(this.saslSession, msg.data)
316+
this.saslSession = null
317+
}
318+
319+
handleBackendKeyData(msg) {
320+
this.processID = msg.processID
321+
this.secretKey = msg.secretKey
322+
}
323+
324+
handleReadyForQuery(msg) {
325+
const { activeQuery } = this
326+
this.activeQuery = null
327+
this.readyForQuery = true
328+
if (activeQuery) {
329+
activeQuery.handleReadyForQuery(this.connection)
330+
}
331+
this._pulseQueryQueue()
332+
}
333+
334+
handleRowDescription(msg) {
335+
// delegate rowDescription to active query
336+
this.activeQuery.handleRowDescription(msg)
337+
}
338+
339+
handleDataRow(msg) {
340+
// delegate dataRow to active query
341+
this.activeQuery.handleDataRow(msg)
342+
}
343+
344+
handlePortalSuspended(msg) {
345+
// delegate portalSuspended to active query
346+
this.activeQuery.handlePortalSuspended(this.connection)
347+
}
348+
349+
handleEmptyQuery(msg) {
337350
// delegate emptyQuery to active query
338-
// eslint-disable-next-line no-unused-vars
339-
con.on('emptyQuery', function (msg) {
340-
self.activeQuery.handleEmptyQuery(con)
341-
})
351+
this.activeQuery.handleEmptyQuery(this.connection)
352+
}
342353

354+
handleCommandComplete(msg) {
343355
// delegate commandComplete to active query
344-
con.on('commandComplete', function (msg) {
345-
self.activeQuery.handleCommandComplete(msg, con)
346-
})
356+
this.activeQuery.handleCommandComplete(msg, this.connection)
357+
}
347358

359+
handleParseComplete(msg) {
348360
// if a prepared statement has a name and properly parses
349361
// we track that its already been executed so we don't parse
350362
// it again on the same client
351-
// eslint-disable-next-line no-unused-vars
352-
con.on('parseComplete', function (msg) {
353-
if (self.activeQuery.name) {
354-
con.parsedStatements[self.activeQuery.name] = self.activeQuery.text
355-
}
356-
})
357-
358-
con.on('copyInResponse', this.handleCopyInResponse.bind(this))
359-
con.on('copyData', this.handleCopyData.bind(this))
360-
con.on('notification', this.handleNotification.bind(this))
363+
if (this.activeQuery.name) {
364+
this.connection.parsedStatements[this.activeQuery.name] = this.activeQuery.text
365+
}
361366
}
362367

363368
handleCopyInResponse(msg) {
@@ -372,6 +377,10 @@ class Client extends EventEmitter {
372377
this.emit('notification', msg)
373378
}
374379

380+
handleNotice(msg) {
381+
this.emit('notice', msg)
382+
}
383+
375384
getStartupConf() {
376385
var params = this.connectionParameters
377386

0 commit comments

Comments
 (0)