forked from brianc/node-pg-native
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 7efb2e0
Showing
8 changed files
with
315 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
.PHONY: publish-patch test | ||
|
||
test: | ||
npm test | ||
|
||
publish-patch: test | ||
npm version patch -m "Bump version" | ||
git push origin master --tags | ||
npm publish |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
var pg = require('pg').native | ||
var Native = require('../') | ||
|
||
var warmup = function(fn, cb) { | ||
var count = 0; | ||
var max = 10; | ||
var run = function(err) { | ||
if(err) return cb(err); | ||
|
||
if(max >= count++) { | ||
return fn(run) | ||
} | ||
|
||
cb() | ||
} | ||
run(); | ||
} | ||
|
||
var native = Native(); | ||
native.connectSync(); | ||
|
||
var queryText = 'SELECT generate_series(0, 1000)'; | ||
var client = new pg.Client(); | ||
client.connect(function() { | ||
var pure = function(cb) { | ||
client.query(queryText, function(err) { | ||
if(err) throw err; | ||
cb(err); | ||
}); | ||
} | ||
var nativeQuery = function(cb) { | ||
native.query(queryText, function(err) { | ||
if(err) throw err; | ||
cb(err); | ||
}); | ||
} | ||
|
||
var run = function() { | ||
var start = Date.now() | ||
warmup(pure, function() { | ||
console.log('pure done', Date.now() - start) | ||
start = Date.now() | ||
warmup(nativeQuery, function() { | ||
console.log('native done', Date.now() - start) | ||
}) | ||
}) | ||
} | ||
|
||
setInterval(function() { | ||
run() | ||
}, 500) | ||
|
||
}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
var Libpq = require('libpq'); | ||
|
||
var Client = module.exports = function(types) { | ||
if(!types) { | ||
var pgTypes = require('pg-types') | ||
types = pgTypes.getTypeParser.bind(pgTypes) | ||
} | ||
if(!(this instanceof Client)) { | ||
return new Client(types); | ||
} | ||
this.pq = new Libpq(); | ||
this.types = types; | ||
}; | ||
|
||
Client.prototype.connect = function(params, cb) { | ||
this.pq.connect(params, cb); | ||
}; | ||
|
||
Client.prototype.connectSync = function(params) { | ||
this.pq.connectSync(params); | ||
}; | ||
|
||
Client.prototype.end = function(cb) { | ||
this.pq.finish(); | ||
if(cb) setImmediate(cb); | ||
}; | ||
|
||
var mapResults = function(pq, types) { | ||
var rows = []; | ||
var rowCount = pq.ntuples(); | ||
var colCount = pq.nfields(); | ||
for(var i = 0; i < rowCount; i++) { | ||
var row = {}; | ||
rows.push(row); | ||
for(var j = 0; j < colCount; j++) { | ||
var rawValue = pq.getvalue(i, j); | ||
var value = rawValue; | ||
if(rawValue == '') { | ||
if(pq.getisnull()) { | ||
value = null; | ||
} | ||
} else { | ||
value = types(pq.ftype(j))(rawValue); | ||
} | ||
row[pq.fname(j)] = value; | ||
} | ||
} | ||
return rows; | ||
}; | ||
|
||
var dispatchQuery = function(pq, fn, cb) { | ||
setImmediate(function() { | ||
var sent = fn(); | ||
if(!sent) return cb(new Error(pq.errorMessage())); | ||
cb(); | ||
}); | ||
}; | ||
|
||
var consumeResults = function(pq, cb) { | ||
var cleanup = function() { | ||
pq.removeListener('readable', onReadable); | ||
pq.stopReader(); | ||
} | ||
|
||
var readError = function(message) { | ||
cleanup(); | ||
return cb(new Error(message || pq.errorMessage)); | ||
}; | ||
|
||
var onReadable = function() { | ||
//read waiting data from the socket | ||
//e.g. clear the pending 'select' | ||
if(!pq.consumeInput()) { | ||
return readError(); | ||
} | ||
//check if there is still outstanding data | ||
//if so, wait for it all to come in | ||
if(pq.isBusy()) { | ||
return; | ||
} | ||
//load our result object | ||
pq.getResult(); | ||
|
||
//"read until results return null" | ||
//or in our case ensure we only have one result | ||
if(pq.getResult()) { | ||
return readError('Only one result at a time is accepted'); | ||
} | ||
cleanup(); | ||
return cb(null); | ||
}; | ||
pq.on('readable', onReadable); | ||
pq.startReader(); | ||
}; | ||
|
||
Client.prototype.query = function(text, values, cb) { | ||
var queryFn; | ||
var pq = this.pq | ||
var types = this.types | ||
if(typeof values == 'function') { | ||
cb = values; | ||
queryFn = pq.sendQuery.bind(pq, text); | ||
} else { | ||
queryFn = pq.sendQueryParams.bind(pq, text, values); | ||
} | ||
|
||
dispatchQuery(pq, queryFn, function(err) { | ||
if(err) return cb(err); | ||
consumeResults(pq, function(err) { | ||
return cb(err, err ? null : mapResults(pq, types)); | ||
}); | ||
}); | ||
}; | ||
|
||
Client.prototype.querySync = function(text, values) { | ||
var queryFn; | ||
var pq = this.pq; | ||
pq[values ? 'execParams' : 'exec'].call(pq, text, values); | ||
var success = !pq.errorMessage(); | ||
if(!success) { | ||
throw new Error(pq.resultErrorMessage()); | ||
} | ||
return mapResults(pq, this.types); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"name": "pg-native", | ||
"version": "0.0.0", | ||
"description": "A slightly nicer interface to Postgres over node-libpq", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "mocha" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/brianc/node-pg-native.git" | ||
}, | ||
"keywords": [ | ||
"postgres", | ||
"pg", | ||
"libpq" | ||
], | ||
"author": "Brian M. Carlson", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/brianc/node-pg-native/issues" | ||
}, | ||
"homepage": "https://github.com/brianc/node-pg-native", | ||
"dependencies": { | ||
"libpq": "^0.2.0", | ||
"pg-types": "^1.4.0" | ||
}, | ||
"devDependencies": { | ||
"mocha": "^1.21.4", | ||
"async": "^0.9.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
var Client = require('../') | ||
var assert = require('assert') | ||
var async = require('async') | ||
|
||
describe('connection', function() { | ||
it('works', function(done) { | ||
Client().connect(done); | ||
}); | ||
|
||
it('connects with args', function(done) { | ||
Client().connect('host=localhost', done); | ||
}); | ||
|
||
it('errors out with bad connection args', function(done) { | ||
Client().connect('host=asldkfjasdf', function(err) { | ||
assert(err, 'should raise an error for bad host'); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('connectSync', function() { | ||
it('works without args', function() { | ||
Client().connectSync(); | ||
}); | ||
|
||
it('works with args', function() { | ||
Client().connectSync('host=localhost'); | ||
}); | ||
|
||
it('throws if bad host', function() { | ||
assert.throws(function() { | ||
Client().connectSync('host=laksdjfdsf'); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('async query', function() { | ||
before(function(done) { | ||
this.client = Client(); | ||
this.client.connect(function(err) { | ||
if(err) return done(err); | ||
return done(); | ||
}); | ||
}); | ||
|
||
after(function(done) { | ||
this.client.end(done); | ||
}); | ||
|
||
it('simple query works', function(done) { | ||
var runQuery = function(n, done) { | ||
this.client.query('SELECT NOW() AS the_time', function(err, rows) { | ||
if(err) return done(err); | ||
assert.equal(rows[0].the_time.getFullYear(), new Date().getFullYear()); | ||
return done(); | ||
}); | ||
}.bind(this); | ||
async.timesSeries(3, runQuery, done) | ||
}); | ||
|
||
it('parameters work', function(done) { | ||
var runQuery = function(n, done) { | ||
this.client.query('SELECT $1::text AS name', ['Brian'], done); | ||
}.bind(this); | ||
async.timesSeries(3, runQuery, done) | ||
}); | ||
|
||
it('prepared, named statements work'); | ||
}); | ||
|
||
describe('query sync', function(done) { | ||
before(function() { | ||
this.client = Client(); | ||
this.client.connectSync(); | ||
}); | ||
|
||
after(function(done) { | ||
this.client.end(done); | ||
}); | ||
|
||
it('simple query works', function() { | ||
var rows = this.client.querySync('SELECT NOW() AS the_time'); | ||
assert.equal(rows.length, 1); | ||
assert.equal(rows[0].the_time.getFullYear(), new Date().getFullYear()); | ||
}); | ||
|
||
it('parameterized query works', function() { | ||
var rows = this.client.querySync('SELECT $1::text AS name', ['Brian']); | ||
assert.equal(rows.length, 1); | ||
assert.equal(rows[0].name, 'Brian'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
--bail | ||
--no-exit |