From 176e6c7ab23d333510dfaf139c01ee413ac47ddf Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 30 May 2012 23:38:03 -0500 Subject: [PATCH] include command metadata with native query result callback - closes #128 --- lib/native/index.js | 10 ++- lib/native/query.js | 5 +- src/binding.cc | 73 +++++++++++-------- .../client/result-metadata-tests.js | 18 ++--- 4 files changed, 63 insertions(+), 43 deletions(-) diff --git a/lib/native/index.js b/lib/native/index.js index ae73f84..423bbd3 100644 --- a/lib/native/index.js +++ b/lib/native/index.js @@ -132,6 +132,14 @@ var clientBuilder = function(config) { connection._activeQuery.handleRow(row); }); + connection.on('_cmdStatus', function(status) { + var meta = { + }; + meta.command = status.command.split(' ')[0]; + meta.rowCount = parseInt(status.value); + connection._lastMeta = meta; + }); + //TODO: emit more native error properties (make it match js error) connection.on('_error', function(err) { //create Error object from object literal @@ -156,7 +164,7 @@ var clientBuilder = function(config) { this._namedQuery = false; this._sendQueryPrepared(q.name, q.values||[]); } else { - connection._activeQuery.handleReadyForQuery(); + connection._activeQuery.handleReadyForQuery(connection._lastMeta); connection._activeQuery = null; connection._pulseQueryQueue(); } diff --git a/lib/native/query.js b/lib/native/query.js index 6187c20..4473100 100644 --- a/lib/native/query.js +++ b/lib/native/query.js @@ -82,9 +82,10 @@ p.handleError = function(error) { } } -p.handleReadyForQuery = function() { +p.handleReadyForQuery = function(meta) { if(this.callback) { - this.callback(null, { rows: this.rows }); + (meta || {}).rows = this.rows; + this.callback(null, meta); } this.emit('end'); }; diff --git a/src/binding.cc b/src/binding.cc index 3c5ccb9..1f498c0 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -30,6 +30,7 @@ static Persistent type_symbol; static Persistent channel_symbol; static Persistent payload_symbol; static Persistent emit_symbol; +static Persistent command_symbol; class Connection : public ObjectWrap { @@ -62,6 +63,7 @@ public: type_symbol = NODE_PSYMBOL("type"); channel_symbol = NODE_PSYMBOL("channel"); payload_symbol = NODE_PSYMBOL("payload"); + command_symbol = NODE_PSYMBOL("command"); NODE_SET_PROTOTYPE_METHOD(t, "connect", Connect); @@ -437,19 +439,22 @@ protected: } } - void HandleResult(const PGresult* result) + void HandleResult(PGresult* result) { ExecStatusType status = PQresultStatus(result); switch(status) { case PGRES_TUPLES_OK: - HandleTuplesResult(result); + { + HandleTuplesResult(result); + EmitCommandMetaData(result); + } break; case PGRES_FATAL_ERROR: HandleErrorResult(result); break; case PGRES_COMMAND_OK: - case PGRES_EMPTY_QUERY: - //do nothing + case PGRES_EMPTY_QUERY: + EmitCommandMetaData(result); break; default: printf("Unrecogized query status: %s\n", PQresStatus(status)); @@ -457,12 +462,23 @@ protected: } } + void EmitCommandMetaData(PGresult* result) + { + HandleScope scope; + Local info = Object::New(); + info->Set(command_symbol, String::New(PQcmdStatus(result))); + info->Set(value_symbol, String::New(PQcmdTuples(result))); + Handle e = (Handle)info; + Emit("_cmdStatus", &e); + } + //maps the postgres tuple results to v8 objects //and emits row events //TODO look at emitting fewer events because the back & forth between //javascript & c++ might introduce overhead (requires benchmarking) void HandleTuplesResult(const PGresult* result) { + HandleScope scope; int rowCount = PQntuples(result); for(int rowNumber = 0; rowNumber < rowCount; rowNumber++) { //create result object for this row @@ -489,7 +505,6 @@ protected: row->Set(Integer::New(fieldNumber), field); } - //not sure about what to dealloc or scope#Close here Handle e = (Handle)row; Emit("_row", &e); } @@ -564,30 +579,30 @@ private: { PostgresPollingStatusType status = PQconnectPoll(connection_); switch(status) { - case PGRES_POLLING_READING: - TRACE("Polled: PGRES_POLLING_READING"); - StopWrite(); - StartRead(); - break; - case PGRES_POLLING_WRITING: - TRACE("Polled: PGRES_POLLING_WRITING"); - StopRead(); - StartWrite(); - break; - case PGRES_POLLING_FAILED: - StopRead(); - StopWrite(); - TRACE("Polled: PGRES_POLLING_FAILED"); - EmitLastError(); - break; - case PGRES_POLLING_OK: - TRACE("Polled: PGRES_POLLING_OK"); - connecting_ = false; - StartRead(); - Emit("connect"); - default: - //printf("Unknown polling status: %d\n", status); - break; + case PGRES_POLLING_READING: + TRACE("Polled: PGRES_POLLING_READING"); + StopWrite(); + StartRead(); + break; + case PGRES_POLLING_WRITING: + TRACE("Polled: PGRES_POLLING_WRITING"); + StopRead(); + StartWrite(); + break; + case PGRES_POLLING_FAILED: + StopRead(); + StopWrite(); + TRACE("Polled: PGRES_POLLING_FAILED"); + EmitLastError(); + break; + case PGRES_POLLING_OK: + TRACE("Polled: PGRES_POLLING_OK"); + connecting_ = false; + StartRead(); + Emit("connect"); + default: + //printf("Unknown polling status: %d\n", status); + break; } } diff --git a/test/integration/client/result-metadata-tests.js b/test/integration/client/result-metadata-tests.js index 1c4f94d..74457ba 100644 --- a/test/integration/client/result-metadata-tests.js +++ b/test/integration/client/result-metadata-tests.js @@ -2,25 +2,21 @@ var helper = require(__dirname + "/test-helper"); var pg = helper.pg; test('should return insert metadata', function() { - return false; pg.connect(helper.config, assert.calls(function(err, client) { assert.isNull(err); client.query("CREATE TEMP TABLE zugzug(name varchar(10))", assert.calls(function(err, result) { assert.isNull(err); - //let's list this as ignored for now - // process.nextTick(function() { - // test('should identify "CREATE TABLE" message', function() { - // return false; - // assert.equal(result.command, "CREATE TABLE"); - // assert.equal(result.rowCount, 0); - // }) - // }) assert.equal(result.oid, null); + assert.equal(result.command, 'CREATE'); client.query("INSERT INTO zugzug(name) VALUES('more work?')", assert.calls(function(err, result) { assert.equal(result.command, "INSERT"); assert.equal(result.rowCount, 1); - process.nextTick(client.end.bind(client)); - return false; + client.query('SELECT * FROM zugzug', assert.calls(function(err, result) { + assert.isNull(err); + assert.equal(result.rowCount, 1); + assert.equal(result.command, 'SELECT'); + process.nextTick(pg.end.bind(pg)); + })) })) })) }))