node-postgres/lib/index.js
2010-12-14 21:21:28 -06:00

145 lines
3.3 KiB
JavaScript

var EventEmitter = require('events').EventEmitter;
var sys = require('sys');
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 = {
}
var poolEnabled = function() {
return defaults.poolSize;
}
var log = function() {
//do nothing
}
//for testing
// var log = function() {
// console.log.apply(console, arguments);
// }
var getPooledClient = function(config, callback) {
//lookup pool using config as key
//TODO this don't work so hot w/ object configs
var pool = clientPools[config];
//create pool if doesn't exist
if(!pool) {
//log("creating pool %s", config)
pool = clientPools[config] = new Pool(defaults.poolSize, function() {
//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) {
callback(null, client);
return;
}
var onError = function(error) {
client.connection.removeListener('readyForQuery', onReady);
callback(error);
pool.checkIn(client);
}
var onReady = function() {
client.removeListener('error', onError);
client.connected = true;
callback(null, client);
client.on('drain', function() {
pool.checkIn(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);
client.connect();
});
}
//destroys the world
//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])
}
module.exports = {
Client: Client,
Connection: require(__dirname + '/connection'),
connect: connect,
end: end,
defaults: defaults
}