Skip to content

Commit d2bb532

Browse files
committed
Make moar tests pass
1 parent 667c528 commit d2bb532

13 files changed

+136
-73
lines changed

lib/client.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,13 +176,13 @@ Client.prototype.connect = function(callback) {
176176
con.once('end', function() {
177177
if ( callback ) {
178178
// haven't received a connection message yet !
179-
var err = new Error('Connection was ended during query');
179+
var err = new Error('Connection terminated');
180180
callback(err);
181181
callback = null;
182182
return;
183183
}
184184
if(self.activeQuery) {
185-
var disconnectError = new Error('Connection was ended during query');
185+
var disconnectError = new Error('Connection terminated');
186186
self.activeQuery.handleError(disconnectError, con);
187187
self.activeQuery = null;
188188
}

lib/native/index.js

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,21 @@ var NativeQuery = require('./query');
77

88
var Client = module.exports = function(config) {
99
EventEmitter.call(this);
10-
if(typeof config === 'string') {
11-
this.connectionString = config;
12-
}
1310
this.native = new Native();
1411
this._queryQueue = [];
1512
this._connected = false;
1613

1714
//keep these on the object for legacy reasons
1815
//for the time being. TODO: deprecate all this jazz
19-
var cp = new ConnectionParameters(config);
16+
var cp = this.connectionParameters = new ConnectionParameters(config);
2017
this.user = cp.user;
2118
this.password = cp.password;
2219
this.database = cp.database;
2320
this.host = cp.host;
2421
this.port = cp.port;
22+
23+
//a hash to hold named queries
24+
this.namedQueries = {};
2525
};
2626

2727
util.inherits(Client, EventEmitter);
@@ -33,20 +33,41 @@ util.inherits(Client, EventEmitter);
3333
//the client will emit an error event.
3434
Client.prototype.connect = function(cb) {
3535
var self = this;
36-
this.native.connect(this.connectionString, function(err) {
37-
//error handling
38-
if(err) {
39-
if(cb) return cb(err);
40-
return self.emit('error', err);
41-
}
4236

43-
//set internal states to connected
44-
self._connected = true;
45-
self.emit('connect');
46-
self._pulseQueryQueue(true);
37+
var onError = function(err) {
38+
if(cb) return cb(err);
39+
return self.emit('error', err);
40+
};
4741

48-
//possibly call the optional callback
49-
if(cb) cb();
42+
this.connectionParameters.getLibpqConnectionString(function(err, conString) {
43+
if(err) return onError(err);
44+
self.native.connect(conString, function(err) {
45+
if(err) return onError(err);
46+
47+
//set internal states to connected
48+
self._connected = true;
49+
self.emit('connect');
50+
self._pulseQueryQueue(true);
51+
52+
//handle connection errors from the native layer
53+
self.native.on('error', function(err) {
54+
//error will be handled by active query
55+
if(self._activeQuery && self._activeQuery.state != 'end') {
56+
return;
57+
}
58+
self.emit('error', err);
59+
});
60+
61+
self.native.on('notification', function(msg) {
62+
self.emit('notification', {
63+
channel: msg.relname,
64+
payload: msg.extra
65+
});
66+
});
67+
68+
//possibly call the optional callback
69+
if(cb) cb();
70+
});
5071
});
5172
};
5273

@@ -86,19 +107,27 @@ Client.prototype.query = function(config, values, callback) {
86107
Client.prototype.end = function(cb) {
87108
var self = this;
88109
this.native.end(function() {
110+
//send an error to the active query
111+
if(self._hasActiveQuery()) {
112+
var msg = 'Connection terminated';
113+
self._queryQueue.length = 0;
114+
self._activeQuery.handleError(new Error(msg));
115+
}
89116
self.emit('end');
90117
if(cb) cb();
91118
});
92119
};
93120

121+
Client.prototype._hasActiveQuery = function() {
122+
return this._activeQuery && this._activeQuery.state != 'error' && this._activeQuery.state != 'end';
123+
};
124+
94125
Client.prototype._pulseQueryQueue = function(initialConnection) {
95126
if(!this._connected) {
96127
return;
97128
}
98-
if(this._activeQuery) {
99-
if(this._activeQuery.state != 'error' && this._activeQuery.state != 'end') {
100-
return;
101-
}
129+
if(this._hasActiveQuery()) {
130+
return;
102131
}
103132
var query = this._queryQueue.shift();
104133
if(!query) {
@@ -108,7 +137,7 @@ Client.prototype._pulseQueryQueue = function(initialConnection) {
108137
return;
109138
}
110139
this._activeQuery = query;
111-
query.submit();
140+
query.submit(this);
112141
var self = this;
113142
query.once('_done', function() {
114143
self._pulseQueryQueue();

lib/native/query.js

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,24 @@ NativeResult.prototype.addCommandComplete = function(pq) {
5555
}
5656
};
5757

58-
NativeQuery.prototype.submit = function() {
58+
NativeQuery.prototype.handleError = function(err) {
59+
var self = this;
60+
//copy pq error fields into the error object
61+
var fields = self.native.pq.resultErrorFields();
62+
if(fields) {
63+
for(var key in fields) {
64+
err[key] = fields[key];
65+
}
66+
}
67+
if(self.callback) {
68+
self.callback(err);
69+
} else {
70+
self.emit('error', err);
71+
}
72+
self.state = 'error';
73+
}
74+
75+
NativeQuery.prototype.submit = function(client) {
5976
this.state = 'running';
6077
var self = this;
6178

@@ -66,9 +83,7 @@ NativeQuery.prototype.submit = function() {
6683

6784
//handle possible query error
6885
if(err) {
69-
self.state = 'error';
70-
if(self.callback) return self.callback(err);
71-
return self.emit('error', err);
86+
return self.handleError(err);
7287
}
7388

7489
var result = new NativeResult();
@@ -91,7 +106,27 @@ NativeQuery.prototype.submit = function() {
91106
}
92107
}
93108

94-
if(this.values) {
109+
if(process.domain) {
110+
after = process.domain.bind(after);
111+
}
112+
113+
//named query
114+
if(this.name) {
115+
var values = (this.values||[]).map(utils.prepareValue);
116+
117+
//check if the client has already executed this named query
118+
//if so...just execute it again - skip the planning phase
119+
if(client.namedQueries[this.name]) {
120+
return this.native.execute(this.name, values, after);
121+
}
122+
//plan the named query the first time, then execute it
123+
return this.native.prepare(this.name, this.text, values.length, function(err) {
124+
if(err) return self.handleError(err);
125+
client.namedQueries[self.name] = true;
126+
return self.native.execute(self.name, values, after);
127+
})
128+
}
129+
else if(this.values) {
95130
var values = this.values.map(utils.prepareValue);
96131
this.native.query(this.text, values, after);
97132
} else {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"nan": "~1.3.0",
2424
"packet-reader": "0.2.0",
2525
"pg-connection-string": "0.1.1",
26-
"pg-native": "0.5.0",
26+
"pg-native": "0.5.2",
2727
"pg-types": "1.4.0",
2828
"pgpass": "0.0.3"
2929
},

test/integration/client/error-handling-tests.js

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
return console.log('error-handling-tests.js: GET TO PASS');
21
var helper = require(__dirname + '/test-helper');
32
var util = require('util');
43

54
var createErorrClient = function() {
65
var client = helper.client();
7-
client.on('error', function(err) {
8-
assert.ok(false, "client should not throw query error: " + util.inspect(err));
6+
client.once('error', function(err) {
7+
//console.log('error', util.inspect(err));
8+
assert.fail('Client shoud not throw error during query execution');
99
});
1010
client.on('drain', client.end.bind(client));
1111
return client;
@@ -19,11 +19,8 @@ test('error handling', function(){
1919
var query = client.query("select omfg from yodas_dsflsd where pixistix = 'zoiks!!!'");
2020

2121
assert.emits(query, 'error', function(error) {
22-
test('error is a psql error', function() {
23-
assert.equal(error.severity, "ERROR");
24-
});
22+
assert.equal(error.severity, "ERROR");
2523
});
26-
2724
});
2825

2926
test('within a prepared statement', function() {
@@ -109,7 +106,7 @@ test('non-error calls supplied callback', function() {
109106
});
110107

111108
client.connect(assert.calls(function(err) {
112-
assert.isNull(err);
109+
assert.ifError(err);
113110
client.end();
114111
}))
115112
});
@@ -124,9 +121,11 @@ test('when connecting to invalid host', function() {
124121
password: '1234',
125122
host: 'asldkfjasdf!!#1308140.com'
126123
});
124+
127125
var delay = 5000;
128126
var tid = setTimeout(function() {
129-
assert(false, "When connecting to an invalid host the error event should be emitted but it has been " + delay + " and still no error event.");
127+
var msg = "When connecting to an invalid host the error event should be emitted but it has been " + delay + " and still no error event."
128+
assert(false, msg);
130129
}, delay);
131130
client.on('error', function() {
132131
clearTimeout(tid);
@@ -141,7 +140,7 @@ test('when connecting to invalid host with callback', function() {
141140
host: 'asldkfjasdf!!#1308140.com'
142141
});
143142
client.connect(function(error, client) {
144-
assert.ok(error);
143+
assert(error);
145144
});
146145
});
147146

test/integration/client/notice-tests.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
return console.log('notice-tests.js - GET TO PASS')
21
var helper = require(__dirname + '/test-helper');
2+
33
test('emits notice message', function() {
44
//TODO this doesn't work on all versions of postgres
55
return false;

test/integration/client/prepared-statement-tests.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
return console.log('prepared-statement-tests: GET TO PASS');
21
var helper = require(__dirname +'/test-helper');
32

43
test("simple, unnamed prepared statement", function(){

test/integration/client/query-callback-error-tests.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
return console.log('query-callback-error-tests: GET TO PASS');
1+
return console.log('query-callback-error-tests: DEPRECATED - if you want saftey in your callback, you can try/catch your own functions');
22
var helper = require(__dirname + '/test-helper');
33
var util = require('util');
44

test/integration/client/query-error-handling-prepared-statement-tests.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
return console.log('query-error-handling-prepared-statement-tests: GET TO PASS');
21
var helper = require(__dirname + '/test-helper');
32
var util = require('util');
43

@@ -64,7 +63,7 @@ test('client end during query execution of prepared statement', function() {
6463
text: sleepQuery,
6564
values: [5] },
6665
assert.calls(function(err, result) {
67-
assert.equal(err.message, 'Connection was ended during query');
66+
assert.equal(err.message, 'Connection terminated');
6867
}));
6968

7069
query1.on('error', function(err) {
@@ -82,3 +81,4 @@ test('client end during query execution of prepared statement', function() {
8281
client.end();
8382
}));
8483
});
84+
return console.log('query-error-handling-prepared-statement-tests: GET TO PASS');

test/integration/client/simple-query-tests.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ test("simple query interface", function() {
3737
});
3838

3939
test("multiple simple queries", function() {
40-
return console.log('MUST SUPPORT MULTIPLE SIMPLE QURIES')
4140
var client = helper.client();
4241
client.query({ text: "create temp table bang(id serial, name varchar(5));insert into bang(name) VALUES('boom');"})
4342
client.query("insert into bang(name) VALUES ('yes');");

test/integration/client/type-coercion-tests.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,11 @@ if(!helper.config.binary) {
158158
client.end();
159159
});
160160

161-
// Set teh server timeszone to the same as used for the test,
161+
// Set the server timeszone to the same as used for the test,
162162
// otherwise (if server's timezone is ahead of GMT) in
163163
// textParsers.js::parseDate() the timezone offest is added to the date;
164164
// in the case of "275760-09-13 00:00:00 GMT" the timevalue overflows.
165-
client.query('SET TIMEZONE TO GMT', [], assert.success(function(res){
165+
client.query('SET TIMEZONE TO GMT', assert.success(function(res){
166166

167167
// PostgreSQL supports date range of 4713 BCE to 294276 CE
168168
// http://www.postgresql.org/docs/9.2/static/datatype-datetime.html
@@ -186,7 +186,7 @@ if(!helper.config.binary) {
186186
}
187187

188188
helper.pg.connect(helper.config, assert.calls(function(err, client, done) {
189-
assert.isNull(err);
189+
assert.ifError(err);
190190
client.query('select null as res;', assert.calls(function(err, res) {
191191
assert.isNull(err);
192192
assert.strictEqual(res.rows[0].res, null)

0 commit comments

Comments
 (0)