Skip to content

Commit 176e6c7

Browse files
committed
include command metadata with native query result callback - closes brianc#128
1 parent 7f00b3e commit 176e6c7

File tree

4 files changed

+63
-43
lines changed

4 files changed

+63
-43
lines changed

lib/native/index.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,14 @@ var clientBuilder = function(config) {
132132
connection._activeQuery.handleRow(row);
133133
});
134134

135+
connection.on('_cmdStatus', function(status) {
136+
var meta = {
137+
};
138+
meta.command = status.command.split(' ')[0];
139+
meta.rowCount = parseInt(status.value);
140+
connection._lastMeta = meta;
141+
});
142+
135143
//TODO: emit more native error properties (make it match js error)
136144
connection.on('_error', function(err) {
137145
//create Error object from object literal
@@ -156,7 +164,7 @@ var clientBuilder = function(config) {
156164
this._namedQuery = false;
157165
this._sendQueryPrepared(q.name, q.values||[]);
158166
} else {
159-
connection._activeQuery.handleReadyForQuery();
167+
connection._activeQuery.handleReadyForQuery(connection._lastMeta);
160168
connection._activeQuery = null;
161169
connection._pulseQueryQueue();
162170
}

lib/native/query.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,10 @@ p.handleError = function(error) {
8282
}
8383
}
8484

85-
p.handleReadyForQuery = function() {
85+
p.handleReadyForQuery = function(meta) {
8686
if(this.callback) {
87-
this.callback(null, { rows: this.rows });
87+
(meta || {}).rows = this.rows;
88+
this.callback(null, meta);
8889
}
8990
this.emit('end');
9091
};

src/binding.cc

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ static Persistent<String> type_symbol;
3030
static Persistent<String> channel_symbol;
3131
static Persistent<String> payload_symbol;
3232
static Persistent<String> emit_symbol;
33+
static Persistent<String> command_symbol;
3334

3435
class Connection : public ObjectWrap {
3536

@@ -62,6 +63,7 @@ class Connection : public ObjectWrap {
6263
type_symbol = NODE_PSYMBOL("type");
6364
channel_symbol = NODE_PSYMBOL("channel");
6465
payload_symbol = NODE_PSYMBOL("payload");
66+
command_symbol = NODE_PSYMBOL("command");
6567

6668

6769
NODE_SET_PROTOTYPE_METHOD(t, "connect", Connect);
@@ -437,32 +439,46 @@ class Connection : public ObjectWrap {
437439
}
438440
}
439441

440-
void HandleResult(const PGresult* result)
442+
void HandleResult(PGresult* result)
441443
{
442444
ExecStatusType status = PQresultStatus(result);
443445
switch(status) {
444446
case PGRES_TUPLES_OK:
445-
HandleTuplesResult(result);
447+
{
448+
HandleTuplesResult(result);
449+
EmitCommandMetaData(result);
450+
}
446451
break;
447452
case PGRES_FATAL_ERROR:
448453
HandleErrorResult(result);
449454
break;
450455
case PGRES_COMMAND_OK:
451-
case PGRES_EMPTY_QUERY:
452-
//do nothing
456+
case PGRES_EMPTY_QUERY:
457+
EmitCommandMetaData(result);
453458
break;
454459
default:
455460
printf("Unrecogized query status: %s\n", PQresStatus(status));
456461
break;
457462
}
458463
}
459464

465+
void EmitCommandMetaData(PGresult* result)
466+
{
467+
HandleScope scope;
468+
Local<Object> info = Object::New();
469+
info->Set(command_symbol, String::New(PQcmdStatus(result)));
470+
info->Set(value_symbol, String::New(PQcmdTuples(result)));
471+
Handle<Value> e = (Handle<Value>)info;
472+
Emit("_cmdStatus", &e);
473+
}
474+
460475
//maps the postgres tuple results to v8 objects
461476
//and emits row events
462477
//TODO look at emitting fewer events because the back & forth between
463478
//javascript & c++ might introduce overhead (requires benchmarking)
464479
void HandleTuplesResult(const PGresult* result)
465480
{
481+
HandleScope scope;
466482
int rowCount = PQntuples(result);
467483
for(int rowNumber = 0; rowNumber < rowCount; rowNumber++) {
468484
//create result object for this row
@@ -489,7 +505,6 @@ class Connection : public ObjectWrap {
489505
row->Set(Integer::New(fieldNumber), field);
490506
}
491507

492-
//not sure about what to dealloc or scope#Close here
493508
Handle<Value> e = (Handle<Value>)row;
494509
Emit("_row", &e);
495510
}
@@ -564,30 +579,30 @@ class Connection : public ObjectWrap {
564579
{
565580
PostgresPollingStatusType status = PQconnectPoll(connection_);
566581
switch(status) {
567-
case PGRES_POLLING_READING:
568-
TRACE("Polled: PGRES_POLLING_READING");
569-
StopWrite();
570-
StartRead();
571-
break;
572-
case PGRES_POLLING_WRITING:
573-
TRACE("Polled: PGRES_POLLING_WRITING");
574-
StopRead();
575-
StartWrite();
576-
break;
577-
case PGRES_POLLING_FAILED:
578-
StopRead();
579-
StopWrite();
580-
TRACE("Polled: PGRES_POLLING_FAILED");
581-
EmitLastError();
582-
break;
583-
case PGRES_POLLING_OK:
584-
TRACE("Polled: PGRES_POLLING_OK");
585-
connecting_ = false;
586-
StartRead();
587-
Emit("connect");
588-
default:
589-
//printf("Unknown polling status: %d\n", status);
590-
break;
582+
case PGRES_POLLING_READING:
583+
TRACE("Polled: PGRES_POLLING_READING");
584+
StopWrite();
585+
StartRead();
586+
break;
587+
case PGRES_POLLING_WRITING:
588+
TRACE("Polled: PGRES_POLLING_WRITING");
589+
StopRead();
590+
StartWrite();
591+
break;
592+
case PGRES_POLLING_FAILED:
593+
StopRead();
594+
StopWrite();
595+
TRACE("Polled: PGRES_POLLING_FAILED");
596+
EmitLastError();
597+
break;
598+
case PGRES_POLLING_OK:
599+
TRACE("Polled: PGRES_POLLING_OK");
600+
connecting_ = false;
601+
StartRead();
602+
Emit("connect");
603+
default:
604+
//printf("Unknown polling status: %d\n", status);
605+
break;
591606
}
592607
}
593608

test/integration/client/result-metadata-tests.js

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,21 @@ var helper = require(__dirname + "/test-helper");
22
var pg = helper.pg;
33

44
test('should return insert metadata', function() {
5-
return false;
65
pg.connect(helper.config, assert.calls(function(err, client) {
76
assert.isNull(err);
87
client.query("CREATE TEMP TABLE zugzug(name varchar(10))", assert.calls(function(err, result) {
98
assert.isNull(err);
10-
//let's list this as ignored for now
11-
// process.nextTick(function() {
12-
// test('should identify "CREATE TABLE" message', function() {
13-
// return false;
14-
// assert.equal(result.command, "CREATE TABLE");
15-
// assert.equal(result.rowCount, 0);
16-
// })
17-
// })
189
assert.equal(result.oid, null);
10+
assert.equal(result.command, 'CREATE');
1911
client.query("INSERT INTO zugzug(name) VALUES('more work?')", assert.calls(function(err, result) {
2012
assert.equal(result.command, "INSERT");
2113
assert.equal(result.rowCount, 1);
22-
process.nextTick(client.end.bind(client));
23-
return false;
14+
client.query('SELECT * FROM zugzug', assert.calls(function(err, result) {
15+
assert.isNull(err);
16+
assert.equal(result.rowCount, 1);
17+
assert.equal(result.command, 'SELECT');
18+
process.nextTick(pg.end.bind(pg));
19+
}))
2420
}))
2521
}))
2622
}))

0 commit comments

Comments
 (0)