Skip to content

Commit

Permalink
prepared statements moved forward a good deal
Browse files Browse the repository at this point in the history
  • Loading branch information
brianc committed Oct 29, 2010
1 parent 9d2c1e3 commit da8026d
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 42 deletions.
29 changes: 20 additions & 9 deletions lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ p.pulseQueryQueue = function() {

p.query = function(config) {
//can take in strings or config objects
var query = new Query(config.text ? config : { text: config });
var query = new Query((config.text || config.name) ? config : { text: config });
this.queryQueue.push(query);
this.pulseQueryQueue();
return query;
Expand All @@ -102,6 +102,7 @@ var Query = function(config) {
this.rowDescription = null;
EventEmitter.call(this);
};

sys.inherits(Query, EventEmitter);
var p = Query.prototype;

Expand Down Expand Up @@ -132,16 +133,13 @@ p.submit = function(connection) {
});
};

p.hasBeenParsed = function(connection) {
return this.name && connection.parsedStatements[this.name];
};

p.prepare = function(connection) {
var self = this;

connection.parse({
text: self.text,
name: self.name,
types: self.types
});
connection.flush();

var onParseComplete = function() {
connection.bind({
portal: self.name,
Expand All @@ -151,7 +149,20 @@ p.prepare = function(connection) {
connection.flush();
};

connection.once('parseComplete', onParseComplete);

if(this.hasBeenParsed(connection)) {
onParseComplete();
} else {
connection.parsedStatements[this.name] = true;
connection.parse({
text: self.text,
name: self.name,
types: self.types
});
connection.flush();
connection.once('parseComplete', onParseComplete);
}


var onBindComplete = function() {
connection.describe({
Expand Down
1 change: 1 addition & 0 deletions lib/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var Connection = function(config) {
this.buffer = null;
this.offset = null;
this.encoding = 'utf8';
this.parsedStatements = {};
};

sys.inherits(Connection, EventEmitter);
Expand Down
137 changes: 136 additions & 1 deletion test/integration/client/prepared-statement-tests.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var helper = require(__dirname +'/test-helper');

test("simple prepared statement", function(){
test("simple, unnamed prepared statement", function(){
var client = helper.client();

var query = client.query({
Expand All @@ -16,3 +16,138 @@ test("simple prepared statement", function(){
client.end();
});
});

test("named prepared statement", function() {

var client = helper.client();
var queryName = "user by age and like name";
var query = client.query({
text: 'select name from person where age <= $1 and name LIKE $2',
values: [20, 'Bri%'],
name: queryName
});

var parseCount = 0;
client.connection.on('parseComplete', function() {
parseCount++;
});

assert.raises(query, 'row', function(row) {
assert.equal(row.fields[0], 'Brian');
});

assert.raises(query, 'end', function() {
test("query was parsed", function() {
assert.equal(parseCount, 1);
});

test("with same name & text", function() {
var cachedQuery = client.query({
text: 'select name from person where age <= $1 and name LIKE $2',
name: queryName,
values: [10, 'A%']
});

assert.raises(cachedQuery, 'row', function(row) {
assert.equal(row.fields[0], 'Aaron');
});

assert.raises(cachedQuery, 'end', function() {
test("query was only parsed one time", function() {
assert.equal(parseCount, 1, "Should not have reparsed query");
});
});
});

test("with same name, but the query text not even there batman!", function() {
var q = client.query({
name: queryName,
values: [30, '%n%']
});

test("gets first row", function() {

assert.raises(q, 'row', function(row) {
assert.equal(row.fields[0], "Aaron");

test("gets second row", function() {

assert.raises(q, 'row', function(row) {
assert.equal(row.fields[0], "Brian");
});
});

});
});

test("only parsed query once total", function() {
assert.equal(parseCount, 1);
q.on('end', function() {
client.end();
});
});

});
});

});

test("prepared statements on different clients", function() {
var statementName = "differ";
var statement1 = "select count(*) from person";
var statement2 = "select count(*) from person where age < $1";

var client1Finished = false;
var client2Finished = false;

var client1 = helper.client();

var client2 = helper.client();

test("client 1 execution", function() {

var query = client1.query({
name: statementName,
text: statement1
});
test('gets right data back', function() {
assert.raises(query, 'row', function(row) {
assert.equal(row.fields[0], 26);
});
});

assert.raises(query, 'end', function() {
if(client2Finished) {
client1.end();
client2.end();
} else {
client1Finished = true;
}
});

});

test('client 2 execution', function() {
var query = client2.query({
name: statementName,
text: statement2,
values: [11]
});

test('gets right data', function() {
assert.raises(query, 'row', function(row) {
assert.equal(row.fields[0], 1);
});
});

assert.raises(query, 'end', function() {
if(client1Finished) {
client1.end();
client2.end();
} else {
client2Finished = true;
}
});
});

});
80 changes: 48 additions & 32 deletions test/unit/client/prepared-statement-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,68 +3,84 @@ var helper = require(__dirname + '/test-helper');
var client = helper.client();
var con = client.connection;
var parseArg = null;
con.parse = function(query) {
parseArg = query;
con.parse = function(arg) {
parseArg = arg;
process.nextTick(function() {
con.emit('parseComplete');
});
};

var bindArg = null;
con.bind = function(arg) {
bindArg = arg;
this.emit('bindComplete');
process.nextTick(function(){
con.emit('bindComplete');
});
};

var executeArg = null;
con.execute = function(arg) {
executeArg = arg;
this.emit('rowData',{ fields: [] });
this.emit('commandComplete');
process.nextTick(function() {
con.emit('rowData',{ fields: [] });
con.emit('commandComplete');
});
};

var describeArg = null;
con.describe = function(arg) {
describeArg = arg;
this.emit('rowDescription', { fields: [] });
process.nextTick(function() {
con.emit('rowDescription', { fields: [] });
});
};

var syncCalled = true;
var syncCalled = false;
con.flush = function() {
};
con.sync = function() {
syncCalled = false;
this.emit('readyForQuery')
syncCalled = true;
process.nextTick(function() {
con.emit('readyForQuery');
});
};

test('bound command', function() {
test('simple, unnamed bound command', function() {
return false;
assert.ok(client.connection.emit('readyForQuery'));

var query = client.query({
text: 'select * where name = $1',
parameters: ['hi']
values: ['hi']
});

test('parse argument', function() {
assert.equal(parseArg.name, null);
assert.equal(parseArg.text, 'select * where name = $1');
assert.equal(parseArg.types, null);
});
assert.raises(query,'end', function() {
test('parse argument', function() {
assert.equal(parseArg.name, null);
assert.equal(parseArg.text, 'select * where name = $1');
assert.equal(parseArg.types, null);
});

test('bind argument', function() {
assert.equal(bindArg.statement, null);
assert.equal(bindArg.portal, null);
assert.length(bindArg.values, 1);
assert.equal(bindArg.values[0], 'hi')
});
test('bind argument', function() {
assert.equal(bindArg.statement, null);
assert.equal(bindArg.portal, null);
assert.length(bindArg.values, 1);
assert.equal(bindArg.values[0], 'hi')
});

test('describe argument', function() {
assert.equal(describeArg, null);
});
test('describe argument', function() {
assert.equal(describeArg.type, 'P');
assert.equal(describeArg.name, "");
});

test('execute argument', function() {
assert.equal(executeArg.portal, null);
assert.equal(executeArg.rows, null);
});
test('execute argument', function() {
assert.equal(executeArg.portal, null);
assert.equal(executeArg.rows, null);
});

test('sync called', function() {
assert.ok(syncCalled);
test('sync called', function() {
assert.ok(syncCalled);
});
});

});
});

0 comments on commit da8026d

Please sign in to comment.