Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Manually promisifying pg.connect with Bluebird

I want to promisify node-postgres' pg.connect method along with the inner connection.query method provided in the callback.

I can .promisify the latter, but I need to implement the first one manually (if I'm missing something here, please explain).

The thing is, I'm not sure if this code is correct or should be improved? The code is working, I just want to know if I'm using Bluebird as meant.

// aliases
var asPromise = Promise.promisify;

// save reference to original method
var connect = pg.connect.bind(pg);

// promisify method
pg.connect = function (data) {
  var deferred = Promise.defer();

  connect(data, function promisify(err, connection, release) {
    if (err) return deferred.reject(err);

    // promisify query factory
    connection.query = asPromise(connection.query, connection);

    // resolve promised connection
    deferred.resolve([connection,release]);
  });

  return deferred.promise;
};
like image 290
luisfarzati Avatar asked May 27 '14 04:05

luisfarzati


3 Answers

Throw all that horrible callback code away, then do this somewhere in your application initialization:

var pg = require("pg");
var Promise = require("bluebird");

Object.keys(pg).forEach(function(key) {
    var Class = pg[key];
    if (typeof Class === "function") {
        Promise.promisifyAll(Class.prototype);
        Promise.promisifyAll(Class);
    }
})
Promise.promisifyAll(pg);

Later in anywhere you can use the pg module as if it was designed to use promises to begin with:

// Later
// Don't even need to require bluebird here
var pg = require("pg");
// Note how it's the pg API but with *Async suffix
pg.connectAsync(...).spread(function(connection, release) {
     return connection.queryAsync("...")
         .then(function(result) {
            console.log("rows", result.rows);
         })
         .finally(function() {
            // Creating a superfluous anonymous function cos I am
            // unsure of your JS skill level
            release();
         });
});
like image 67
Esailija Avatar answered Nov 05 '22 00:11

Esailija


By now there are a number of libraries which do this for you:

  • pg-promise - generic Promises/A+ for PG
  • postgres-bluebird
  • dbh-ph
  • pg-bluebird
like image 4
Flimzy Avatar answered Nov 05 '22 01:11

Flimzy


Update for bluebird 3:

The pg.connectAsync(...).spread(function(connection, release) { ... }) call will not work anymore, because the API of bluebird has changed: http://bluebirdjs.com/docs/new-in-bluebird-3.html#promisification-api-changes .

The problem is that promisifyAll in bluebird 3 does not handle multiple arguments by default. This results in the .spread() call reporting a TypeError like the following:

TypeError: expecting an array or an iterable object but got [object Null]

To solve this, you can explicitly enable multiple arguments for connect / connectAsync. Do the following after all the promisifying stuff mentioned above:

...
pg.connectAsync = Promise.promisify(pg.connect, { multiArgs: true });
like image 3
Oliver Avatar answered Nov 05 '22 00:11

Oliver