mirror of
https://github.com/brianc/node-postgres.git
synced 2025-12-08 20:16:25 +00:00
.
This commit is contained in:
commit
7fcfbd8bb0
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1,3 @@
|
||||
/.emacs-project
|
||||
*.swp
|
||||
*.log
|
||||
|
||||
29
Makefile
Normal file
29
Makefile
Normal file
@ -0,0 +1,29 @@
|
||||
SHELL := /bin/bash
|
||||
|
||||
user=postgres
|
||||
password=1234
|
||||
host=localhost
|
||||
port=5432
|
||||
database=postgres
|
||||
verbose=false
|
||||
|
||||
params := -u $(user) --password $(password) -p $(port) -d $(database) -h $(host) --verbose $(verbose)
|
||||
|
||||
node-command := xargs -n 1 -I file node file $(params)
|
||||
|
||||
.PHONY : test test-connection test-integration bench
|
||||
test: test-unit
|
||||
|
||||
test-all: test-unit test-integration
|
||||
|
||||
bench:
|
||||
@find benchmark -name "*-bench.js" | $(node-command)
|
||||
|
||||
test-unit:
|
||||
@find test/unit -name "*-tests.js" | $(node-command)
|
||||
|
||||
test-connection:
|
||||
@node script/test-connection.js $(params)
|
||||
|
||||
test-integration: test-connection
|
||||
@find test/integration -name "*-tests.js" | $(node-command)
|
||||
43
README.md
43
README.md
@ -3,17 +3,15 @@
|
||||
Non-blocking (async) pure JavaScript PostgreSQL client for node.js written
|
||||
with love and TDD.
|
||||
|
||||
## alpha version
|
||||
|
||||
### Installation
|
||||
## Installation
|
||||
|
||||
npm install pg
|
||||
|
||||
### Example
|
||||
## Example
|
||||
|
||||
var pg = require('pg');
|
||||
|
||||
pg.connect("pg://user:password@host:port/database", function(err, client) {
|
||||
var connectionString = "pg://user:password@host:port/database";
|
||||
pg.connect(connectionString, function(err, client) {
|
||||
if(err) {
|
||||
//handle connection error
|
||||
}
|
||||
@ -40,14 +38,14 @@ with love and TDD.
|
||||
}
|
||||
}
|
||||
|
||||
### Philosophy
|
||||
## Philosophy
|
||||
|
||||
* well tested
|
||||
* no monkey patching
|
||||
* no dependencies (...besides PostgreSQL)
|
||||
* [in-depth documentation](http://github.com/brianc/node-postgres/wiki) (work in progress)
|
||||
|
||||
### features
|
||||
## features
|
||||
|
||||
- prepared statement support
|
||||
- parameters
|
||||
@ -58,8 +56,9 @@ with love and TDD.
|
||||
- float <-> double, numeric
|
||||
- boolean <-> boolean
|
||||
- notification message support
|
||||
- tested like a Toyota
|
||||
~1000 assertions executed on
|
||||
- connection pooling
|
||||
- mucho testing
|
||||
~250 tests executed on
|
||||
- ubuntu
|
||||
- node v0.2.2, v0.2.3, v0.2.4, v0.2.5, v0.3.0, v0.3.1
|
||||
- postgres 8.4.4
|
||||
@ -67,21 +66,31 @@ with love and TDD.
|
||||
- node v0.2.2, v0.2.3, v0.2.4, v0.2.5, v0.3.0, v0.3.1
|
||||
- postgres v8.4.4, v9.0.1 installed both locally and on networked Windows 7
|
||||
|
||||
### Contributing
|
||||
## Contributing
|
||||
|
||||
clone the repo:
|
||||
|
||||
git clone git://github.com/brianc/node-postgres
|
||||
cd node-postgres
|
||||
node test/run.js
|
||||
make test
|
||||
|
||||
And just like magic, you're ready to contribute! <3
|
||||
|
||||
### Contributors
|
||||
|
||||
Many thanks to the following:
|
||||
|
||||
* [creationix](https://github.com/creationix)
|
||||
* [felixge](https://github.com/felixge)
|
||||
* [pshc](https://github.com/pshc)
|
||||
* [pjornblomqvist](https://github.com/bjornblomqvist)
|
||||
* [JulianBirch](https://github.com/JulianBirch)
|
||||
|
||||
## More info please
|
||||
|
||||
### Documentation
|
||||
### [Documentation](node-postgres/wiki)
|
||||
|
||||
__PLEASE__ check out the [WIKI](node-postgres/wiki). __MUCH__ more information there.
|
||||
### __PLEASE__ check out the WIKI
|
||||
|
||||
### Working?
|
||||
|
||||
@ -89,9 +98,7 @@ __PLEASE__ check out the [WIKI](node-postgres/wiki). __MUCH__ more information
|
||||
|
||||
### Why did you write this?
|
||||
|
||||
As soon as I saw node.js for the first time I knew I had found
|
||||
something lovely and simple and _just what I always wanted!_. So...I
|
||||
poked around for a while. I was excited. I still am!
|
||||
As soon as I saw node.js for the first time I knew I had found something lovely and simple and _just what I always wanted!_. So...I poked around for a while. I was excited. I still am!
|
||||
|
||||
I drew major inspiration from [postgres-js](http://github.com/creationix/postgres-js).
|
||||
|
||||
@ -102,9 +109,7 @@ saw there.
|
||||
### Plans for the future?
|
||||
|
||||
- transparent prepared statement caching
|
||||
- connection pooling
|
||||
- more testings of error scenarios
|
||||
- streamline writing of buffers
|
||||
|
||||
## License
|
||||
|
||||
|
||||
58
benchmark/simple-query-bench.js
Normal file
58
benchmark/simple-query-bench.js
Normal file
@ -0,0 +1,58 @@
|
||||
var pg = require(__dirname + '/../lib')
|
||||
var bencher = require('bencher');
|
||||
var helper = require(__dirname + '/../test/test-helper')
|
||||
var conString = helper.connectionString()
|
||||
|
||||
var round = function(num) {
|
||||
return Math.round((num*1000))/1000
|
||||
}
|
||||
|
||||
var doBenchmark = function() {
|
||||
var bench = bencher({
|
||||
name: 'query compare',
|
||||
repeat: 1000,
|
||||
actions: [{
|
||||
name: 'simple query',
|
||||
run: function(next) {
|
||||
var query = client.query('SELECT name FROM person WHERE age > 10');
|
||||
query.on('end', function() {
|
||||
next();
|
||||
});
|
||||
}
|
||||
},{
|
||||
name: 'unnamed prepared statement',
|
||||
run: function(next) {
|
||||
var query = client.query('SELECT name FROM person WHERE age > $1', [10]);
|
||||
query.on('end', function() {
|
||||
next();
|
||||
});
|
||||
}
|
||||
},{
|
||||
name: 'named prepared statement',
|
||||
run: function(next) {
|
||||
var config = {
|
||||
name: 'get peeps',
|
||||
text: 'SELECT name FROM person WHERE age > $1',
|
||||
values: [10]
|
||||
}
|
||||
client.query(config).on('end', function() {
|
||||
next();
|
||||
});
|
||||
}
|
||||
}]
|
||||
});
|
||||
bench(function(result) {
|
||||
console.log();
|
||||
console.log("%s (%d repeats):", result.name, result.repeat)
|
||||
result.actions.forEach(function(action) {
|
||||
console.log(" %s: \n average: %d ms\n total: %d ms", action.name, round(action.meanTime), round(action.totalTime));
|
||||
})
|
||||
client.end();
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
var client = new pg.Client(conString);
|
||||
client.connect();
|
||||
client.connection.once('readyForQuery', doBenchmark)
|
||||
@ -12,7 +12,7 @@ var Connection = require(__dirname + '/connection');
|
||||
var parseConnectionString = function(str) {
|
||||
var result = url.parse(str);
|
||||
result.host = result.hostname;
|
||||
result.database = result.pathname.slice(1);
|
||||
result.database = result.pathname ? result.pathname.slice(1) : null
|
||||
var auth = (result.auth || ':').split(':');
|
||||
result.user = auth[0];
|
||||
result.password = auth[1];
|
||||
|
||||
@ -16,6 +16,7 @@ var Connection = function(config) {
|
||||
this.offset = null;
|
||||
this.encoding = 'utf8';
|
||||
this.parsedStatements = {};
|
||||
this.writer = new Writer();
|
||||
};
|
||||
|
||||
sys.inherits(Connection, EventEmitter);
|
||||
@ -53,14 +54,14 @@ p.connect = function(port, host) {
|
||||
};
|
||||
|
||||
p.startup = function(config) {
|
||||
var bodyBuffer = new Writer()
|
||||
var bodyBuffer = this.writer
|
||||
.addInt16(3)
|
||||
.addInt16(0)
|
||||
.addCString('user')
|
||||
.addCString(config.user)
|
||||
.addCString('database')
|
||||
.addCString(config.database)
|
||||
.addCString('').join();
|
||||
.addCString('').flush();
|
||||
//this message is sent without a code
|
||||
|
||||
var length = bodyBuffer.length + 4;
|
||||
@ -74,7 +75,7 @@ p.startup = function(config) {
|
||||
|
||||
p.password = function(password) {
|
||||
//0x70 = 'p'
|
||||
this.send(0x70, new Writer().addCString(password).join());
|
||||
this.send(0x70, this.writer.addCString(password).flush());
|
||||
};
|
||||
|
||||
p.send = function(code, bodyBuffer) {
|
||||
@ -97,7 +98,7 @@ p.end = function() {
|
||||
|
||||
p.query = function(text) {
|
||||
//0x51 = Q
|
||||
this.send(0x51, new Writer().addCString(text).join());
|
||||
this.send(0x51, this.writer.addCString(text).flush());
|
||||
};
|
||||
|
||||
p.parse = function(query) {
|
||||
@ -111,7 +112,7 @@ p.parse = function(query) {
|
||||
//normalize null type array
|
||||
query.types = query.types || [];
|
||||
var len = query.types.length;
|
||||
var buffer = new Writer()
|
||||
var buffer = this.writer
|
||||
.addCString(query.name) //name of query
|
||||
.addCString(query.text) //actual query text
|
||||
.addInt16(len);
|
||||
@ -120,7 +121,7 @@ p.parse = function(query) {
|
||||
}
|
||||
|
||||
//0x50 = 'P'
|
||||
this.send(0x50, buffer.join());
|
||||
this.send(0x50, buffer.flush());
|
||||
|
||||
return this;
|
||||
};
|
||||
@ -132,7 +133,7 @@ p.bind = function(config) {
|
||||
config.statement = config.statement || '';
|
||||
var values = config.values || [];
|
||||
var len = values.length;
|
||||
var buffer = new Writer()
|
||||
var buffer = this.writer
|
||||
.addCString(config.portal)
|
||||
.addCString(config.statement)
|
||||
.addInt16(0) //always use default text format
|
||||
@ -144,22 +145,22 @@ p.bind = function(config) {
|
||||
} else {
|
||||
val = val.toString();
|
||||
buffer.addInt32(Buffer.byteLength(val));
|
||||
buffer.add(Buffer(val,this.encoding));
|
||||
buffer.addString(val);
|
||||
}
|
||||
}
|
||||
buffer.addInt16(0); //no format codes, use text
|
||||
//0x42 = 'B'
|
||||
this.send(0x42, buffer.join());
|
||||
this.send(0x42, buffer.flush());
|
||||
};
|
||||
|
||||
p.execute = function(config) {
|
||||
config = config || {};
|
||||
config.portal = config.portal || '';
|
||||
config.rows = config.rows || '';
|
||||
var buffer = new Writer()
|
||||
var buffer = this.writer
|
||||
.addCString(config.portal)
|
||||
.addInt32(config.rows)
|
||||
.join();
|
||||
.flush();
|
||||
|
||||
//0x45 = 'E'
|
||||
this.send(0x45, buffer);
|
||||
@ -181,7 +182,7 @@ p.end = function() {
|
||||
};
|
||||
|
||||
p.describe = function(msg) {
|
||||
this.send(0x44, new Writer().addCString(msg.type + (msg.name || '')).join());
|
||||
this.send(0x44, this.writer.addCString(msg.type + (msg.name || '')).flush());
|
||||
};
|
||||
|
||||
//parsing methods
|
||||
|
||||
120
lib/index.js
120
lib/index.js
@ -4,6 +4,36 @@ var net = require('net');
|
||||
var Pool = require(__dirname + '/utils').Pool;
|
||||
var Client = require(__dirname+'/client');
|
||||
var defaults = require(__dirname + '/defaults');
|
||||
|
||||
//wrap up common connection management boilerplate
|
||||
var connect = function(config, callback) {
|
||||
if(poolEnabled()) {
|
||||
return getPooledClient(config, callback)
|
||||
}
|
||||
|
||||
var client = new Client(config);
|
||||
client.connect();
|
||||
|
||||
var onError = function(error) {
|
||||
client.connection.removeListener('readyForQuery', onReady);
|
||||
callback(error);
|
||||
}
|
||||
|
||||
var onReady = function() {
|
||||
client.removeListener('error', onError);
|
||||
callback(null, client);
|
||||
client.on('drain', client.end.bind(client));
|
||||
}
|
||||
|
||||
client.once('error', onError);
|
||||
|
||||
//TODO refactor
|
||||
//i don't like reaching into the client's connection for attaching
|
||||
//to specific events here
|
||||
client.connection.once('readyForQuery', onReady);
|
||||
}
|
||||
|
||||
|
||||
//connection pool global cache
|
||||
var clientPools = {
|
||||
}
|
||||
@ -13,12 +43,13 @@ var poolEnabled = function() {
|
||||
}
|
||||
|
||||
var log = function() {
|
||||
|
||||
//do nothing
|
||||
}
|
||||
|
||||
var log = function() {
|
||||
console.log.apply(console, arguments);
|
||||
}
|
||||
//for testing
|
||||
// var log = function() {
|
||||
// console.log.apply(console, arguments);
|
||||
// }
|
||||
|
||||
var getPooledClient = function(config, callback) {
|
||||
//lookup pool using config as key
|
||||
@ -27,16 +58,17 @@ var getPooledClient = function(config, callback) {
|
||||
|
||||
//create pool if doesn't exist
|
||||
if(!pool) {
|
||||
log("creating pool %s", config)
|
||||
//log("creating pool %s", config)
|
||||
pool = clientPools[config] = new Pool(defaults.poolSize, function() {
|
||||
log("creating new client in pool %s", config)
|
||||
//log("creating new client in pool %s", config)
|
||||
var client = new Client(config);
|
||||
client.connected = false;
|
||||
return client;
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
pool.checkOut(function(err, client) {
|
||||
|
||||
//if client already connected just
|
||||
//pass it along to the callback and return
|
||||
if(client.connected) {
|
||||
@ -72,56 +104,36 @@ var getPooledClient = function(config, callback) {
|
||||
}
|
||||
|
||||
//destroys the world
|
||||
var end = function(callback) {
|
||||
for(var name in clientPools) {
|
||||
var pool = clientPools[name];
|
||||
log("destroying pool %s", name);
|
||||
pool.waits.forEach(function(wait) {
|
||||
wait(new Error("Client is being destroyed"))
|
||||
})
|
||||
pool.waits = [];
|
||||
pool.items.forEach(function(item) {
|
||||
var client = item.ref;
|
||||
if(client.activeQuery) {
|
||||
log("client is still active, waiting for it to complete");
|
||||
client.on('drain', client.end.bind(client))
|
||||
} else {
|
||||
client.end();
|
||||
}
|
||||
})
|
||||
//remove reference to pool lookup
|
||||
clientPools[name] = null;
|
||||
delete(clientPools[name])
|
||||
//or optionally only a single pool
|
||||
//mostly used for testing or
|
||||
//a hard shutdown
|
||||
var end = function(name) {
|
||||
if(!name) {
|
||||
for(var poolName in clientPools) {
|
||||
end(poolName)
|
||||
return
|
||||
}
|
||||
}
|
||||
var pool = clientPools[name];
|
||||
//log("destroying pool %s", name);
|
||||
pool.waits.forEach(function(wait) {
|
||||
wait(new Error("Client is being destroyed"))
|
||||
})
|
||||
pool.waits = [];
|
||||
pool.items.forEach(function(item) {
|
||||
var client = item.ref;
|
||||
if(client.activeQuery) {
|
||||
//log("client is still active, waiting for it to complete");
|
||||
client.on('drain', client.end.bind(client))
|
||||
} else {
|
||||
client.end();
|
||||
}
|
||||
})
|
||||
//remove reference to pool lookup
|
||||
clientPools[name] = null;
|
||||
delete(clientPools[name])
|
||||
}
|
||||
|
||||
//wrap up common connection management boilerplate
|
||||
var connect = function(config, callback) {
|
||||
if(poolEnabled()) {
|
||||
return getPooledClient(config, callback)
|
||||
}
|
||||
throw new Error("FUCK")
|
||||
var client = new Client(config);
|
||||
client.connect();
|
||||
|
||||
var onError = function(error) {
|
||||
client.connection.removeListener('readyForQuery', onReady);
|
||||
callback(error);
|
||||
}
|
||||
|
||||
var onReady = function() {
|
||||
client.removeListener('error', onError);
|
||||
callback(null, client);
|
||||
client.on('drain', client.end.bind(client));
|
||||
}
|
||||
|
||||
client.once('error', onError);
|
||||
|
||||
//TODO refactor
|
||||
//i don't like reaching into the client's connection for attaching
|
||||
//to specific events here
|
||||
client.connection.once('readyForQuery', onReady);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Client: Client,
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var sys = require('sys');var sys = require('sys');
|
||||
var Row = require(__dirname + '/row');
|
||||
|
||||
var Query = function(config) {
|
||||
this.text = config.text;
|
||||
@ -44,7 +43,7 @@ p.submit = function(connection) {
|
||||
};
|
||||
};
|
||||
var handleDatarow = function(msg) {
|
||||
var result = new Row();
|
||||
var result = {};
|
||||
for(var i = 0; i < msg.fields.length; i++) {
|
||||
var rawValue = msg.fields[i];
|
||||
result[names[i]] = rawValue === null ? null : converters[i](rawValue);
|
||||
@ -75,8 +74,9 @@ p.submit = function(connection) {
|
||||
if(self.callback) {
|
||||
self.callback(err);
|
||||
connection.removeListener('commandComplete', onCommandComplete);
|
||||
} else {
|
||||
self.emit('error', err);
|
||||
}
|
||||
self.emit('error', err);
|
||||
self.emit('end');
|
||||
};
|
||||
|
||||
@ -180,7 +180,7 @@ var dateParser = function(isoDate) {
|
||||
var seconds = /(\d{2})/.exec(end);
|
||||
seconds = (seconds ? seconds[1] : 0);
|
||||
seconds = parseInt(seconds,10);
|
||||
var mili = /\.(\d{1,})/.exec(end+"000");
|
||||
var mili = /\.(\d{1,})/.exec(end+"000");
|
||||
mili = mili ? mili[1].slice(0,3) : 0;
|
||||
var tZone = /([Z|+\-])(\d{2})?(\d{2})?/.exec(end);
|
||||
//minutes to adjust for timezone
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
var sys = require('sys');
|
||||
var Row = function() {
|
||||
|
||||
};
|
||||
|
||||
var p = Row.prototype;
|
||||
|
||||
module.exports = Row;
|
||||
127
lib/writer.js
127
lib/writer.js
@ -1,60 +1,93 @@
|
||||
var Writer = function() {
|
||||
this.buffers = [];
|
||||
var Writer = function(size) {
|
||||
this.size = size || 1024;
|
||||
this.buffer = new Buffer(this.size);
|
||||
this.offset = 0;
|
||||
};
|
||||
|
||||
var p = Writer.prototype;
|
||||
|
||||
p.add = function(buffer) {
|
||||
this.buffers.push(buffer);
|
||||
p._remaining = function() {
|
||||
return this.buffer.length - this.offset;
|
||||
}
|
||||
|
||||
p._resize = function() {
|
||||
var oldBuffer = this.buffer;
|
||||
this.buffer = Buffer(oldBuffer.length + this.size);
|
||||
oldBuffer.copy(this.buffer);
|
||||
}
|
||||
|
||||
//resizes internal buffer if not enough size left
|
||||
p._ensure = function(size) {
|
||||
if(this._remaining() < size) {
|
||||
this._resize()
|
||||
}
|
||||
}
|
||||
|
||||
p.addInt32 = function(num) {
|
||||
this._ensure(4)
|
||||
this.buffer[this.offset++] = (num >>> 24 & 0xFF)
|
||||
this.buffer[this.offset++] = (num >>> 16 & 0xFF)
|
||||
this.buffer[this.offset++] = (num >>> 8 & 0xFF)
|
||||
this.buffer[this.offset++] = (num >>> 0 & 0xFF)
|
||||
return this;
|
||||
};
|
||||
}
|
||||
|
||||
p.addInt16 = function(val, front) {
|
||||
return this.add(Buffer([
|
||||
(val >>> 8),
|
||||
(val >>> 0)
|
||||
]));
|
||||
};
|
||||
p.addInt16 = function(num) {
|
||||
this._ensure(2)
|
||||
this.buffer[this.offset++] = (num >>> 8 & 0xFF)
|
||||
this.buffer[this.offset++] = (num >>> 0 & 0xFF)
|
||||
return this;
|
||||
}
|
||||
|
||||
p.getByteLength = function(initial) {
|
||||
return this.buffers.reduce(function(previous, current){
|
||||
return previous + current.length;
|
||||
},initial || 0);
|
||||
};
|
||||
p.addCString = function(string) {
|
||||
var string = string || "";
|
||||
var len = Buffer.byteLength(string) + 1;
|
||||
this._ensure(len);
|
||||
this.buffer.write(string, this.offset);
|
||||
this.offset += len;
|
||||
this.buffer[this.offset] = 0; //add null terminator
|
||||
return this;
|
||||
}
|
||||
|
||||
p.addInt32 = function(val, first) {
|
||||
return this.add(Buffer([
|
||||
(val >>> 24 & 0xFF),
|
||||
(val >>> 16 & 0xFF),
|
||||
(val >>> 8 & 0xFF),
|
||||
(val >>> 0 & 0xFF)
|
||||
]));
|
||||
};
|
||||
|
||||
p.addCString = function(val) {
|
||||
var len = Buffer.byteLength(val);
|
||||
var buffer = new Buffer(len+1);
|
||||
buffer.write(val);
|
||||
buffer[len] = 0;
|
||||
return this.add(buffer);
|
||||
};
|
||||
|
||||
p.addChar = function(char, first) {
|
||||
return this.add(Buffer(char,'utf8'), first);
|
||||
};
|
||||
p.addChar = function(char) {
|
||||
this._ensure(1);
|
||||
this.buffer.write(char, this.offset);
|
||||
this.offset++;
|
||||
return this;
|
||||
}
|
||||
|
||||
p.join = function() {
|
||||
var result = Buffer(this.getByteLength());
|
||||
var index = 0;
|
||||
var buffers = this.buffers;
|
||||
var length = this.buffers.length;
|
||||
for(var i = 0; i < length; i ++) {
|
||||
var buffer = buffers[i];
|
||||
buffer.copy(result, index, 0);
|
||||
index += buffer.length;
|
||||
}
|
||||
return this.buffer.slice(0, this.offset);
|
||||
}
|
||||
|
||||
p.addString = function(string) {
|
||||
var string = string || "";
|
||||
var len = Buffer.byteLength(string);
|
||||
this._ensure(len);
|
||||
this.buffer.write(string, this.offset);
|
||||
this.offset += len;
|
||||
return this;
|
||||
}
|
||||
|
||||
p.getByteLength = function() {
|
||||
return this.offset;
|
||||
}
|
||||
|
||||
p.add = function(otherBuffer) {
|
||||
this._ensure(otherBuffer.length);
|
||||
otherBuffer.copy(this.buffer, this.offset);
|
||||
this.offset += otherBuffer.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
p.clear = function() {
|
||||
this.offset=0;
|
||||
}
|
||||
|
||||
p.flush = function() {
|
||||
var result = this.join();
|
||||
this.clear();
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = Writer;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{ "name": "pg",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.2",
|
||||
"description": "Pure JavaScript PostgreSQL client",
|
||||
"homepage": "http://github.com/brianc/node-postgres",
|
||||
"repository" : {
|
||||
|
||||
23
script/test-connection.js
Normal file
23
script/test-connection.js
Normal file
@ -0,0 +1,23 @@
|
||||
var helper = require(__dirname + '/../test/test-helper');
|
||||
var connectionString = helper.connectionString();
|
||||
console.log();
|
||||
console.log("testing ability to connect to '%s'", connectionString);
|
||||
var pg = require(__dirname + '/../lib');
|
||||
pg.connect(connectionString, function(err, client) {
|
||||
if(err !== null) {
|
||||
console.error("Recieved connection error when attempting to contact PostgreSQL:");
|
||||
console.error(err);
|
||||
process.exit(255);
|
||||
}
|
||||
console.log("Checking for existance of required test table 'person'")
|
||||
client.query("SELECT COUNT(name) FROM person", function(err, callback) {
|
||||
if(err != null) {
|
||||
console.error("Recieved error when executing query 'SELECT COUNT(name) FROM person'")
|
||||
console.error("It is possible you have not yet run the table create script under script/create-test-tables")
|
||||
console.error("Consult the postgres-node wiki under the 'Testing' section for more information")
|
||||
console.error(err);
|
||||
process.exit(255);
|
||||
}
|
||||
pg.end();
|
||||
})
|
||||
})
|
||||
@ -17,6 +17,9 @@ for(var i = 0; i < args.length; i++) {
|
||||
case '--password':
|
||||
config.password = args[++i];
|
||||
break;
|
||||
case '--verbose':
|
||||
config.verbose = (args[++i] == "true");
|
||||
break;
|
||||
case '-d':
|
||||
case '--database':
|
||||
config.database = args[++i];
|
||||
@ -45,5 +48,5 @@ var log = function(keys) {
|
||||
console.log(key + ": '" + config[key] + "'");
|
||||
});
|
||||
}
|
||||
//log(['user','password','database','port','host'])
|
||||
|
||||
module.exports = config;
|
||||
|
||||
@ -1,9 +1,20 @@
|
||||
var helper = require(__dirname + '/../test-helper');
|
||||
var pg = require(__dirname + '/../../../lib');
|
||||
var connectionString = helper.connectionString(__filename);
|
||||
|
||||
var log = function() {
|
||||
//console.log.apply(console, arguments);
|
||||
}
|
||||
|
||||
var sink = new helper.Sink(4, 10000, function() {
|
||||
log("ending connection pool: %s", connectionString);
|
||||
pg.end(connectionString);
|
||||
});
|
||||
|
||||
test('api', function() {
|
||||
pg.connect(helper.args, assert.calls(function(err, client) {
|
||||
assert.equal(err, null, "Failed to connect");
|
||||
log("connecting to %s", connectionString)
|
||||
pg.connect(connectionString, assert.calls(function(err, client) {
|
||||
assert.equal(err, null, "Failed to connect: " + sys.inspect(err));
|
||||
|
||||
client.query('CREATE TEMP TABLE band(name varchar(100))');
|
||||
|
||||
@ -13,23 +24,30 @@ test('api', function() {
|
||||
|
||||
|
||||
test('simple query execution',assert.calls( function() {
|
||||
client.query("SELECT * FROM band WHERE name = 'the beach boys'", function(err, result) {
|
||||
log("executing simple query")
|
||||
client.query("SELECT * FROM band WHERE name = 'the beach boys'", assert.calls(function(err, result) {
|
||||
assert.length(result.rows, 1)
|
||||
assert.equal(result.rows.pop().name, 'the beach boys')
|
||||
});
|
||||
log("simple query executed")
|
||||
}));
|
||||
|
||||
}))
|
||||
|
||||
test('prepared statement execution',assert.calls( function() {
|
||||
log("executing prepared statement 1")
|
||||
client.query('SELECT * FROM band WHERE name = $1', ['dead black hearts'],assert.calls( function(err, result) {
|
||||
log("Prepared statement 1 finished")
|
||||
assert.length(result.rows, 1);
|
||||
assert.equal(result.rows.pop().name, 'dead black hearts');
|
||||
}))
|
||||
|
||||
log("executing prepared statement two")
|
||||
client.query('SELECT * FROM band WHERE name LIKE $1 ORDER BY name', ['the %'], assert.calls(function(err, result) {
|
||||
log("prepared statement two finished")
|
||||
assert.length(result.rows, 2);
|
||||
assert.equal(result.rows.pop().name, 'the flaming lips');
|
||||
assert.equal(result.rows.pop().name, 'the beach boys');
|
||||
sink.add();
|
||||
}))
|
||||
}))
|
||||
|
||||
@ -37,12 +55,16 @@ test('api', function() {
|
||||
})
|
||||
|
||||
test('executing nested queries', function() {
|
||||
pg.connect(helper.args, assert.calls(function(err, client) {
|
||||
pg.connect(connectionString, assert.calls(function(err, client) {
|
||||
assert.isNull(err);
|
||||
log("connected for nested queriese")
|
||||
client.query('select now as now from NOW()', assert.calls(function(err, result) {
|
||||
assert.equal(new Date().getYear(), result.rows[0].now.getYear())
|
||||
client.query('select now as now_again FROM NOW()', assert.calls(function() {
|
||||
client.query('select * FROM NOW()', assert.calls(function() {
|
||||
log('all nested queries recieved')
|
||||
assert.ok('all queries hit')
|
||||
sink.add();
|
||||
}))
|
||||
}))
|
||||
}))
|
||||
@ -50,10 +72,23 @@ test('executing nested queries', function() {
|
||||
})
|
||||
|
||||
test('raises error if cannot connect', function() {
|
||||
var connectionString = "pg://asdf@seoiasfd:4884/ieieie";
|
||||
var connectionString = "pg://sfalsdkf:asdf@localhost/ieieie";
|
||||
log("trying to connect to invalid place for error")
|
||||
pg.connect(connectionString, assert.calls(function(err, client) {
|
||||
assert.ok(err, 'should have raised an error')
|
||||
log("invalid connection supplied error to callback")
|
||||
sink.add();
|
||||
}))
|
||||
})
|
||||
|
||||
pg.end();
|
||||
test("query errors are handled and do not bubble if callback is provded", function() {
|
||||
pg.connect(connectionString, assert.calls(function(err, client) {
|
||||
assert.isNull(err)
|
||||
log("checking for query error")
|
||||
client.query("SELECT OISDJF FROM LEIWLISEJLSE", assert.calls(function(err, result) {
|
||||
assert.ok(err);
|
||||
log("query error supplied error to callback")
|
||||
sink.add();
|
||||
}))
|
||||
}))
|
||||
})
|
||||
|
||||
@ -4,7 +4,7 @@ test("simple query interface", function() {
|
||||
|
||||
var client = helper.client();
|
||||
|
||||
var query = client.query("select name from person");
|
||||
var query = client.query("select name from person order by name");
|
||||
|
||||
client.on('drain', client.end.bind(client));
|
||||
|
||||
@ -12,6 +12,17 @@ test("simple query interface", function() {
|
||||
query.on('row', function(row) {
|
||||
rows.push(row['name'])
|
||||
});
|
||||
query.once('row', function(row) {
|
||||
test('Can iterate through columns', function () {
|
||||
var columnCount = 0;
|
||||
for (column in row) {
|
||||
columnCount++;
|
||||
};
|
||||
if ('length' in row) {
|
||||
assert.length(row, columnCount, 'Iterating through the columns gives a different length from calling .length.');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
assert.emits(query, 'end', function() {
|
||||
test("returned right number of rows", function() {
|
||||
@ -51,4 +62,3 @@ test("multiple select statements", function() {
|
||||
});
|
||||
client.on('drain', client.end.bind(client));
|
||||
});
|
||||
|
||||
|
||||
@ -10,7 +10,11 @@ module.exports = {
|
||||
host: helper.args.host,
|
||||
port: helper.args.port
|
||||
});
|
||||
|
||||
client.connect();
|
||||
return client;
|
||||
}
|
||||
},
|
||||
connectionString: helper.connectionString,
|
||||
Sink: helper.Sink,
|
||||
pg: helper.pg
|
||||
};
|
||||
|
||||
48
test/integration/client/transaction-tests.js
Normal file
48
test/integration/client/transaction-tests.js
Normal file
@ -0,0 +1,48 @@
|
||||
var helper = require(__dirname + '/test-helper');
|
||||
|
||||
test('a single connection transaction', function() {
|
||||
var connectionString = helper.connectionString();
|
||||
var sink = new helper.Sink(1, function() {
|
||||
helper.pg.end();
|
||||
});
|
||||
|
||||
helper.pg.connect(connectionString, assert.calls(function(err, client) {
|
||||
assert.isNull(err);
|
||||
|
||||
client.query('begin');
|
||||
|
||||
var getZed = {
|
||||
text: 'SELECT * FROM person WHERE name = $1',
|
||||
values: ['Zed']
|
||||
};
|
||||
|
||||
test('Zed should not exist in the database', function() {
|
||||
client.query(getZed, assert.calls(function(err, result) {
|
||||
assert.isNull(err);
|
||||
assert.empty(result.rows);
|
||||
}))
|
||||
})
|
||||
|
||||
client.query("INSERT INTO person(name, age) VALUES($1, $2)", ['Zed', 270], assert.calls(function(err, result) {
|
||||
assert.isNull(err)
|
||||
}));
|
||||
|
||||
test('Zed should exist in the database', function() {
|
||||
client.query(getZed, assert.calls(function(err, result) {
|
||||
assert.isNull(err);
|
||||
assert.equal(result.rows[0].name, 'Zed');
|
||||
}))
|
||||
})
|
||||
|
||||
client.query('rollback');
|
||||
|
||||
test('Zed should not exist in the database', function() {
|
||||
client.query(getZed, assert.calls(function(err, result) {
|
||||
assert.isNull(err);
|
||||
assert.empty(result.rows);
|
||||
sink.add();
|
||||
}))
|
||||
})
|
||||
|
||||
}))
|
||||
})
|
||||
@ -1,37 +1,39 @@
|
||||
var helper = require(__dirname + '/test-helper');
|
||||
|
||||
var client = helper.client();
|
||||
client.on('drain', client.end.bind(client));
|
||||
|
||||
var sink;
|
||||
var connectionString = helper.connectionString();
|
||||
var testForTypeCoercion = function(type){
|
||||
client.query("create temp table test_type(col " + type.name + ")");
|
||||
helper.pg.connect(connectionString, function(err, client) {
|
||||
assert.isNull(err)
|
||||
client.query("create temp table test_type(col " + type.name + ")");
|
||||
|
||||
test("Coerces " + type.name, function() {
|
||||
type.values.forEach(function(val) {
|
||||
test("Coerces " + type.name, function() {
|
||||
type.values.forEach(function(val) {
|
||||
|
||||
var insertQuery = client.query({
|
||||
name: 'insert type test ' + type.name,
|
||||
text: 'insert into test_type(col) VALUES($1)',
|
||||
values: [val]
|
||||
var insertQuery = client.query({
|
||||
name: 'insert type test ' + type.name,
|
||||
text: 'insert into test_type(col) VALUES($1)',
|
||||
values: [val]
|
||||
});
|
||||
|
||||
var query = client.query({
|
||||
name: 'get type ' + type.name ,
|
||||
text: 'select col from test_type'
|
||||
});
|
||||
|
||||
assert.emits(query, 'row', function(row) {
|
||||
assert.strictEqual(row.col, val, "expected " + type.name + " of " + val + " but got " + row[0]);
|
||||
});
|
||||
|
||||
client.query({
|
||||
name: 'delete values',
|
||||
text: 'delete from test_type'
|
||||
});
|
||||
sink.add();
|
||||
});
|
||||
|
||||
var query = client.query({
|
||||
name: 'get type ' + type.name ,
|
||||
text: 'select col from test_type'
|
||||
});
|
||||
|
||||
assert.emits(query, 'row', function(row) {
|
||||
assert.strictEqual(row.col, val, "expected " + type.name + " of " + val + " but got " + row[0]);
|
||||
});
|
||||
|
||||
client.query({
|
||||
name: 'delete values',
|
||||
text: 'delete from test_type'
|
||||
});
|
||||
client.query('drop table test_type');
|
||||
});
|
||||
|
||||
client.query('drop table test_type');
|
||||
});
|
||||
})
|
||||
};
|
||||
|
||||
var types = [{
|
||||
@ -76,9 +78,18 @@ var types = [{
|
||||
values: ['13:12:12.321', null]
|
||||
}];
|
||||
|
||||
var valueCount = 0;
|
||||
types.forEach(function(type) {
|
||||
valueCount += type.values.length;
|
||||
})
|
||||
sink = new helper.Sink(valueCount, function() {
|
||||
helper.pg.end();
|
||||
})
|
||||
|
||||
types.forEach(testForTypeCoercion);
|
||||
|
||||
test("timestampz round trip", function() {
|
||||
|
||||
var now = new Date();
|
||||
var client = helper.client();
|
||||
client.on('error', function(err) {
|
||||
@ -112,6 +123,7 @@ test("timestampz round trip", function() {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
client.on('drain', client.end.bind(client));
|
||||
});
|
||||
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
var helper = require(__dirname + "/test-helper")
|
||||
helper.testPoolSize(2);
|
||||
27
test/integration/connection-pool/ending-pool-tests.js
Normal file
27
test/integration/connection-pool/ending-pool-tests.js
Normal file
@ -0,0 +1,27 @@
|
||||
var helper = require(__dirname + '/test-helper')
|
||||
var conString1 = helper.connectionString();
|
||||
var conString2 = helper.connectionString();
|
||||
var conString3 = helper.connectionString();
|
||||
var conString4 = helper.connectionString();
|
||||
|
||||
var called = false;
|
||||
test('disconnects', function() {
|
||||
var sink = new helper.Sink(4, function() {
|
||||
called = true;
|
||||
//this should exit the process, killing each connection pool
|
||||
helper.pg.end();
|
||||
});
|
||||
[conString1, conString2, conString3, conString4].forEach(function() {
|
||||
helper.pg.connect(conString1, function(err, client) {
|
||||
assert.isNull(err);
|
||||
client.query("SELECT * FROM NOW()", function(err, result) {
|
||||
process.nextTick(function() {
|
||||
assert.equal(called, false, "Should not have disconnected yet")
|
||||
sink.add();
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
var helper = require(__dirname + "/test-helper")
|
||||
helper.testPoolSize(10);
|
||||
helper.testPoolSize(11);
|
||||
@ -1,32 +1,2 @@
|
||||
var helper = require(__dirname + "/test-helper")
|
||||
|
||||
setTimeout(function() {
|
||||
helper.pg.defaults.poolSize = 10;
|
||||
test('executes a single pooled connection/query', function() {
|
||||
var args = helper.args;
|
||||
var conString = "pg://"+args.user+":"+args.password+"@"+args.host+":"+args.port+"/"+args.database;
|
||||
var queryCount = 0;
|
||||
helper.pg.connect(conString, assert.calls(function(err, client) {
|
||||
assert.isNull(err);
|
||||
client.query("select * from NOW()", assert.calls(function(err, result) {
|
||||
assert.isNull(err);
|
||||
queryCount++;
|
||||
}))
|
||||
}))
|
||||
var id = setTimeout(function() {
|
||||
assert.equal(queryCount, 1)
|
||||
}, 1000)
|
||||
var check = function() {
|
||||
setTimeout(function() {
|
||||
if(queryCount == 1) {
|
||||
clearTimeout(id)
|
||||
helper.pg.end();
|
||||
} else {
|
||||
check();
|
||||
}
|
||||
}, 50)
|
||||
}
|
||||
check();
|
||||
})
|
||||
}, 1000)
|
||||
|
||||
helper.testPoolSize(1);
|
||||
|
||||
@ -1,4 +1,40 @@
|
||||
module.exports = {
|
||||
args: require(__dirname + "/../test-helper").args,
|
||||
pg: require(__dirname + "/../../../lib")
|
||||
var helper = require(__dirname + "/../test-helper");
|
||||
var pg = require(__dirname + "/../../../lib");
|
||||
helper.pg = pg;
|
||||
|
||||
var testPoolSize = function(max) {
|
||||
var conString = helper.connectionString();
|
||||
var sink = new helper.Sink(max, function() {
|
||||
helper.pg.end(conString);
|
||||
});
|
||||
|
||||
test("can pool " + max + " times", function() {
|
||||
for(var i = 0; i < max; i++) {
|
||||
helper.pg.poolSize = 10;
|
||||
test("connection #" + i + " executes", function() {
|
||||
helper.pg.connect(conString, function(err, client) {
|
||||
assert.isNull(err);
|
||||
client.query("select * from person", function(err, result) {
|
||||
assert.length(result.rows, 26)
|
||||
})
|
||||
client.query("select count(*) as c from person", function(err, result) {
|
||||
assert.equal(result.rows[0].c, 26)
|
||||
})
|
||||
var query = client.query("SELECT * FROM NOW()")
|
||||
query.on('end',function() {
|
||||
sink.add()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
args: helper.args,
|
||||
pg: helper.pg,
|
||||
connectionString: helper.connectionString,
|
||||
Sink: helper.Sink,
|
||||
testPoolSize: testPoolSize
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
var helper = require(__dirname + "/test-helper")
|
||||
helper.testPoolSize(200);
|
||||
@ -1,3 +1,6 @@
|
||||
var helper = require(__dirname + '/../test-helper');
|
||||
//export parent helper stuffs
|
||||
module.exports = { args: helper.args };
|
||||
module.exports = helper;
|
||||
|
||||
if(helper.args.verbose) {
|
||||
}
|
||||
|
||||
25
test/run.js
25
test/run.js
@ -1,25 +0,0 @@
|
||||
|
||||
//executes all the unit tests
|
||||
var fs = require('fs');
|
||||
|
||||
var args = require(__dirname + '/cli');
|
||||
|
||||
var runDir = function(dir) {
|
||||
fs.readdirSync(dir).forEach(function(file) {
|
||||
if(file.indexOf(".js") < 0) {
|
||||
return runDir(fs.realpathSync(dir + file) + "/");
|
||||
}
|
||||
require(dir + file.split('.js') [0]);
|
||||
});
|
||||
};
|
||||
|
||||
var arg = args.test;
|
||||
|
||||
if(arg == 'all') {
|
||||
runDir(__dirname+'/unit/');
|
||||
runDir(__dirname+'/integration/');
|
||||
}
|
||||
else {
|
||||
runDir(__dirname+'/' + arg + '/');
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
require.paths.unshift(__dirname + '/../lib/');
|
||||
|
||||
Client = require('client');
|
||||
@ -11,6 +10,15 @@ buffers = require(__dirname + '/test-buffers');
|
||||
Connection = require('connection');
|
||||
var args = require(__dirname + '/cli');
|
||||
|
||||
process.on('uncaughtException', function(d) {
|
||||
if ('stack' in d && 'message' in d) {
|
||||
console.log("Message: " + d.message);
|
||||
console.log(d.stack);
|
||||
} else {
|
||||
console.log(d);
|
||||
}
|
||||
});
|
||||
|
||||
assert.same = function(actual, expected) {
|
||||
for(var key in expected) {
|
||||
assert.equal(actual[key], expected[key]);
|
||||
@ -85,7 +93,7 @@ assert.length = function(actual, expectedLength) {
|
||||
var expect = function(callback, timeout) {
|
||||
var executed = false;
|
||||
var id = setTimeout(function() {
|
||||
assert.ok(executed, "Expected execution of " + callback + " fired");
|
||||
assert.ok(executed, "Expected execution of funtion to be fired");
|
||||
}, timeout || 2000)
|
||||
|
||||
return function(err, queryResult) {
|
||||
@ -101,46 +109,93 @@ assert.isNull = function(item, message) {
|
||||
assert.ok(item === null, message);
|
||||
};
|
||||
|
||||
['equal', 'length', 'empty', 'strictEqual', 'emits', 'equalBuffers', 'same', 'calls', 'ok'].forEach(function(name) {
|
||||
var old = assert[name];
|
||||
assert[name] = function() {
|
||||
test.assertCount++
|
||||
return old.apply(this, arguments);
|
||||
};
|
||||
});
|
||||
|
||||
test = function(name, action) {
|
||||
test.testCount ++;
|
||||
if(args.verbose) {
|
||||
console.log(name);
|
||||
}
|
||||
var result = action();
|
||||
if(result === false) {
|
||||
test.ignored.push(name);
|
||||
process.stdout.write('?');
|
||||
if(!args.verbose) {
|
||||
process.stdout.write('?');
|
||||
}
|
||||
}else{
|
||||
process.stdout.write('.');
|
||||
if(!args.verbose) {
|
||||
process.stdout.write('.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
test.assertCount = test.assertCount || 0;
|
||||
//print out the filename
|
||||
process.stdout.write(require('path').basename(process.argv[1]));
|
||||
//print a new line since we'll be printing test names
|
||||
if(args.verbose) {
|
||||
console.log();
|
||||
}
|
||||
test.testCount = test.testCount || 0;
|
||||
test.ignored = test.ignored || [];
|
||||
test.errors = test.errors || [];
|
||||
test.start = test.start || new Date();
|
||||
|
||||
process.on('exit', function() {
|
||||
console.log('');
|
||||
var duration = ((new Date() - test.start)/1000);
|
||||
console.log(test.testCount + ' tests ' + test.assertCount + ' assertions in ' + duration + ' seconds');
|
||||
test.ignored.forEach(function(name) {
|
||||
console.log("Ignored: " + name);
|
||||
});
|
||||
test.errors.forEach(function(error) {
|
||||
console.log("Error: " + error.name);
|
||||
});
|
||||
if(test.ignored.length || test.errors.length) {
|
||||
test.ignored.forEach(function(name) {
|
||||
console.log("Ignored: " + name);
|
||||
});
|
||||
test.errors.forEach(function(error) {
|
||||
console.log("Error: " + error.name);
|
||||
});
|
||||
console.log('');
|
||||
}
|
||||
test.errors.forEach(function(error) {
|
||||
throw error.e;
|
||||
});
|
||||
});
|
||||
|
||||
process.on('uncaughtException', function(err) {
|
||||
console.error("\n %s", err.stack || err.toString())
|
||||
//causes xargs to abort right away
|
||||
process.exit(255);
|
||||
});
|
||||
|
||||
var count = 0;
|
||||
|
||||
var Sink = function(expected, timeout, callback) {
|
||||
var defaultTimeout = 1000;
|
||||
if(typeof timeout == 'function') {
|
||||
callback = timeout;
|
||||
timeout = defaultTimeout;
|
||||
}
|
||||
timeout = timeout || defaultTimeout;
|
||||
var internalCount = 0;
|
||||
var kill = function() {
|
||||
assert.ok(false, "Did not reach expected " + expected + " with an idle timeout of " + timeout);
|
||||
}
|
||||
var killTimeout = setTimeout(kill, timeout);
|
||||
return {
|
||||
add: function(count) {
|
||||
count = count || 1;
|
||||
internalCount += count;
|
||||
clearTimeout(killTimeout)
|
||||
if(internalCount < expected) {
|
||||
killTimeout = setTimeout(kill, timeout)
|
||||
}
|
||||
else {
|
||||
assert.equal(internalCount, expected);
|
||||
callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
args: args
|
||||
args: args,
|
||||
Sink: Sink,
|
||||
pg: require('index'),
|
||||
connectionString: function() {
|
||||
return "pg"+(count++)+"://"+args.user+":"+args.password+"@"+args.host+":"+args.port+"/"+args.database;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ test('client settings', function() {
|
||||
port: 321,
|
||||
password: password
|
||||
});
|
||||
|
||||
|
||||
assert.equal(client.user, user);
|
||||
assert.equal(client.database, database);
|
||||
assert.equal(client.port, 321);
|
||||
@ -27,3 +27,26 @@ test('client settings', function() {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
test('initializing from a config string', function() {
|
||||
|
||||
test('uses the correct values from the config string', function() {
|
||||
var client = new Client("pg://brian:pass@host1:333/databasename")
|
||||
assert.equal(client.user, 'brian')
|
||||
assert.equal(client.password, "pass")
|
||||
assert.equal(client.host, "host1")
|
||||
assert.equal(client.port, 333)
|
||||
assert.equal(client.database, "databasename")
|
||||
})
|
||||
|
||||
test('when not including all values the defaults are used', function() {
|
||||
var client = new Client("pg://host1")
|
||||
assert.equal(client.user, "")
|
||||
assert.equal(client.password, "")
|
||||
assert.equal(client.host, "host1")
|
||||
assert.equal(client.port, 5432)
|
||||
assert.equal(client.database, "")
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
//mostly just testing simple row api
|
||||
require(__dirname + "/test-helper");
|
||||
var Row = require('row');
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
require(__dirname + '/test-helper');
|
||||
var Pool = require("utils").Pool;
|
||||
var Pool = require(__dirname + "/../../lib/utils").Pool;
|
||||
|
||||
//this tests the monkey patching
|
||||
//to ensure comptability with older
|
||||
|
||||
@ -1,57 +1,153 @@
|
||||
require(__dirname + "/test-helper");
|
||||
var Writer = require(__dirname + "/../../lib/writer");
|
||||
|
||||
test('adding int32', function() {
|
||||
var testAddingInt32 = function(int, expectedBuffer) {
|
||||
test('writes ' + int, function() {
|
||||
var subject = new Writer();
|
||||
var result = subject.addInt32(int).join();
|
||||
assert.equalBuffers(result, expectedBuffer);
|
||||
})
|
||||
}
|
||||
|
||||
testAddingInt32(0, [0, 0, 0, 0]);
|
||||
testAddingInt32(1, [0, 0, 0, 1]);
|
||||
testAddingInt32(256, [0, 0, 1, 0]);
|
||||
test('writes largest int32', function() {
|
||||
//todo need to find largest int32 when I have internet access
|
||||
return false;
|
||||
})
|
||||
|
||||
test('writing multiple int32s', function() {
|
||||
var subject = new Writer();
|
||||
var result = subject.addInt32(1).addInt32(10).addInt32(0).join();
|
||||
assert.equalBuffers(result, [0, 0, 0, 1, 0, 0, 0, 0x0a, 0, 0, 0, 0]);
|
||||
})
|
||||
|
||||
test('having to resize the buffer', function() {
|
||||
test('after resize correct result returned', function() {
|
||||
var subject = new Writer(10);
|
||||
subject.addInt32(1).addInt32(1).addInt32(1)
|
||||
assert.equalBuffers(subject.join(), [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('int16', function() {
|
||||
test('writes 0', function() {
|
||||
var subject = new Writer();
|
||||
var result = subject.addInt16(0).join();
|
||||
assert.equalBuffers(result, [0,0]);
|
||||
})
|
||||
|
||||
test('writes 400', function() {
|
||||
var subject = new Writer();
|
||||
var result = subject.addInt16(400).join();
|
||||
assert.equalBuffers(result, [1, 0x90])
|
||||
})
|
||||
|
||||
test('writes many', function() {
|
||||
var subject = new Writer();
|
||||
var result = subject.addInt16(0).addInt16(1).addInt16(2).join();
|
||||
assert.equalBuffers(result, [0, 0, 0, 1, 0, 2])
|
||||
})
|
||||
|
||||
test('resizes if internal buffer fills up', function() {
|
||||
var subject = new Writer(3);
|
||||
var result = subject.addInt16(2).addInt16(3).join();
|
||||
assert.equalBuffers(result, [0, 2, 0, 3])
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
test('cString', function() {
|
||||
test('writes empty cstring', function() {
|
||||
var subject = new Writer();
|
||||
var result = subject.addCString().join();
|
||||
assert.equalBuffers(result, [0])
|
||||
})
|
||||
|
||||
test('writes non-empty cstring', function() {
|
||||
var subject = new Writer();
|
||||
var result = subject.addCString("!!!").join();
|
||||
assert.equalBuffers(result, [33, 33, 33, 0]);
|
||||
})
|
||||
|
||||
test('resizes if reached end', function() {
|
||||
var subject = new Writer(3);
|
||||
var result = subject.addCString("!!!").join();
|
||||
assert.equalBuffers(result, [33, 33, 33, 0]);
|
||||
})
|
||||
|
||||
test('writes multiple cstrings', function() {
|
||||
var subject = new Writer();
|
||||
var result = subject.addCString("!").addCString("!").join();
|
||||
assert.equalBuffers(result, [33, 0, 33, 0]);
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
test('writes char', function() {
|
||||
var subject = new Writer(2);
|
||||
var result = subject.addChar('a').addChar('b').addChar('c').join();
|
||||
assert.equalBuffers(result, [0x61, 0x62, 0x63])
|
||||
})
|
||||
|
||||
test('gets correct byte length', function() {
|
||||
var subject = new Writer(5);
|
||||
assert.equal(subject.getByteLength(), 0)
|
||||
subject.addInt32(0)
|
||||
assert.equal(subject.getByteLength(), 4)
|
||||
subject.addCString("!")
|
||||
assert.equal(subject.getByteLength(), 6)
|
||||
})
|
||||
|
||||
test('can add arbitrary buffer to the end', function() {
|
||||
var subject = new Writer(4);
|
||||
subject.addCString("!!!")
|
||||
var result = subject.add(Buffer("@@@")).join();
|
||||
assert.equalBuffers(result, [33, 33, 33, 0, 0x40, 0x40, 0x40]);
|
||||
})
|
||||
|
||||
test('can write normal string', function() {
|
||||
var subject = new Writer(4);
|
||||
var result = subject.addString("!").join();
|
||||
assert.equalBuffers(result, [33]);
|
||||
test('can write cString too', function() {
|
||||
var result = subject.addCString("!").join();
|
||||
assert.equalBuffers(result, [33, 33, 0]);
|
||||
test('can resize', function() {
|
||||
var result = subject.addString("!!").join();
|
||||
assert.equalBuffers(result, [33, 33, 0, 33, 33]);
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
|
||||
BufferList.prototype.compare = function(expected) {
|
||||
var buf = this.join();
|
||||
assert.equalBuffers(buf, expected);
|
||||
};
|
||||
test('clearing', function() {
|
||||
var subject = new Writer();
|
||||
subject.addCString("@!!#!#");
|
||||
subject.addInt32(10401);
|
||||
subject.clear();
|
||||
assert.equalBuffers(subject.join(), []);
|
||||
test('can keep writing', function() {
|
||||
var joinedResult = subject.addCString("!").addInt32(9).addInt16(2).join();
|
||||
assert.equalBuffers(joinedResult, [33, 0, 0, 0, 0, 9, 0, 2]);
|
||||
test('flush', function() {
|
||||
var flushedResult = subject.flush();
|
||||
test('returns result', function() {
|
||||
assert.equalBuffers(flushedResult, [33, 0, 0, 0, 0, 9, 0, 2])
|
||||
})
|
||||
test('clears the writer', function() {
|
||||
assert.equalBuffers(subject.join(), [])
|
||||
assert.equalBuffers(subject.flush(), [])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('adds int16', function() {
|
||||
new BufferList().addInt16(5).compare([0, 5]);
|
||||
});
|
||||
})
|
||||
|
||||
test('adds two int16s', function() {
|
||||
new BufferList().addInt16(5).addInt16(3).compare([0,5,0,3]);
|
||||
});
|
||||
|
||||
test('adds int32', function() {
|
||||
new BufferList().addInt32(1).compare([0,0,0,1]);
|
||||
new BufferList().addInt32(1).addInt32(3).compare([0,0,0,1,0,0,0,3]);
|
||||
});
|
||||
|
||||
test('adds CStrings', function() {
|
||||
new BufferList().addCString('').compare([0]);
|
||||
new BufferList().addCString('!!').compare([33,33,0]);
|
||||
new BufferList().addCString('!').addCString('!').compare([33,0,33,0]);
|
||||
});
|
||||
|
||||
test('computes length', function() {
|
||||
var buf = new BufferList().join(true);
|
||||
assert.equalBuffers(buf, [0,0,0,4]);
|
||||
});
|
||||
|
||||
test('appends character', function() {
|
||||
var buf = new BufferList().join(false,'!');
|
||||
assert.equalBuffers(buf,[33]);
|
||||
});
|
||||
|
||||
test('appends char and length', function() {
|
||||
var buf = new BufferList().join(true,'!');
|
||||
assert.equalBuffers(buf,[33,0,0,0,4]);
|
||||
});
|
||||
|
||||
test('does complicated buffer', function() {
|
||||
var buf = new BufferList()
|
||||
.addInt32(1)
|
||||
.addInt16(2)
|
||||
.addCString('!')
|
||||
.join(true,'!');
|
||||
assert.equalBuffers(buf, [33, 0, 0, 0, 0x0c, 0, 0, 0, 1, 0, 2, 33, 0]);
|
||||
});
|
||||
|
||||
test('concats', function() {
|
||||
var buf1 = new BufferList().addInt32(8).join(false,'!');
|
||||
var buf2 = new BufferList().addInt16(1).join();
|
||||
var result = BufferList.concat(buf1, buf2);
|
||||
assert.equalBuffers(result, [33, 0, 0, 0, 8, 0, 1]);
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user