Upgrading to 7.0
node-postgres at 7.0 introduces somewhat significant breaking changes to the public API.
node version support
Starting with pg@7.0
the earliest version of node supported will be node@4.x LTS
. Support for node@0.12.x
and node@.10.x
is dropped, and the module wont work as it relies on new es6 features not available in older versions of node.
pg singleton
In the past there was a singleton pool manager attached to the root pg
object in the package. This singleton could be used to provision connection pools automatically by calling pg.connect
. This API caused a lot of confusion for users. It also introduced a opaque module-managed singleton which was difficult to reason about, debug, error-prone, and inflexible. Starting in pg@6.0 the methods' documentation was removed, and starting in pg@6.3 the methods were deprecated with a warning message.
If your application still relies on these they will be gone in pg@7.0
. In order to migrate you can do the following:
// old way, deprecated in 6.3.0:// connection using global singletonpg.connect(function(err, client, done) {client.query(/* etc, etc */)done()})// singleton pool shutdownpg.end()// ------------------// new way, available since 6.0.0:// create a poolvar pool = new pg.Pool()// connection using created poolpool.connect(function(err, client, done) {client.query(/* etc, etc */)done()})// pool shutdownpool.end()
node-postgres ships with a built-in pool object provided by pg-pool which is already used internally by the pg.connect
and pg.end
methods. Migrating to a user-managed pool (or set of pools) allows you to more directly control their set up their life-cycle.
client.query(...).on
Before pg@7.0
the client.query
method would always return an instance of a query. The query instance was an event emitter, accepted a callback, and was also a promise. A few problems...
- too many flow control options on a single object was confusing
- event emitter
.on('error')
does not mix well with promise.catch
- the
row
event was a common source of errors: it looks like a stream but has no support for back-pressure, misleading users into trying to pipe results or handling them in the event emitter for a desired performance gain. - error handling with a
.done
and.error
emitter pair for every query is cumbersome and returning the emitter fromclient.query
indicated this sort of pattern may be encouraged: it is not.
Starting with pg@7.0
the return value client.query
will be dependent on what you pass to the method: I think this aligns more with how most node libraries handle the callback/promise combo, and I hope it will make the "just works" :tm: feeling better while reducing surface area and surprises around event emitter / callback combos.
client.query with a callback
const query = client.query('SELECT NOW()', (err, res) => {/* etc, etc */})assert(query === undefined) // true
If you pass a callback to the method client.query
will return undefined
. This limits flow control to the callback which is in-line with almost all of node's core APIs.
client.query without a callback
const query = client.query('SELECT NOW()')assert(query instanceof Promise) // trueassert(query.on === undefined) // truequery.then((res) => /* etc, etc */)
If you do not pass a callback client.query
will return an instance of a Promise
. This will not be a query instance and will not be an event emitter. This is in line with how most promise-based APIs work in node.
client.query(Submittable)
client.query
has always accepted any object that has a .submit
method on it. In this scenario the client calls .submit
on the object, delegating execution responsibility to it. In this situation the client also returns the instance it was passed. This is how pg-cursor and pg-query-stream work. So, if you need the event emitter functionality on your queries for some reason, it is still possible because Query
is an instance of Submittable
:
const { Client, Query } = require('pg')const query = client.query(new Query('SELECT NOW()'))query.on('row', row => {})query.on('end', res => {})query.on('error', res => {})
Query
is considered a public, documented part of the API of node-postgres and this form will be supported indefinitely.
note: I have been building apps with node-postgres for almost 7 years. In that time I have never used the event emitter API as the primary way to execute queries. I used to use callbacks and now I use async/await. If you need to stream results I highly recommend you use pg-cursor or pg-query-stream and not the query object as an event emitter.