Comparing version 0.4.1 to 0.5.0
@@ -7,31 +7,2 @@ var Pool = require(__dirname + '/utils').Pool; | ||
//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.removeListener('connect', 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.once('connect', onReady); | ||
} | ||
//connection pool global cache | ||
@@ -41,16 +12,3 @@ 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) { | ||
var connect = function(config, callback) { | ||
//lookup pool using config as key | ||
@@ -62,5 +20,3 @@ //TODO this don't work so hot w/ object configs | ||
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); | ||
@@ -73,3 +29,2 @@ client.connected = false; | ||
pool.checkOut(function(err, client) { | ||
//if client already connected just | ||
@@ -99,5 +54,2 @@ //pass it along to the callback and return | ||
//TODO refactor | ||
//i don't like reaching into the client's connection for attaching | ||
//to specific events here | ||
client.once('connect', onReady); | ||
@@ -104,0 +56,0 @@ |
@@ -14,4 +14,5 @@ var EventEmitter = require('events').EventEmitter; | ||
//lazy require native module...the c++ may not have been compiled | ||
module.exports.__defineGetter__("native", function() { | ||
return require(__dirname + '/native'); | ||
}) |
@@ -11,30 +11,2 @@ //require the c++ bindings & export to javascript | ||
var add = function(params, config, paramName) { | ||
var value = config[paramName]; | ||
if(value) { | ||
params.push(paramName+"='"+value+"'"); | ||
} | ||
} | ||
var getLibpgConString = function(config, callback) { | ||
if(typeof config == 'object') { | ||
var params = [] | ||
add(params, config, 'user'); | ||
add(params, config, 'password'); | ||
add(params, config, 'port'); | ||
if(config.database) { | ||
params.push("dbname='" + config.database + "'"); | ||
} | ||
if(config.host) { | ||
if(config.host != 'localhost' && config.host != '127.0.0.1') { | ||
throw new Error("Need to use node to do async DNS on host"); | ||
} | ||
params.push("hostaddr=127.0.0.1 "); | ||
} | ||
callback(params.join(" ")); | ||
} else { | ||
throw new Error("Unrecognized config type for connection"); | ||
} | ||
} | ||
var nativeConnect = p.connect; | ||
@@ -44,3 +16,4 @@ | ||
var self = this; | ||
getLibpgConString(this._config, function(conString) { | ||
utils.buildLibpqConnectionString(this._config, function(err, conString) { | ||
if(err) return self.emit('error', err); | ||
nativeConnect.call(self, conString); | ||
@@ -151,4 +124,15 @@ }) | ||
var item = this.values[i]; | ||
if(item instanceof Date) { | ||
this.values[i] = JSON.stringify(item); | ||
switch(typeof item) { | ||
case 'undefined': | ||
this.values[i] = null; | ||
break; | ||
case 'object': | ||
this.values[i] = item === null ? null : JSON.stringify(item); | ||
break; | ||
case 'string': | ||
//value already string | ||
break; | ||
default: | ||
//numbers | ||
this.values[i] = item.toString(); | ||
} | ||
@@ -159,3 +143,2 @@ } | ||
EventEmitter.call(this); | ||
this._translateValues(); | ||
}; | ||
@@ -170,5 +153,4 @@ | ||
for(var i = 0, len = row.length; i < len; i++) { | ||
var item = row[i]; | ||
var parser = types.getStringTypeParser(item.type); | ||
result[item.name] = parser(item.value); | ||
var item = row[i]; | ||
result[item.name] = item.value == null ? null : types.getStringTypeParser(item.type)(item.value); | ||
} | ||
@@ -202,11 +184,2 @@ return result; | ||
//translates values into strings | ||
p._translateValues = function() { | ||
if(this.values) { | ||
this.values = this.values.map(function(val) { | ||
return val.toString(); | ||
}); | ||
} | ||
} | ||
var pool = require(__dirname + '/client-pool').init(ctor); | ||
@@ -213,0 +186,0 @@ |
@@ -12,5 +12,2 @@ var EventEmitter = require('events').EventEmitter; | ||
this.name = config.name; | ||
//for code clarity purposes we'll declare this here though it's not | ||
//set or used until a rowDescription message comes in | ||
this.rowDescription = null; | ||
this.callback = config.callback; | ||
@@ -129,3 +126,3 @@ this._fieldNames = []; | ||
//TODO is there some btter way to prepare values for the database? | ||
//TODO is there some better way to prepare values for the database? | ||
if(self.values) { | ||
@@ -132,0 +129,0 @@ self.values = self.values.map(function(val) { |
@@ -28,2 +28,6 @@ //maps types from javascript to postgres and vise-versa | ||
var match = dateMatcher.exec(isoDate); | ||
//could not parse date | ||
if(!match) { | ||
return null; | ||
} | ||
var year = match[1]; | ||
@@ -30,0 +34,0 @@ var month = parseInt(match[2],10)-1; |
@@ -23,6 +23,11 @@ var url = require('url'); | ||
} | ||
sys.inherits(Pool, events.EventEmitter); | ||
var p = Pool.prototype; | ||
p.checkOut = function(callback) { | ||
if(!this.maxSize) { | ||
return callback(null, this.createFn()); | ||
} | ||
var len = 0; | ||
@@ -38,9 +43,3 @@ for(var i = 0, len = this.items.length; i < len; i++) { | ||
var result = this.createFn(); | ||
var item = result; | ||
//create function can return item conforming to interface | ||
//of stored items to allow for create function to create | ||
//checked out items | ||
if(typeof item.checkedIn == "undefined") { | ||
var item = {ref: result, checkedIn: true} | ||
} | ||
var item = {ref: result, checkedIn: true} | ||
this.items.push(item); | ||
@@ -122,5 +121,47 @@ if(item.checkedIn) { | ||
var add = function(params, config, paramName) { | ||
var value = config[paramName]; | ||
if(value) { | ||
params.push(paramName+"='"+value+"'"); | ||
} | ||
} | ||
//builds libpq specific connection string | ||
//from a supplied config object | ||
//the config object conforms to the interface of the config object | ||
//accepted by the pure javascript client | ||
var getLibpgConString = function(config, callback) { | ||
if(typeof config == 'object') { | ||
var params = [] | ||
add(params, config, 'user'); | ||
add(params, config, 'password'); | ||
add(params, config, 'port'); | ||
if(config.database) { | ||
params.push("dbname='" + config.database + "'"); | ||
} | ||
if(config.host) { | ||
if(config.host != 'localhost' && config.host != '127.0.0.1') { | ||
//do dns lookup | ||
return require('dns').lookup(config.host, 4, function(err, address) { | ||
if(err) return callback(err, null); | ||
params.push("hostaddr="+address) | ||
callback(null, params.join(" ")) | ||
}) | ||
} | ||
params.push("hostaddr=127.0.0.1 "); | ||
} | ||
callback(null, params.join(" ")); | ||
} else { | ||
throw new Error("Unrecognized config type for connection"); | ||
} | ||
} | ||
module.exports = { | ||
Pool: Pool, | ||
normalizeConnectionInfo: normalizeConnectionInfo | ||
normalizeConnectionInfo: normalizeConnectionInfo, | ||
//only exported here to make testing of this method possible | ||
//since it contains quite a bit of logic and testing for | ||
//each connection scenario in an integration test is impractical | ||
buildLibpqConnectionString: getLibpgConString | ||
} |
@@ -0,1 +1,4 @@ | ||
//binary data writer tuned for creating | ||
//postgres message packets as effeciently as possible by reusing the | ||
//same buffer to avoid memcpy and limit memory allocations | ||
var Writer = function(size) { | ||
@@ -2,0 +5,0 @@ this.size = size || 1024; |
{ "name": "pg", | ||
"version": "0.4.1", | ||
"version": "0.5.0", | ||
"description": "PostgreSQL client - pure javascript & libpq with the same API", | ||
@@ -4,0 +4,0 @@ "keywords" : ["postgres", "pg", "libpq", "postgre", "database", "rdbms"], |
@@ -111,2 +111,3 @@ #node-postgres | ||
* [ef4](https://github.com/ef4) | ||
* [napa3um](https://github.com/napa3um) | ||
@@ -113,0 +114,0 @@ ## Documentation |
@@ -88,1 +88,11 @@ var helper = require(__dirname + '/test-helper'); | ||
}); | ||
test('when connecting to invalid host', function() { | ||
var client = new Client({ | ||
user: 'brian', | ||
password: '1234', | ||
host: 'asldkfjasdf!!#1308140.com' | ||
}) | ||
assert.emits(client, 'error'); | ||
client.connect(); | ||
}) |
@@ -25,3 +25,3 @@ var helper = require(__dirname + '/test-helper'); | ||
client.end() | ||
}, 500) | ||
}, 100) | ||
@@ -28,0 +28,0 @@ }); |
@@ -5,22 +5,25 @@ var helper = require(__dirname + "/test-helper"); | ||
pg.connect(conString, assert.calls(function(err, client) { | ||
assert.isNull(err); | ||
client.query("CREATE TEMP TABLE zugzug(name varchar(10))", assert.calls(function(err, result) { | ||
test('should return insert metadata', function() { | ||
return false; | ||
pg.connect(conString, assert.calls(function(err, client) { | ||
assert.isNull(err); | ||
//let's list this as ignored for now | ||
// process.nextTick(function() { | ||
// test('should identify "CREATE TABLE" message', function() { | ||
// return false; | ||
// assert.equal(result.command, "CREATE TABLE"); | ||
// assert.equal(result.rowCount, 0); | ||
// }) | ||
// }) | ||
assert.equal(result.oid, null); | ||
client.query("INSERT INTO zugzug(name) VALUES('more work?')", assert.calls(function(err, result) { | ||
assert.equal(result.command, "INSERT"); | ||
assert.equal(result.rowCount, 1); | ||
process.nextTick(client.end.bind(client)); | ||
return false; | ||
client.query("CREATE TEMP TABLE zugzug(name varchar(10))", assert.calls(function(err, result) { | ||
assert.isNull(err); | ||
//let's list this as ignored for now | ||
// process.nextTick(function() { | ||
// test('should identify "CREATE TABLE" message', function() { | ||
// return false; | ||
// assert.equal(result.command, "CREATE TABLE"); | ||
// assert.equal(result.rowCount, 0); | ||
// }) | ||
// }) | ||
assert.equal(result.oid, null); | ||
client.query("INSERT INTO zugzug(name) VALUES('more work?')", assert.calls(function(err, result) { | ||
assert.equal(result.command, "INSERT"); | ||
assert.equal(result.rowCount, 1); | ||
process.nextTick(client.end.bind(client)); | ||
return false; | ||
})) | ||
})) | ||
})) | ||
})) | ||
}) |
@@ -7,31 +7,32 @@ var helper = require(__dirname + '/test-helper'); | ||
assert.isNull(err) | ||
client.query("create temp table test_type(col " + type.name + ")"); | ||
client.query("create temp table test_type(col " + type.name + ")", assert.calls(function(err, result) { | ||
assert.isNull(err); | ||
test("Coerces " + type.name, function() { | ||
type.values.forEach(function(val) { | ||
test("Coerces " + type.name, function() { | ||
type.values.forEach(function(val) { | ||
var insertQuery = client.query('insert into test_type(col) VALUES($1)',[val],assert.calls(function(err, result) { | ||
assert.isNull(err); | ||
})); | ||
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' | ||
}); | ||
query.on('error', function(err) { | ||
console.log(err); | ||
throw err; | ||
}); | ||
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]); | ||
}, "row should have been called for " + type.name + " of " + val); | ||
assert.emits(query, 'row', function(row) { | ||
assert.strictEqual(row.col, val, "expected " + type.name + " of " + val + " but got " + row[0]); | ||
client.query('delete from test_type'); | ||
}); | ||
client.query({ | ||
name: 'delete values', | ||
text: 'delete from test_type' | ||
client.query('drop table test_type', function() { | ||
sink.add(); | ||
}); | ||
sink.add(); | ||
}); | ||
client.query('drop table test_type'); | ||
}); | ||
}) | ||
})); | ||
}) | ||
@@ -86,10 +87,11 @@ }; | ||
}) | ||
sink = new helper.Sink(valueCount, function() { | ||
sink = new helper.Sink(types.length, function() { | ||
helper.pg.end(); | ||
}) | ||
types.forEach(testForTypeCoercion); | ||
types.forEach(function(type) { | ||
testForTypeCoercion(type) | ||
}); | ||
test("timestampz round trip", function() { | ||
var now = new Date(); | ||
@@ -129,1 +131,13 @@ var client = helper.client(); | ||
helper.pg.connect(helper.connectionString(), assert.calls(function(err, client) { | ||
assert.isNull(err); | ||
client.query('select null as res;', assert.calls(function(err, res) { | ||
assert.isNull(err); | ||
assert.strictEqual(res.rows[0].res, null) | ||
})) | ||
client.query('select 7 <> $1 as res;',[null], function(err, res) { | ||
assert.isNull(err); | ||
assert.strictEqual(res.rows[0].res, null); | ||
client.end(); | ||
}) | ||
})) |
var helper = require(__dirname + '/../test-helper'); | ||
//TODO would this be better served set at ../test-helper? | ||
if(helper.args.native) { | ||
Client = require(__dirname + '/../../lib/native').Client; | ||
helper.pg = helper.pg.native; | ||
} | ||
@@ -6,0 +8,0 @@ //export parent helper stuffs |
@@ -30,7 +30,7 @@ require.paths.unshift(__dirname + '/../lib/'); | ||
assert.emits = function(item, eventName, callback) { | ||
assert.emits = function(item, eventName, callback, message) { | ||
var called = false; | ||
var id = setTimeout(function() { | ||
test("Should have called " + eventName, function() { | ||
assert.ok(called, "Expected '" + eventName + "' to be called.") | ||
assert.ok(called, message || "Expected '" + eventName + "' to be called.") | ||
}); | ||
@@ -37,0 +37,0 @@ },2000); |
@@ -94,21 +94,25 @@ require(__dirname + '/test-helper'); | ||
test('when creating async new pool members', function() { | ||
var count = 0; | ||
var pool = new Pool(3, function() { | ||
var item = {ref: {name: ++count}, checkedIn: false}; | ||
process.nextTick(function() { | ||
pool.checkIn(item.ref) | ||
}) | ||
return item; | ||
test('a pool with size of zero', function() { | ||
var index = 0; | ||
var pool = new Pool(0, function() { | ||
return index++; | ||
}) | ||
test('one request recieves member', function() { | ||
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.name, 1) | ||
pool.checkOut(assert.calls(function(err, item) { | ||
assert.equal(item.name, 2) | ||
pool.checkOut(assert.calls(function(err, item) { | ||
assert.equal(item.name, 3) | ||
})) | ||
})) | ||
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); | ||
})) | ||
}) | ||
@@ -171,3 +175,3 @@ }) | ||
}); | ||
test('uses overridden defaults', function() { | ||
@@ -188,1 +192,54 @@ defaults.host = "/var/run/postgresql"; | ||
}) | ||
test('libpq connection string building', function() { | ||
var checkForPart = function(array, part) { | ||
assert.ok(array.indexOf(part) > -1, array.join(" ") + " did not contain " + part); | ||
} | ||
test('builds simple string', function() { | ||
var config = { | ||
user: 'brian', | ||
password: 'xyz', | ||
port: 888, | ||
host: 'localhost', | ||
database: 'bam' | ||
} | ||
utils.buildLibpqConnectionString(config, assert.calls(function(err, constring) { | ||
assert.isNull(err) | ||
var parts = constring.split(" "); | ||
checkForPart(parts, "user='brian'") | ||
checkForPart(parts, "password='xyz'") | ||
checkForPart(parts, "port='888'") | ||
checkForPart(parts, "hostaddr=127.0.0.1") | ||
checkForPart(parts, "dbname='bam'") | ||
})) | ||
}) | ||
test('builds dns string', function() { | ||
var config = { | ||
user: 'brian', | ||
password: 'asdf', | ||
port: 5432, | ||
host: 'example.com' | ||
} | ||
utils.buildLibpqConnectionString(config, assert.calls(function(err, constring) { | ||
assert.isNull(err); | ||
var parts = constring.split(" "); | ||
checkForPart(parts, "user='brian'") | ||
checkForPart(parts, "hostaddr=192.0.32.10") | ||
})) | ||
}) | ||
test('error when dns fails', function() { | ||
var config = { | ||
user: 'brian', | ||
password: 'asf', | ||
port: 5432, | ||
host: 'asdlfkjasldfkksfd#!$!!!!..com' | ||
} | ||
utils.buildLibpqConnectionString(config, assert.calls(function(err, constring) { | ||
assert.ok(err); | ||
assert.isNull(constring) | ||
})) | ||
}) | ||
}) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
188400
81
4989
154
119
3