Fix native constructor and pool exports (#1061)
This commit is contained in:
parent
e2830ac847
commit
812277f99f
126
README.md
126
README.md
@ -3,7 +3,7 @@
|
|||||||
[![Build Status](https://secure.travis-ci.org/brianc/node-postgres.svg?branch=master)](http://travis-ci.org/brianc/node-postgres)
|
[![Build Status](https://secure.travis-ci.org/brianc/node-postgres.svg?branch=master)](http://travis-ci.org/brianc/node-postgres)
|
||||||
[![Dependency Status](https://david-dm.org/brianc/node-postgres.svg)](https://david-dm.org/brianc/node-postgres)
|
[![Dependency Status](https://david-dm.org/brianc/node-postgres.svg)](https://david-dm.org/brianc/node-postgres)
|
||||||
|
|
||||||
PostgreSQL client for node.js. Pure JavaScript and optional native libpq bindings.
|
Non-blocking PostgreSQL client for node.js. Pure JavaScript and optional native libpq bindings.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
@ -11,28 +11,69 @@ PostgreSQL client for node.js. Pure JavaScript and optional native libpq bindin
|
|||||||
$ npm install pg
|
$ npm install pg
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Intro & Examples
|
||||||
|
|
||||||
## Examples
|
### Simple example
|
||||||
|
|
||||||
|
```js
|
||||||
|
var pg = require('pg');
|
||||||
|
|
||||||
|
// instantiate a new client
|
||||||
|
// the client will read connection information from
|
||||||
|
// the same environment varaibles used by postgres cli tools
|
||||||
|
var client = new pg.Client();
|
||||||
|
|
||||||
|
// connect to our PostgreSQL server instance
|
||||||
|
client.connect(function (err) {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
// execute a query on our database
|
||||||
|
client.query('SELECT $1::text as name', ['brianc'], function (err, result) {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
// just print the result to the console
|
||||||
|
console.log(result.rows[0]); // outputs: { name: 'brianc' }
|
||||||
|
|
||||||
|
// disconnect the client
|
||||||
|
client.end(function (err) {
|
||||||
|
if (err) throw err;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
### Client pooling
|
### Client pooling
|
||||||
|
|
||||||
Generally you will access the PostgreSQL server through a pool of clients. A client takes a non-trivial amount of time to establish a new connection. A client also consumes a non-trivial amount of resources on the PostgreSQL server - not something you want to do on every http request. Good news: node-postgres ships with built in client pooling.
|
If you're working on something like a web application which makes frequent queries you'll want to access the PostgreSQL server through a pool of clients. Why? There is ~20-30 millisecond delay (YMMV) when connecting a new client to the PostgreSQL server because of the startup handshake. Also, PostgreSQL can only support a limited number of clients...it depends on the amount of ram on your database server, but generally more than 100 clients at a time is a bad thing. :tm: Finally
|
||||||
|
PostgreSQL can only execute 1 query at a time per connected client.
|
||||||
|
|
||||||
|
With that in mind we can imagine a situtation where you have a web server which connects and disconnects a new client for every web request or every query (don't do this!). If you get only 1 request at a time everything will seem to work fine, though it will be a touch slower due to the connection overhead. Once you get >500 simultaneous requests your web server will attempt to open 500 connections to the PostgreSQL backend and :boom: you'll run out of memory on the PostgreSQL server, it will become
|
||||||
|
unresponsive, your app will seem to hang, and everything will break. Boooo!
|
||||||
|
|
||||||
|
__Good news__: node-postgres ships with built in client pooling.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var Pool = require('pg').Pool;
|
var pg = require('pg');
|
||||||
|
|
||||||
|
// create a config to configure both pooling behavior
|
||||||
|
// and client options
|
||||||
|
// note: all config is optional and the environment variables
|
||||||
|
// will be read if the config is not present
|
||||||
var config = {
|
var config = {
|
||||||
user: 'foo',
|
user: 'foo', //env var: PGUSER
|
||||||
password: 'secret',
|
database: 'my_db', //env var: PGDATABASE
|
||||||
database: 'my_db',
|
password: 'secret', //env var: PGPASSWORD
|
||||||
port: 5432
|
port: 5432, //env var: PGPORT
|
||||||
|
max: 10, // max number of clients in the pool
|
||||||
|
idleTimeoutMillis: 30000, // how long a client is allowed to remain idle before being closed
|
||||||
};
|
};
|
||||||
|
|
||||||
var pool = new Pool(config);
|
var pool = new pg.Pool(config);
|
||||||
|
|
||||||
//this initializes a connection pool
|
//this initializes a connection pool
|
||||||
//it will keep idle connections open for a (configurable) 30 seconds
|
//it will keep idle connections open for a 30 seconds
|
||||||
//and set a limit of 10 (also configurable)
|
//and set a limit of maximum 10 idle clients
|
||||||
pool.connect(function(err, client, done) {
|
pool.connect(function(err, client, done) {
|
||||||
if(err) {
|
if(err) {
|
||||||
return console.error('error fetching client from pool', err);
|
return console.error('error fetching client from pool', err);
|
||||||
@ -50,38 +91,13 @@ pool.connect(function(err, client, done) {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
node-postgres uses [pg-pool](https://github.com/brianc/node-pg-pool.git) to manage pooling and only provides a very thin layer on top.
|
node-postgres uses [pg-pool](https://github.com/brianc/node-pg-pool.git) to manage pooling and includes it and exports it for convienience. If you want, you can `require('pg-pool')` and use it directly - its the same as the constructor exported at `pg.Pool`.
|
||||||
|
|
||||||
It's _highly recommend_ you read the documentation for [pg-pool](https://github.com/brianc/node-pg-pool.git)
|
It's __highly recommend__ you read the documentation for [pg-pool](https://github.com/brianc/node-pg-pool.git).
|
||||||
|
|
||||||
|
|
||||||
[Here is a tl;dr get up & running quickly example](https://github.com/brianc/node-postgres/wiki/Example)
|
[Here is an up & running quickly example](https://github.com/brianc/node-postgres/wiki/Example)
|
||||||
|
|
||||||
### Client instance
|
|
||||||
|
|
||||||
Sometimes you may not want to use a pool of connections. You can easily connect a single client to a postgres instance, run some queries, and disconnect.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var pg = require('pg');
|
|
||||||
|
|
||||||
var conString = "postgres://username:password@localhost/database";
|
|
||||||
|
|
||||||
var client = new pg.Client(conString);
|
|
||||||
client.connect(function(err) {
|
|
||||||
if(err) {
|
|
||||||
return console.error('could not connect to postgres', err);
|
|
||||||
}
|
|
||||||
client.query('SELECT NOW() AS "theTime"', function(err, result) {
|
|
||||||
if(err) {
|
|
||||||
return console.error('error running query', err);
|
|
||||||
}
|
|
||||||
console.log(result.rows[0].theTime);
|
|
||||||
//output: Tue Jan 15 2013 19:12:47 GMT-600 (CST)
|
|
||||||
client.end();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## [More Documentation](https://github.com/brianc/node-postgres/wiki)
|
## [More Documentation](https://github.com/brianc/node-postgres/wiki)
|
||||||
|
|
||||||
@ -94,16 +110,26 @@ $ npm install pg pg-native
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
node-postgres contains a pure JavaScript protocol implementation which is quite fast, but you can optionally use native bindings for a 20-30% increase in parsing speed. Both versions are adequate for production workloads.
|
node-postgres contains a pure JavaScript protocol implementation which is quite fast, but you can optionally use [native](https://github.com/brianc/node-pg-native) [bindings](https://github.com/brianc/node-libpq) for a 20-30% increase in parsing speed (YMMV). Both versions are adequate for production workloads. I personally use the pure JavaScript implementation because I like knowing whats going on all the way down to the binary on the socket, and it allows for some fancier [use](https://github.com/brianc/node-pg-cursor) [cases](https://github.com/brianc/node-pg-query-stream) which are difficult to do with libpq. :smile:
|
||||||
|
|
||||||
To use the native bindings, first install [pg-native](https://github.com/brianc/node-pg-native.git). Once pg-native is installed, simply replace `require('pg')` with `require('pg').native`.
|
To use the native bindings, first install [pg-native](https://github.com/brianc/node-pg-native.git). Once pg-native is installed, simply replace `var pg = require('pg')` with `var pg = require('pg').native`. Make sure any exported constructors from `pg` are from the native instance. Example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var pg = require('pg').native
|
||||||
|
var Pool = require('pg').Pool // bad! this is not bound to the native client
|
||||||
|
var Client = require('pg').Client // bad! this is the pure JavaScript client
|
||||||
|
|
||||||
|
var pg = require('pg').native
|
||||||
|
var Pool = pg.Pool // good! a pool bound to the native client
|
||||||
|
var Client = pg.Client // good! this client uses libpq bindings
|
||||||
|
```
|
||||||
|
|
||||||
node-postgres abstracts over the pg-native module to provide exactly the same interface as the pure JavaScript version. Care has been taken to keep the number of api differences between the two modules to a minimum; however, it is recommend you use either the pure JavaScript or native bindings in both development and production and don't mix & match them in the same process - it can get confusing!
|
node-postgres abstracts over the pg-native module to provide exactly the same interface as the pure JavaScript version. Care has been taken to keep the number of api differences between the two modules to a minimum; however, it is recommend you use either the pure JavaScript or native bindings in both development and production and don't mix & match them in the same process - it can get confusing!
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* pure JavaScript client and native libpq bindings share _the same api_
|
* pure JavaScript client and native libpq bindings share _the same api_
|
||||||
* optional connection pooling
|
* connection pooling
|
||||||
* extensible js<->postgresql data-type coercion
|
* extensible js<->postgresql data-type coercion
|
||||||
* supported PostgreSQL features
|
* supported PostgreSQL features
|
||||||
* parameterized queries
|
* parameterized queries
|
||||||
@ -111,9 +137,14 @@ node-postgres abstracts over the pg-native module to provide exactly the same in
|
|||||||
* async notifications with `LISTEN/NOTIFY`
|
* async notifications with `LISTEN/NOTIFY`
|
||||||
* bulk import & export with `COPY TO/COPY FROM`
|
* bulk import & export with `COPY TO/COPY FROM`
|
||||||
|
|
||||||
|
## Extras
|
||||||
|
|
||||||
|
node-postgres is by design pretty light on abstractions. These are some handy modules we've been using over the years to complete the picture.
|
||||||
|
Entire list can be found on [wiki](https://github.com/brianc/node-postgres/wiki/Extras)
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
__We love contributions!__
|
__:heart: contributions!__
|
||||||
|
|
||||||
If you need help getting the tests running locally or have any questions about the code when working on a patch please feel free to email me or gchat me.
|
If you need help getting the tests running locally or have any questions about the code when working on a patch please feel free to email me or gchat me.
|
||||||
|
|
||||||
@ -135,17 +166,14 @@ If at all possible when you open an issue please provide
|
|||||||
|
|
||||||
Usually I'll pop the code into the repo as a test. Hopefully the test fails. Then I make the test pass. Then everyone's happy!
|
Usually I'll pop the code into the repo as a test. Hopefully the test fails. Then I make the test pass. Then everyone's happy!
|
||||||
|
|
||||||
If you need help or run into _any_ issues getting node-postgres to work on your system please report a bug or contact me directly. I am usually available via google-talk at my github account public email address.
|
If you need help or run into _any_ issues getting node-postgres to work on your system please report a bug or contact me directly. I am usually available via google-talk at my github account public email address. Remember this is a labor of love, and though I try to get back to everything sometimes life takes priority, and I might take a while. It helps if you use nice code formatting in your issue, search for existing answers before posting, and come back and close out the issue if you figure out a solution. The easier you can make it for me, the quicker I'll try and respond to you!
|
||||||
|
|
||||||
|
If you need deeper support, have application specific questions, would like to sponsor development, or want consulting around node & postgres please send me an email, I'm always happy to discuss!
|
||||||
|
|
||||||
I usually tweet about any important status updates or changes to node-postgres on twitter.
|
I usually tweet about any important status updates or changes to node-postgres on twitter.
|
||||||
Follow me [@briancarlson](https://twitter.com/briancarlson) to keep up to date.
|
Follow me [@briancarlson](https://twitter.com/briancarlson) to keep up to date.
|
||||||
|
|
||||||
|
|
||||||
## Extras
|
|
||||||
|
|
||||||
node-postgres is by design pretty light on abstractions. These are some handy modules we've been using over the years to complete the picture.
|
|
||||||
Entire list can be found on [wiki](https://github.com/brianc/node-postgres/wiki/Extras)
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Copyright (c) 2010-2016 Brian Carlson (brian.m.carlson@gmail.com)
|
Copyright (c) 2010-2016 Brian Carlson (brian.m.carlson@gmail.com)
|
||||||
|
@ -4,14 +4,14 @@ var Client = require('./client');
|
|||||||
var defaults = require('./defaults');
|
var defaults = require('./defaults');
|
||||||
var Connection = require('./connection');
|
var Connection = require('./connection');
|
||||||
var ConnectionParameters = require('./connection-parameters');
|
var ConnectionParameters = require('./connection-parameters');
|
||||||
var Pool = require('pg-pool');
|
var poolFactory = require('./pool-factory');
|
||||||
|
|
||||||
var PG = function(clientConstructor) {
|
var PG = function(clientConstructor) {
|
||||||
EventEmitter.call(this);
|
EventEmitter.call(this);
|
||||||
this.defaults = defaults;
|
this.defaults = defaults;
|
||||||
this.Client = clientConstructor;
|
this.Client = clientConstructor;
|
||||||
this.Query = this.Client.Query;
|
this.Query = this.Client.Query;
|
||||||
this.Pool = Pool;
|
this.Pool = poolFactory(this.Client);
|
||||||
this._pools = [];
|
this._pools = [];
|
||||||
this.Connection = Connection;
|
this.Connection = Connection;
|
||||||
this.types = require('pg-types');
|
this.types = require('pg-types');
|
||||||
@ -58,7 +58,7 @@ PG.prototype.connect = function(config, callback) {
|
|||||||
config.idleTimeoutMillis = config.idleTimeoutMillis || config.poolIdleTimeout || defaults.poolIdleTimeout;
|
config.idleTimeoutMillis = config.idleTimeoutMillis || config.poolIdleTimeout || defaults.poolIdleTimeout;
|
||||||
config.log = config.log || config.poolLog || defaults.poolLog;
|
config.log = config.log || config.poolLog || defaults.poolLog;
|
||||||
|
|
||||||
this._pools[poolName] = this._pools[poolName] || new Pool(config, this.Client);
|
this._pools[poolName] = this._pools[poolName] || new this.Pool(config);
|
||||||
var pool = this._pools[poolName];
|
var pool = this._pools[poolName];
|
||||||
pool.connect(callback);
|
pool.connect(callback);
|
||||||
if(!pool.listeners('error').length) {
|
if(!pool.listeners('error').length) {
|
||||||
@ -69,7 +69,7 @@ PG.prototype.connect = function(config, callback) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// cancel the query runned by the given client
|
// cancel the query running on the given client
|
||||||
PG.prototype.cancel = function(config, client, query) {
|
PG.prototype.cancel = function(config, client, query) {
|
||||||
if(client.native) {
|
if(client.native) {
|
||||||
return client.cancel(query);
|
return client.cancel(query);
|
||||||
|
18
lib/pool-factory.js
Normal file
18
lib/pool-factory.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
var Client = require('./client');
|
||||||
|
var util = require('util');
|
||||||
|
var Pool = require('pg-pool');
|
||||||
|
|
||||||
|
module.exports = function(Client) {
|
||||||
|
|
||||||
|
var BoundPool = function(options) {
|
||||||
|
var config = { Client: Client };
|
||||||
|
for (var key in options) {
|
||||||
|
config[key] = options[key];
|
||||||
|
}
|
||||||
|
Pool.call(this, config);
|
||||||
|
};
|
||||||
|
|
||||||
|
util.inherits(BoundPool, Pool);
|
||||||
|
|
||||||
|
return BoundPool;
|
||||||
|
};
|
@ -21,6 +21,12 @@ test('api', function() {
|
|||||||
pg.connect(helper.config, assert.calls(function(err, client, done) {
|
pg.connect(helper.config, assert.calls(function(err, client, done) {
|
||||||
assert.equal(err, null, "Failed to connect: " + helper.sys.inspect(err));
|
assert.equal(err, null, "Failed to connect: " + helper.sys.inspect(err));
|
||||||
|
|
||||||
|
if (helper.args.native) {
|
||||||
|
assert(client.native)
|
||||||
|
} else {
|
||||||
|
assert(!client.native)
|
||||||
|
}
|
||||||
|
|
||||||
client.query('CREATE TEMP TABLE band(name varchar(100))');
|
client.query('CREATE TEMP TABLE band(name varchar(100))');
|
||||||
|
|
||||||
['the flaming lips', 'wolf parade', 'radiohead', 'bright eyes', 'the beach boys', 'dead black hearts'].forEach(function(bandName) {
|
['the flaming lips', 'wolf parade', 'radiohead', 'bright eyes', 'the beach boys', 'dead black hearts'].forEach(function(bandName) {
|
||||||
|
@ -25,4 +25,4 @@ test('connection with config ssl = true', function() {
|
|||||||
pg.end();
|
pg.end();
|
||||||
}))
|
}))
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
var helper = require(__dirname + "/../test-helper");
|
var helper = require(__dirname + "/../test-helper");
|
||||||
var pg = require(__dirname + "/../../../lib");
|
var pg = require(__dirname + "/../../../lib");
|
||||||
pg = pg;
|
|
||||||
|
|
||||||
//first make pool hold 2 clients
|
//first make pool hold 2 clients
|
||||||
pg.defaults.poolSize = 2;
|
pg.defaults.poolSize = 2;
|
||||||
|
15
test/integration/connection-pool/native-instance-tests.js
Normal file
15
test/integration/connection-pool/native-instance-tests.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
var helper = require(__dirname + "/../test-helper")
|
||||||
|
var pg = helper.pg
|
||||||
|
var native = helper.args.native
|
||||||
|
|
||||||
|
var pool = new pg.Pool()
|
||||||
|
|
||||||
|
pool.connect(assert.calls(function(err, client, done) {
|
||||||
|
if (native) {
|
||||||
|
assert(client.native)
|
||||||
|
} else {
|
||||||
|
assert(!client.native)
|
||||||
|
}
|
||||||
|
done()
|
||||||
|
pool.end()
|
||||||
|
}))
|
Loading…
Reference in New Issue
Block a user