From 2fd9c77085c1efd66306f4dfe40ae4f05b7dede7 Mon Sep 17 00:00:00 2001 From: Brian C Date: Fri, 10 Jun 2016 17:18:19 -0500 Subject: [PATCH] Make Query & NativeQuery implement the promise interface (#1047) * Make Query & NativeQuery implement the promise interface * Fix test * Use older node API for checking listener length * Do not test for promises on node@v0.10.0 --- lib/native/query.js | 17 ++++++++++ lib/query.js | 23 +++++++++++-- .../client/query-as-promise-tests.js | 33 +++++++++++++++++++ .../integration/client/type-coercion-tests.js | 4 +-- 4 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 test/integration/client/query-as-promise-tests.js diff --git a/lib/native/query.js b/lib/native/query.js index 2c4bc47d..73fdf39f 100644 --- a/lib/native/query.js +++ b/lib/native/query.js @@ -26,6 +26,23 @@ var NativeQuery = module.exports = function(native) { util.inherits(NativeQuery, EventEmitter); +NativeQuery.prototype.then = function(callback) { + return this.promise().then(callback); +}; + +NativeQuery.prototype.catch = function(callback) { + return this.promise().catch(callback); +}; + +NativeQuery.prototype.promise = function() { + if (this._promise) return this._promise; + this._promise = new Promise(function(resolve, reject) { + this.once('end', resolve); + this.once('error', reject); + }.bind(this)); + return this._promise; +}; + NativeQuery.prototype.handleError = function(err) { var self = this; //copy pq error fields into the error object diff --git a/lib/query.js b/lib/query.js index cd57bd8e..ab47b653 100644 --- a/lib/query.js +++ b/lib/query.js @@ -26,11 +26,29 @@ var Query = function(config, values, callback) { this._result = new Result(config.rowMode, config.types); this.isPreparedStatement = false; this._canceledDueToError = false; + this._promise = null; EventEmitter.call(this); }; util.inherits(Query, EventEmitter); +Query.prototype.then = function(callback) { + return this.promise().then(callback); +}; + +Query.prototype.catch = function(callback) { + return this.promise().catch(callback); +}; + +Query.prototype.promise = function() { + if (this._promise) return this._promise; + this._promise = new Promise(function(resolve, reject) { + this.once('end', resolve); + this.once('error', reject); + }.bind(this)); + return this._promise; +}; + Query.prototype.requiresPreparation = function() { //named queries must always be prepared if(this.name) { return true; } @@ -52,14 +70,13 @@ Query.prototype.requiresPreparation = function() { //metadata used when parsing row results Query.prototype.handleRowDescription = function(msg) { this._result.addFields(msg.fields); + this._accumulateRows = this.callback || !this.listeners('row').length; }; Query.prototype.handleDataRow = function(msg) { var row = this._result.parseRow(msg.fields); this.emit('row', row, this._result); - - //if there is a callback collect rows - if(this.callback) { + if (this._accumulateRows) { this._result.addRow(row); } }; diff --git a/test/integration/client/query-as-promise-tests.js b/test/integration/client/query-as-promise-tests.js new file mode 100644 index 00000000..8dcdeb51 --- /dev/null +++ b/test/integration/client/query-as-promise-tests.js @@ -0,0 +1,33 @@ +var helper = require(__dirname + '/../test-helper'); +var pg = helper.pg; +var semver = require('semver') + +if (semver.lt(process.version, '0.12.0')) { + return console.log('promises are not supported in node < v0.10') +} + +process.on('unhandledRejection', function(e) { + console.error(e, e.stack) + process.exit(1) +}) + +pg.connect(helper.config, assert.success(function(client, done) { + client.query('SELECT $1::text as name', ['foo']) + .then(function(result) { + assert.equal(result.rows[0].name, 'foo') + return client + }) + .then(function(client) { + client.query('ALKJSDF') + .catch(function(e) { + assert(e instanceof Error) + }) + }) + + client.query('SELECT 1 as num') + .then(function(result) { + assert.equal(result.rows[0].num, 1) + done() + pg.end() + }) +})) diff --git a/test/integration/client/type-coercion-tests.js b/test/integration/client/type-coercion-tests.js index efc3a86d..70eff30b 100644 --- a/test/integration/client/type-coercion-tests.js +++ b/test/integration/client/type-coercion-tests.js @@ -202,14 +202,14 @@ helper.pg.connect(helper.config, assert.calls(function(err, client, done) { if(!helper.config.binary) { test("postgres date type", function() { var client = helper.client(); - var testDate = new Date (2010, 9, 31); + var testDate = new Date(2010, 9, 31); client.on('error', function(err) { console.log(err); client.end(); }); client.query("SELECT $1::date", [testDate], assert.calls(function(err, result){ assert.isNull(err); - assert.strictEqual(result.rows[0].date.toString(), testDate.toString()); + assert.strictEqual(result.rows[0].date.toString(), new Date(Date.UTC(2010, 9, 31)).toString()); })); client.on('drain', client.end.bind(client)); });