Using promises with node-pg

While it is possible to use node-pg with just raw callbacks, as soon as you want to use transactions the chances of getting it right dwindle rapidly.

Using a promise library helps remove some of the pain. I ended up with something like this (using Q):

var Q = require('q'),
    pg = require('pg'),
    Connection = require('./Connection');

module.exports = function(connString) {
    this.connect = function() {
        var deferred = Q.defer();

        pg.connect(connString, function(err, client, done) {
            if (err) {
                return deferred.reject(new Error(err));
            }

            deferred.resolve(new Connection(client, done));
        });

        return deferred.promise;
    };
};
var Q = require('q'),
    pg = require('pg');

module.exports = function(client, done) {
    this.begin = function() {
        return this.query('BEGIN;', []);
    };

    this.query = function(sql, args) {
        var deferred = Q.defer();

        client.query(sql, args, function(err, result) {
            if (err) {
                err.message = err.message + ' (Query: ' + sql + ', Args: ' + args + ')';
                return deferred.reject(err);
            }

            deferred.resolve(result.rows);
        });

        return deferred.promise;
    };

    this.rollback = function() {
        var deferred = Q.defer();

        client.query('ROLLBACK', function(err) {
            deferred.resolve();
            return done(err);
        });

        return deferred.promise;
    };

    this.commit = function() {
        var deferred = Q.defer();

        client.query('COMMIT', function(err) {
            if (err) {
                deferred.reject(err);
            } else {
                deferred.resolve();
            }
            return done(err);
        });

        return deferred.promise;
    };

    this.close = function() {
        done();
    };
}

Which you can use like this:

var db = new Db(connString);

return db.connect().then(function(conn) {
    return db.begin().then(function() {
        return conn.query('SELECT something FROM foo WHERE id = $1;', [id]).then(function(rows) {
            return conn.query('INSERT INTO ...', [...]);
        }).then(function() {
            return conn.commit();
        });
    }).fin(conn.close);
});

And remove at least some of the risk of failing to return the connection to the pool, or otherwise bungling your error handling.

Advertisements

One thought on “Using promises with node-pg

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s