Comparing version 0.5.3 to 0.5.4
@@ -15,3 +15,5 @@ module.exports = { | ||
//0 will disable connection pooling | ||
poolSize: 10 | ||
poolSize: 10, | ||
//duration of node-pool timeout | ||
poolIdleTimeout: 30000 | ||
} |
var EventEmitter = require('events').EventEmitter; | ||
var Client = require(__dirname+'/client'); | ||
var defaults = require(__dirname + '/defaults'); | ||
var pool = require(__dirname + "/client-pool").init(Client); | ||
var genericPool = require('generic-pool'); | ||
//cache of existing client pools | ||
var pools = {}; | ||
//returns connect function using supplied client constructor | ||
var makeConnectFunction = function(ClientConstructor) { | ||
return function(config, callback) { | ||
var c = config; | ||
var cb = callback; | ||
//allow for no config to be passed | ||
if(typeof c === 'function') { | ||
cb = c; | ||
c = defaults; | ||
} | ||
//get unique pool name if using a config object instead of config string | ||
var poolName = typeof(c) === 'string' ? c : c.user+c.host+c.port+c.database; | ||
var pool = pools[poolName]; | ||
if(pool) return pool.acquire(cb); | ||
var pool = pools[poolName] = genericPool.Pool({ | ||
name: poolName, | ||
create: function(callback) { | ||
var client = new Client(c); | ||
client.connect(); | ||
var connectError = function(err) { | ||
client.removeListener('connect', connectSuccess); | ||
callback(err, null); | ||
}; | ||
var connectSuccess = function() { | ||
client.removeListener('error', connectError); | ||
callback(null, client); | ||
}; | ||
client.once('connect', connectSuccess); | ||
client.once('error', connectError); | ||
client.on('drain', function() { | ||
pool.release(client); | ||
}); | ||
}, | ||
destroy: function(client) { | ||
client.end(); | ||
}, | ||
max: defaults.poolSize, | ||
idleTimeoutMillis: defaults.poolIdleTimeout | ||
}); | ||
return pool.acquire(cb); | ||
} | ||
} | ||
var end = function() { | ||
Object.keys(pools).forEach(function(name) { | ||
var pool = pools[name]; | ||
pool.drain(function() { | ||
pool.destroyAllNow(); | ||
}); | ||
}) | ||
}; | ||
module.exports = { | ||
Client: Client, | ||
Connection: require(__dirname + '/connection'), | ||
connect: pool.connect, | ||
end: pool.end, | ||
connect: makeConnectFunction(Client), | ||
end: end, | ||
defaults: defaults | ||
} | ||
var nativeExport = null; | ||
//lazy require native module...the c++ may not have been compiled | ||
module.exports.__defineGetter__("native", function() { | ||
return require(__dirname + '/native'); | ||
if(nativeExport === null) { | ||
var NativeClient = require(__dirname + '/native'); | ||
nativeExport = { | ||
Client: NativeClient, | ||
connect: makeConnectFunction(NativeClient), | ||
end: end, | ||
defaults: defaults | ||
} | ||
} | ||
return nativeExport; | ||
}) |
@@ -179,9 +179,2 @@ //require the c++ bindings & export to javascript | ||
var pool = require(__dirname + '/client-pool').init(ctor); | ||
module.exports = { | ||
Client: ctor, | ||
connect: pool.connect, | ||
end: pool.end, | ||
defaults: require(__dirname + '/defaults') | ||
}; | ||
module.exports = ctor; |
@@ -6,2 +6,3 @@ var url = require('url'); | ||
//compatibility for old nodes | ||
if(typeof events.EventEmitter.prototype.once !== 'function') { | ||
@@ -17,65 +18,2 @@ events.EventEmitter.prototype.once = function (type, listener) { | ||
var Pool = function(maxSize, createFn) { | ||
events.EventEmitter.call(this); | ||
this.maxSize = maxSize; | ||
this.createFn = createFn; | ||
this.items = []; | ||
this.waits = []; | ||
} | ||
sys.inherits(Pool, events.EventEmitter); | ||
var p = Pool.prototype; | ||
p.checkOut = function(callback) { | ||
if(!this.maxSize) { | ||
return callback(null, this.createFn()); | ||
} | ||
var len = 0; | ||
for(var i = 0, len = this.items.length; i < len; i++) { | ||
var item = this.items[i]; | ||
if(item.checkedIn) { | ||
return this._pulse(item, callback); | ||
} | ||
} | ||
//check if we can create a new item | ||
if(this.items.length < this.maxSize && this.createFn) { | ||
var result = this.createFn(); | ||
var item = {ref: result, checkedIn: true} | ||
this.items.push(item); | ||
if(item.checkedIn) { | ||
return this._pulse(item, callback) | ||
} | ||
} | ||
this.waits.push(callback); | ||
return false; //did not execute sync | ||
} | ||
p.checkIn = function(item) { | ||
//scan current items | ||
for(var i = 0, len = this.items.length; i < len; i++) { | ||
var currentItem = this.items[i]; | ||
if(currentItem.ref == item) { | ||
currentItem.checkedIn = true; | ||
this._pulse(currentItem); | ||
return true; | ||
} | ||
} | ||
//add new item | ||
var newItem = {ref: item, checkedIn: true}; | ||
this.items.push(newItem); | ||
this._pulse(newItem); | ||
return false; | ||
} | ||
p._pulse = function(item, cb) { | ||
cb = cb || this.waits.shift() | ||
if(cb) { | ||
item.checkedIn = false; | ||
cb(null, item.ref) | ||
return true; | ||
} | ||
return false; | ||
}; | ||
var parseConnectionString = function(str) { | ||
@@ -160,3 +98,2 @@ //unix socket | ||
module.exports = { | ||
Pool: Pool, | ||
normalizeConnectionInfo: normalizeConnectionInfo, | ||
@@ -163,0 +100,0 @@ //only exported here to make testing of this method possible |
{ "name": "pg", | ||
"version": "0.5.3", | ||
"version": "0.5.4", | ||
"description": "PostgreSQL client - pure javascript & libpq with the same API", | ||
@@ -12,2 +12,5 @@ "keywords" : ["postgres", "pg", "libpq", "postgre", "database", "rdbms"], | ||
"main" : "./lib", | ||
"dependencies" : { | ||
"generic-pool" : "1.0.6" | ||
}, | ||
"scripts" : { | ||
@@ -14,0 +17,0 @@ "test" : "make test", |
#node-postgres | ||
Non-blocking PostgreSQL client for node.js. Pure JavaScript and native libpq bindings. | ||
Non-blocking PostgreSQL client for node.js. Pure JavaScript and native libpq bindings. Active development, well tested, and production use. | ||
@@ -11,10 +11,2 @@ ## Installation | ||
All examples will work with the pure javascript bindings (currently default) or the libpq native (c/c++) bindings (currently in beta) | ||
To use native libpq bindings replace `require('pg')` with `require('pg').native`. | ||
The two share the same interface so __no other code changes should be required__. If you find yourself having to change code other than the require statement when switching from `pg` to `pg.native`, please report an issue. | ||
node-postgres supports both an 'event emitter' style API and a 'callback' style. The callback style is more concise and generally preferred, but the evented API can come in handy. They can be mixed and matched. The only events which do __not__ fire when callbacks are supplied are the `error` events, as they are to be handled by the callback function. | ||
### Simple, using built-in client pool | ||
@@ -77,5 +69,15 @@ | ||
### Example notes | ||
node-postgres supports both an 'event emitter' style API and a 'callback' style. The callback style is more concise and generally preferred, but the evented API can come in handy. They can be mixed and matched. The only events which do __not__ fire when callbacks are supplied are the `error` events, as they are to be handled by the callback function. | ||
All examples will work with the pure javascript bindings (currently default) or the libpq native (c/c++) bindings (currently in beta) | ||
To use native libpq bindings replace `require('pg')` with `require('pg').native`. | ||
The two share the same interface so __no other code changes should be required__. If you find yourself having to change code other than the require statement when switching from `pg` to `pg.native`, please report an issue. | ||
### Info | ||
* a pure javascript client and native libpq bindings with _the same api_ | ||
* pure javascript client and native libpq bindings share _the same api_ | ||
* _heavily_ tested | ||
@@ -89,3 +91,3 @@ * the same suite of 200+ integration tests passed by both javascript & libpq bindings | ||
* row-by-row result streaming | ||
* optional, built-in connection pooling | ||
* built-in (optional) connection pooling | ||
* responsive project maintainer | ||
@@ -100,5 +102,3 @@ * supported PostgreSQL features | ||
* fast | ||
* No dependencies (other than PostgreSQL) | ||
* No monkey patching | ||
* Tried to mirror the node-mysql api as much as possible for future multi-database-supported ORM implementation ease | ||
* close mirror of the node-mysql api for future multi-database-supported ORM implementation ease | ||
@@ -117,6 +117,7 @@ ### Contributors | ||
* [drdaeman](https://github.com/drdaeman) | ||
* [booo](https://github.com/booo) | ||
## Documentation | ||
Still a work in progress, I am trying to flesh out the wiki... | ||
Documentation is a work in progress primarily taking place on the github WIKI | ||
@@ -127,2 +128,4 @@ ### [Documentation](https://github.com/brianc/node-postgres/wiki) | ||
If you have a question, post it to the FAQ section of the WIKI so everyone can read the answer | ||
## Production Use | ||
@@ -129,0 +132,0 @@ * [bayt.com](http://bayt.com) |
@@ -5,3 +5,3 @@ var helper = require(__dirname + '/../test-helper'); | ||
if(helper.args.native) { | ||
pg = require(__dirname + '/../../../lib/native') | ||
pg = require(__dirname + '/../../../lib').native; | ||
} | ||
@@ -8,0 +8,0 @@ |
var helper = require(__dirname + '/test-helper'); | ||
var sink = new helper.Sink(2, function() { | ||
helper.pg.end(); | ||
}); | ||
test('a single connection transaction', function() { | ||
var connectionString = helper.connectionString(); | ||
var sink = new helper.Sink(1, function() { | ||
helper.pg.end(); | ||
}); | ||
@@ -46,3 +47,2 @@ helper.pg.connect(connectionString, assert.calls(function(err, client) { | ||
}) | ||
})) | ||
@@ -72,5 +72,6 @@ }) | ||
})) | ||
client.query("COMMIT") | ||
client.on('drain', client.end.bind(client)) | ||
client.query("COMMIT", function() { | ||
sink.add(); | ||
}) | ||
}) | ||
}) |
@@ -86,3 +86,3 @@ var helper = require(__dirname + '/test-helper'); | ||
}) | ||
sink = new helper.Sink(types.length, function() { | ||
sink = new helper.Sink(types.length + 1, function() { | ||
helper.pg.end(); | ||
@@ -139,4 +139,4 @@ }) | ||
assert.strictEqual(res.rows[0].res, null); | ||
client.end(); | ||
sink.add(); | ||
}) | ||
})) |
var helper = require(__dirname + '/test-helper'); | ||
helper.pg.defaults.poolSize = 1; | ||
helper.pg.defaults.user = helper.args.user; | ||
helper.pg.defaults.password = helper.args.password; | ||
helper.pg.defaults.database = helper.args.database; | ||
helper.pg.defaults.port = helper.args.port; | ||
helper.pg.defaults.host = helper.args.host; | ||
helper.pg.defaults.poolIdleTimeout = 100; | ||
var args = { | ||
@@ -13,12 +18,15 @@ user: helper.args.user, | ||
helper.pg.connect(args, assert.calls(function(err, client) { | ||
assert.isNull(err); | ||
client.iGotAccessed = true; | ||
client.query("SELECT NOW()") | ||
})) | ||
var moreArgs = { | ||
user: helper.args.user + "2", | ||
database: helper.args.database, | ||
password: helper.args.password, | ||
port: helper.args.port, | ||
user: helper.args.user, | ||
host: helper.args.host, | ||
password: helper.args.password, | ||
zomg: true | ||
} | ||
var badArgs = { | ||
user: helper.args.user + 'laksdjfl', | ||
host: helper.args.host, | ||
password: helper.args.password + 'asldkfjlas', | ||
database: helper.args.database, | ||
@@ -29,6 +37,38 @@ port: helper.args.port, | ||
helper.pg.connect(moreArgs, assert.calls(function(err, client) { | ||
assert.isNull(err); | ||
assert.ok(client.iGotAccessed === true) | ||
client.end(); | ||
})) | ||
test('connecting with complete config', function() { | ||
helper.pg.connect(args, assert.calls(function(err, client) { | ||
assert.isNull(err); | ||
client.iGotAccessed = true; | ||
client.query("SELECT NOW()") | ||
})); | ||
}); | ||
test('connecting with different config object', function() { | ||
helper.pg.connect(moreArgs, assert.calls(function(err, client) { | ||
assert.isNull(err); | ||
assert.ok(client.iGotAccessed === true) | ||
client.query("SELECT NOW()"); | ||
})) | ||
}); | ||
test('connecting with all defaults', function() { | ||
helper.pg.connect(assert.calls(function(err, client) { | ||
assert.isNull(err); | ||
assert.ok(client.iGotAccessed === true); | ||
client.end(); | ||
})); | ||
}); | ||
test('connecting with invalid config', function() { | ||
helper.pg.connect(badArgs, assert.calls(function(err, client) { | ||
assert.ok(err != null, "Expected connection error using invalid connection credentials"); | ||
})); | ||
}); |
@@ -5,3 +5,3 @@ var helper = require(__dirname + '/../test-helper'); | ||
if(helper.args.native) { | ||
Client = require(__dirname + '/../../lib/native').Client; | ||
Client = require(__dirname + '/../../lib/native'); | ||
helper.pg = helper.pg.native; | ||
@@ -8,0 +8,0 @@ } |
var helper = require(__dirname + "/../test-helper"); | ||
var Client = require(__dirname + "/../../lib/native").Client; | ||
var Client = require(__dirname + "/../../lib/native"); | ||
var conString = helper.connectionString(); | ||
@@ -4,0 +4,0 @@ |
var helper = require(__dirname + "/../test-helper"); | ||
var Client = require(__dirname + "/../../lib/native").Client; | ||
var Client = require(__dirname + "/../../lib/native"); | ||
@@ -4,0 +4,0 @@ test('connecting with wrong parameters', function() { |
var helper = require(__dirname + "/../test-helper"); | ||
var Client = require(__dirname + "/../../lib/native").Client; | ||
var Client = require(__dirname + "/../../lib/native"); | ||
var conString = helper.connectionString(); | ||
@@ -4,0 +4,0 @@ |
var helper = require(__dirname + "/../test-helper"); | ||
var Client = require(__dirname + "/../../lib/native").Client; | ||
var Client = require(__dirname + "/../../lib/native"); | ||
var conString = helper.connectionString(); | ||
@@ -4,0 +4,0 @@ |
var helper = require(__dirname + "/../test-helper"); | ||
var Client = require(__dirname + "/../../lib/native").Client; | ||
var Client = require(__dirname + "/../../lib/native"); | ||
@@ -4,0 +4,0 @@ test('many rows', function() { |
require(__dirname + '/test-helper'); | ||
var utils = require(__dirname + "/../../lib/utils"); | ||
var Pool = utils.Pool; | ||
var defaults = require(__dirname + "/../../lib").defaults; | ||
@@ -24,98 +23,3 @@ | ||
test('an empty pool', function() { | ||
test('with no creation method', function() { | ||
var pool = new Pool(10); | ||
var brian = {name:'brian'}; | ||
test('can set and get an item', function() { | ||
pool.checkIn(brian); | ||
var sync = pool.checkOut(assert.calls(function(err, item) { | ||
assert.equal(brian, item) | ||
assert.same(brian, item) | ||
})) | ||
assert.ok(sync, "should have fired sync") | ||
}) | ||
test('checkout blocks until item checked back in', function() { | ||
var called = false; | ||
var sync = pool.checkOut(assert.calls(function(err, item) { | ||
called = true; | ||
assert.equal(brian, item) | ||
assert.same(brian, item) | ||
})) | ||
assert.ok(sync === false, "Should not have fired sync") | ||
assert.ok(called === false, "Should not have fired callback yet") | ||
pool.checkIn(brian) | ||
}) | ||
}) | ||
test('with a creation method', function() { | ||
var customName = "first"; | ||
var callCount = 0; | ||
var pool = new Pool(3, function() { | ||
return {name: customName + (++callCount)}; | ||
}); | ||
test('creates if pool is not at max size', function() { | ||
var sync = pool.checkOut(assert.calls(function(err, item) { | ||
assert.equal(item.name, "first1"); | ||
})) | ||
assert.ok(sync, "Should have generated item & called callback in sync") | ||
}) | ||
test('creates again if item is checked out', function() { | ||
var sync = pool.checkOut(assert.calls(function(err, item) { | ||
assert.equal(item.name, "first2") | ||
})) | ||
assert.ok(sync, "Should have called in sync again") | ||
}) | ||
var external = {name: 'boom'}; | ||
test('can add another item', function() { | ||
pool.checkIn(external) | ||
var sync = pool.checkOut(assert.calls(function(err, item) { | ||
assert.equal(item.name, 'boom') | ||
})) | ||
assert.ok(sync, "Should have fired 3rd in sync") | ||
}) | ||
test('after pool is full, create is not called again', function() { | ||
var called = false; | ||
var sync = pool.checkOut(assert.calls(function(err, item) { | ||
called = true; | ||
assert.equal(item.name, 'boom') | ||
})) | ||
assert.ok(sync === false, "should not be sync") | ||
assert.ok(called === false, "should not have called callback") | ||
pool.checkIn(external); | ||
}) | ||
}) | ||
}) | ||
test('a pool with size of zero', function() { | ||
var index = 0; | ||
var pool = new Pool(0, function() { | ||
return index++; | ||
}) | ||
test('checkin does nothing', function() { | ||
index = 0; | ||
pool.checkIn(301813); | ||
assert.equal(pool.checkOut(assert.calls(function(err, item) { | ||
assert.equal(item, 0); | ||
}))); | ||
}) | ||
test('always creates a new item', function() { | ||
index = 0; | ||
pool.checkOut(assert.calls(function(err, item) { | ||
assert.equal(item, 0); | ||
})) | ||
pool.checkOut(assert.calls(function(err, item) { | ||
assert.equal(item, 1); | ||
})) | ||
pool.checkOut(assert.calls(function(err, item) { | ||
assert.equal(item, 2); | ||
})) | ||
}) | ||
}) | ||
test('normalizing connection info', function() { | ||
@@ -122,0 +26,0 @@ test('with objects', function() { |
Sorry, the diff of this file is not supported yet
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
158
116
186479
1
4957
+ Addedgeneric-pool@1.0.6
+ Addedgeneric-pool@1.0.6(transitive)