diff --git a/lib/client.js b/lib/client.js index da229421..659e5468 100644 --- a/lib/client.js +++ b/lib/client.js @@ -73,11 +73,14 @@ p.connect = function() { con.on('readyForQuery', function() { self.readyForQuery = true; + this.activeQuery = null; self.pulseQueryQueue(); }); con.on('error', function(error) { - self.emit('error', error); + if(!self.activeQuery) { + self.emit('error', error); + } }); }; @@ -87,6 +90,7 @@ p.pulseQueryQueue = function() { if(this.queryQueue.length > 0) { this.readyForQuery = false; var query = this.queryQueue.shift(); + this.activeQuery = query; query.submit(this.connection); } else { this.emit('drain'); diff --git a/lib/query.js b/lib/query.js index 20a2c075..d68f3229 100644 --- a/lib/query.js +++ b/lib/query.js @@ -49,14 +49,30 @@ p.submit = function(connection) { } self.emit('row', result); }; - connection.on('rowDescription', handleRowDescription); - connection.on('dataRow', handleDatarow); - connection.once('readyForQuery', function() { + + var onError = function(err) { //remove all listeners + connection.removeListener('rowDescription', handleDatarow); + connection.removeListener('dataRow', handleDatarow); + connection.removeListener('error', onError); + connection.removeListener('readyForQuery', onReadyForQuery); + self.emit('error', err); + self.emit('end'); + }; + + var onReadyForQuery = function() { + //remove all listeners connection.removeListener('rowDescription', handleRowDescription); connection.removeListener('dataRow', handleDatarow); + connection.removeListener('readyForQuery', onReadyForQuery); + connection.removeListener('error', onError); self.emit('end'); - }); + }; + + connection.on('rowDescription', handleRowDescription); + connection.on('dataRow', handleDatarow); + connection.on('readyForQuery', onReadyForQuery); + connection.on('error', onError); }; p.hasBeenParsed = function(connection) { @@ -104,10 +120,19 @@ p.prepare = function(connection) { //TODO support EmptyQueryResponse, ErrorResponse, and PortalSuspended var onCommandComplete = function() { + connection.removeListener('error', onError); + connection.removeListener('commandComplete', onCommandComplete); connection.sync(); }; - connection.once('commandComplete', onCommandComplete); + var onError = function() { + connection.removeListener('error', onError); + connection.removeListener('commandComplete', onCommandComplete); + connection.sync(); + }; + + connection.on('commandComplete', onCommandComplete); + connection.on('error', onError); }; var dateParser = function(isoDate) { diff --git a/test/integration/client/error-handling-tests.js b/test/integration/client/error-handling-tests.js index b9e93b8b..c9211c23 100644 --- a/test/integration/client/error-handling-tests.js +++ b/test/integration/client/error-handling-tests.js @@ -1,10 +1,82 @@ var helper = require(__dirname + '/test-helper'); -test('error handling', function(){ +var createErorrClient = function() { var client = helper.client(); - client.query("select omfg from yodas_soda where pixistix = 'zoiks!!!'"); - assert.emits(client, 'error', function(error) { - assert.equal(error.severity, "ERROR"); - client.end(); + client.on('error', function(err) { + assert.ok(false, "client should not throw query error: " + sys.inspect(err)); + }) + client.on('drain', client.end.bind(client)); + return client; +}; + +test('error handling', function(){ + + test('within a simple query', function() { + + var client = createErorrClient(); + + var query = client.query("select omfg from yodas_soda where pixistix = 'zoiks!!!'"); + + assert.emits(query, 'error', function(error) { + assert.equal(error.severity, "ERROR"); + }); + }); + + test('within a prepared statement', function() { + + var client = createErorrClient(); + + var q = client.query("CREATE TEMP TABLE boom(age integer); INSERT INTO boom (age) VALUES (28);"); + + test("when query is parsing", function() { + //this query wont parse since there ain't no table named bang + + var ensureFuture = function(testClient) { + test("client can issue more queries successfully", function() { + var goodQuery = testClient.query("select age from boom"); + assert.emits(goodQuery, 'row', function(row) { + assert.equal(row.age, 28); + }); + }); + }; + + var query = client.query({ + text: "select * from bang where name = $1", + values: ['0'] + }); + + test("query emits the error", function() { + assert.emits(query, 'error', function(err) { + ensureFuture(client); + }); + }) + + test("when a query is binding", function() { + var query = client.query({ + text: 'select * from boom where age = $1', + values: ['asldkfjasdf'] + }); + + test("query emits the error", function() { + assert.emits(query, 'error', function(err) { + assert.equal(err.severity, "ERROR"); + ensureFuture(client); + }); + }); + + //TODO how to test for errors during execution? + }); + }) + }); + + test('non-query error', function() { + + var client = new Client({ + user:'asldkfjsadlfkj' + }); + assert.emits(client, 'error'); + client.connect(); + }); + });