Merge pull request #1369 from brianc/7.0

7.0
This commit is contained in:
Brian C 2017-07-17 21:53:03 -05:00 committed by GitHub
commit 8cc7308835
126 changed files with 5965 additions and 6226 deletions

6
.eslintrc Normal file
View File

@ -0,0 +1,6 @@
{
"extends": "standard",
"rules": {
"no-new-func": "off"
}
}

View File

@ -1,5 +0,0 @@
{
"trailing": true,
"indent": 2,
"evil": true
}

View File

@ -6,39 +6,30 @@ before_script:
env:
- CC=clang CXX=clang++ npm_config_clang=1 PGUSER=postgres PGDATABASE=postgres
node_js: "6"
addons:
postgresql: "9.6"
matrix:
include:
- node_js: "0.10"
- node_js: "lts/argon"
addons:
postgresql: "9.6"
env: []
- node_js: "0.12"
addons:
postgresql: "9.6"
env: []
- node_js: "4"
addons:
postgresql: "9.6"
- node_js: "5"
addons:
postgresql: "9.6"
- node_js: "6"
- node_js: "lts/boron"
addons:
postgresql: "9.1"
dist: precise
- node_js: "6"
- node_js: "lts/boron"
addons:
postgresql: "9.2"
- node_js: "6"
- node_js: "lts/boron"
addons:
postgresql: "9.3"
- node_js: "6"
- node_js: "lts/boron"
addons:
postgresql: "9.4"
- node_js: "6"
- node_js: "lts/boron"
addons:
postgresql: "9.5"
- node_js: "lts/boron"
addons:
postgresql: "9.6"
- node_js: "8"
addons:
postgresql: "9.6"

View File

@ -4,16 +4,6 @@ For richer information consult the commit log on github with referenced pull req
We do not include break-fix version release in this file.
### v6.4.0
- Add support for passing `client_encoding` as a connection parameter. Used when decoding strings in the JavaScript driver. The default is still `utf8`.
### v6.3.0
- Deprecate `pg.connect` `pg.end` and `pg.cancel` - favor using `new pg.Pool()` instead of pg singleton.
- Deprecate undocumented but possibly used `query.promise()` method. Use the promise returned directly from `client.query` / `pool.query`.
- Deprecate returning an automatically created query result from `client.query`. Instead return more idomatic responses for callback/promise methods.
### v6.2.0
- Add support for [parsing `replicationStart` messages](https://github.com/brianc/node-postgres/pull/1271/files).

View File

@ -7,7 +7,7 @@ params := $(connectionString)
node-command := xargs -n 1 -I file node file $(params)
.PHONY : test test-connection test-integration bench test-native \
jshint publish test-missing-native update-npm
lint publish test-missing-native update-npm
all:
npm install
@ -17,7 +17,7 @@ help:
test: test-unit
test-all: jshint test-missing-native test-unit test-integration test-native test-binary
test-all: lint test-missing-native test-unit test-integration test-native
update-npm:
@ -36,8 +36,10 @@ test-connection:
test-missing-native:
@echo "***Testing optional native install***"
@rm -rf node_modules/pg-native
@rm -rf node_modules/libpq
@node test/native/missing-native.js
@rm -rf node_modules/pg-native
@rm -rf node_modules/libpq
node_modules/pg-native/index.js:
@npm i pg-native
@ -58,6 +60,6 @@ test-binary: test-connection
test-pool:
@find test/integration/connection-pool -name "*.js" | $(node-command) binary
jshint:
@echo "***Starting jshint***"
@./node_modules/.bin/jshint lib
lint:
@echo "***Starting lint***"
eslint lib

View File

@ -1,3 +1,4 @@
'use strict'
/**
* Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
* All rights reserved.
@ -6,381 +7,413 @@
* README.md file in the root directory of this source tree.
*/
var crypto = require('crypto');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var pgPass = require('pgpass');
var TypeOverrides = require('./type-overrides');
var EventEmitter = require('events').EventEmitter
var util = require('util')
var utils = require('./utils')
var pgPass = require('pgpass')
var TypeOverrides = require('./type-overrides')
var ConnectionParameters = require('./connection-parameters');
var utils = require('./utils');
var Query = require('./query');
var defaults = require('./defaults');
var Connection = require('./connection');
var ConnectionParameters = require('./connection-parameters')
var Query = require('./query')
var defaults = require('./defaults')
var Connection = require('./connection')
var Client = function(config) {
EventEmitter.call(this);
var Client = function (config) {
EventEmitter.call(this)
this.connectionParameters = new ConnectionParameters(config);
this.user = this.connectionParameters.user;
this.database = this.connectionParameters.database;
this.port = this.connectionParameters.port;
this.host = this.connectionParameters.host;
this.password = this.connectionParameters.password;
this.replication = this.connectionParameters.replication;
this.connectionParameters = new ConnectionParameters(config)
this.user = this.connectionParameters.user
this.database = this.connectionParameters.database
this.port = this.connectionParameters.port
this.host = this.connectionParameters.host
this.password = this.connectionParameters.password
this.replication = this.connectionParameters.replication
var c = config || {};
var c = config || {}
this._types = new TypeOverrides(c.types);
this._ending = false;
this._connecting = false;
this._connectionError = false;
this._types = new TypeOverrides(c.types)
this._ending = false
this._connecting = false
this._connected = false
this._connectionError = false
this.connection = c.connection || new Connection({
stream: c.stream,
ssl: this.connectionParameters.ssl,
keepAlive: c.keepAlive || false,
client_encoding: this.connectionParameters.client_encoding || 'utf8',
});
this.queryQueue = [];
this.binary = c.binary || defaults.binary;
this.encoding = this.connectionParameters.client_encoding || 'utf8';
this.processID = null;
this.secretKey = null;
this.ssl = this.connectionParameters.ssl || false;
};
encoding: this.connectionParameters.client_encoding || 'utf8'
})
this.queryQueue = []
this.binary = c.binary || defaults.binary
this.processID = null
this.secretKey = null
this.ssl = this.connectionParameters.ssl || false
}
util.inherits(Client, EventEmitter);
util.inherits(Client, EventEmitter)
Client.prototype.connect = function(callback) {
var self = this;
var con = this.connection;
this._connecting = true;
Client.prototype.connect = function (callback) {
var self = this
var con = this.connection
if (this._connecting || this._connected) {
const err = new Error('Client has already been connected. You cannot reuse a client.')
if (callback) {
callback(err)
return undefined
}
return Promise.reject(err)
}
this._connecting = true
if(this.host && this.host.indexOf('/') === 0) {
con.connect(this.host + '/.s.PGSQL.' + this.port);
if (this.host && this.host.indexOf('/') === 0) {
con.connect(this.host + '/.s.PGSQL.' + this.port)
} else {
con.connect(this.port, this.host);
con.connect(this.port, this.host)
}
//once connection is established send startup message
con.on('connect', function() {
if(self.ssl) {
con.requestSsl();
// once connection is established send startup message
con.on('connect', function () {
if (self.ssl) {
con.requestSsl()
} else {
con.startup(self.getStartupConf());
con.startup(self.getStartupConf())
}
});
})
con.on('sslconnect', function() {
con.startup(self.getStartupConf());
});
con.on('sslconnect', function () {
con.startup(self.getStartupConf())
})
function checkPgPass(cb) {
return function(msg) {
if (null !== self.password) {
cb(msg);
function checkPgPass (cb) {
return function (msg) {
if (self.password !== null) {
cb(msg)
} else {
pgPass(self.connectionParameters, function(pass){
pgPass(self.connectionParameters, function (pass) {
if (undefined !== pass) {
self.connectionParameters.password = self.password = pass;
self.connectionParameters.password = self.password = pass
}
cb(msg);
});
cb(msg)
})
}
};
}
}
//password request handling
con.on('authenticationCleartextPassword', checkPgPass(function() {
con.password(self.password);
}));
// password request handling
con.on('authenticationCleartextPassword', checkPgPass(function () {
con.password(self.password)
}))
//password request handling
con.on('authenticationMD5Password', checkPgPass(function(msg) {
var inner = Client.md5(self.password + self.user);
var outer = Client.md5(Buffer.concat([new Buffer(inner), msg.salt]));
var md5password = "md5" + outer;
con.password(md5password);
}));
// password request handling
con.on('authenticationMD5Password', checkPgPass(function (msg) {
var inner = utils.md5(self.password + self.user)
var outer = utils.md5(Buffer.concat([Buffer.from(inner), msg.salt]))
var md5password = 'md5' + outer
con.password(md5password)
}))
con.once('backendKeyData', function(msg) {
self.processID = msg.processID;
self.secretKey = msg.secretKey;
});
con.once('backendKeyData', function (msg) {
self.processID = msg.processID
self.secretKey = msg.secretKey
})
//hook up query handling events to connection
//after the connection initially becomes ready for queries
con.once('readyForQuery', function() {
self._connecting = false;
//delegate rowDescription to active query
con.on('rowDescription', function(msg) {
self.activeQuery.handleRowDescription(msg);
});
//delegate dataRow to active query
con.on('dataRow', function(msg) {
self.activeQuery.handleDataRow(msg);
});
//delegate portalSuspended to active query
con.on('portalSuspended', function(msg) {
self.activeQuery.handlePortalSuspended(con);
});
//deletagate emptyQuery to active query
con.on('emptyQuery', function(msg) {
self.activeQuery.handleEmptyQuery(con);
});
//delegate commandComplete to active query
con.on('commandComplete', function(msg) {
self.activeQuery.handleCommandComplete(msg, con);
});
//if a prepared statement has a name and properly parses
//we track that its already been executed so we don't parse
//it again on the same client
con.on('parseComplete', function(msg) {
if(self.activeQuery.name) {
con.parsedStatements[self.activeQuery.name] = true;
}
});
con.on('copyInResponse', function(msg) {
self.activeQuery.handleCopyInResponse(self.connection);
});
con.on('copyData', function (msg) {
self.activeQuery.handleCopyData(msg, self.connection);
});
con.on('notification', function(msg) {
self.emit('notification', msg);
});
//process possible callback argument to Client#connect
const connectingErrorHandler = (err) => {
if (this._connectionError) {
return
}
this._connectionError = true
if (callback) {
callback(null, self);
//remove callback for proper error handling
//after the connect event
callback = null;
return callback(err)
}
self.emit('connect');
});
this.emit('error', err)
}
con.on('readyForQuery', function() {
var activeQuery = self.activeQuery;
self.activeQuery = null;
self.readyForQuery = true;
self._pulseQueryQueue();
if(activeQuery) {
activeQuery.handleReadyForQuery(con);
const connectedErrorHandler = (err) => {
if (this.activeQuery) {
var activeQuery = self.activeQuery
this.activeQuery = null
return activeQuery.handleError(err, con)
}
});
this.emit('error', err)
}
con.on('error', function(error) {
if(this.activeQuery) {
var activeQuery = self.activeQuery;
this.activeQuery = null;
return activeQuery.handleError(error, con);
}
con.on('error', connectingErrorHandler)
if (this._connecting) {
// set a flag indicating we've seen an error during connection
// the backend will terminate the connection and we don't want
// to throw a second error when the connection is terminated
this._connectionError = true;
}
// hook up query handling events to connection
// after the connection initially becomes ready for queries
con.once('readyForQuery', function () {
self._connecting = false
self._connected = true
self._attachListeners(con)
con.removeListener('error', connectingErrorHandler)
con.on('error', connectedErrorHandler)
if(!callback) {
return this.emit('error', error);
}
con.end(); // make sure ECONNRESET errors don't cause error events
callback(error);
callback = null;
}.bind(this));
con.once('end', function() {
// process possible callback argument to Client#connect
if (callback) {
// haven't received a connection message yet!
var err = new Error('Connection terminated');
callback(err);
callback = null;
return;
callback(null, self)
// remove callback for proper error handling
// after the connect event
callback = null
}
if(this.activeQuery) {
var disconnectError = new Error('Connection terminated');
this.activeQuery.handleError(disconnectError, con);
this.activeQuery = null;
self.emit('connect')
})
con.on('readyForQuery', function () {
var activeQuery = self.activeQuery
self.activeQuery = null
self.readyForQuery = true
if (activeQuery) {
activeQuery.handleReadyForQuery(con)
}
self._pulseQueryQueue()
})
con.once('end', () => {
if (this.activeQuery) {
var disconnectError = new Error('Connection terminated')
this.activeQuery.handleError(disconnectError, con)
this.activeQuery = null
}
if (!this._ending) {
// if the connection is ended without us calling .end()
// on this client then we have an unexpected disconnection
// treat this as an error unless we've already emitted an error
// during connection.
if (!this._connectionError) {
this.emit('error', new Error('Connection terminated unexpectedly'));
const error = new Error('Connection terminated unexpectedly')
if (this._connecting && !this._connectionError) {
if (callback) {
callback(error)
} else {
this.emit('error', error)
}
} else if (!this._connectionError) {
this.emit('error', error)
}
}
this.emit('end');
}.bind(this));
this.emit('end')
})
con.on('notice', function (msg) {
self.emit('notice', msg)
})
con.on('notice', function(msg) {
self.emit('notice', msg);
});
if (!callback) {
return new global.Promise((resolve, reject) => {
this.once('error', reject)
this.once('connect', () => {
this.removeListener('error', reject)
resolve()
})
})
}
}
};
Client.prototype._attachListeners = function (con) {
const self = this
// delegate rowDescription to active query
con.on('rowDescription', function (msg) {
self.activeQuery.handleRowDescription(msg)
})
Client.prototype.getStartupConf = function() {
var params = this.connectionParameters;
// delegate dataRow to active query
con.on('dataRow', function (msg) {
self.activeQuery.handleDataRow(msg)
})
// delegate portalSuspended to active query
con.on('portalSuspended', function (msg) {
self.activeQuery.handlePortalSuspended(con)
})
// deletagate emptyQuery to active query
con.on('emptyQuery', function (msg) {
self.activeQuery.handleEmptyQuery(con)
})
// delegate commandComplete to active query
con.on('commandComplete', function (msg) {
self.activeQuery.handleCommandComplete(msg, con)
})
// if a prepared statement has a name and properly parses
// we track that its already been executed so we don't parse
// it again on the same client
con.on('parseComplete', function (msg) {
if (self.activeQuery.name) {
con.parsedStatements[self.activeQuery.name] = true
}
})
con.on('copyInResponse', function (msg) {
self.activeQuery.handleCopyInResponse(self.connection)
})
con.on('copyData', function (msg) {
self.activeQuery.handleCopyData(msg, self.connection)
})
con.on('notification', function (msg) {
self.emit('notification', msg)
})
}
Client.prototype.getStartupConf = function () {
var params = this.connectionParameters
var data = {
user: params.user,
database: params.database
};
}
var appName = params.application_name || params.fallback_application_name;
var appName = params.application_name || params.fallback_application_name
if (appName) {
data.application_name = appName;
data.application_name = appName
}
if (params.replication) {
data.replication = '' + params.replication;
data.replication = '' + params.replication
}
return data;
};
return data
}
Client.prototype.cancel = function(client, query) {
if(client.activeQuery == query) {
var con = this.connection;
Client.prototype.cancel = function (client, query) {
if (client.activeQuery === query) {
var con = this.connection
if(this.host && this.host.indexOf('/') === 0) {
con.connect(this.host + '/.s.PGSQL.' + this.port);
if (this.host && this.host.indexOf('/') === 0) {
con.connect(this.host + '/.s.PGSQL.' + this.port)
} else {
con.connect(this.port, this.host);
con.connect(this.port, this.host)
}
//once connection is established send cancel message
con.on('connect', function() {
con.cancel(client.processID, client.secretKey);
});
} else if(client.queryQueue.indexOf(query) != -1) {
client.queryQueue.splice(client.queryQueue.indexOf(query), 1);
// once connection is established send cancel message
con.on('connect', function () {
con.cancel(client.processID, client.secretKey)
})
} else if (client.queryQueue.indexOf(query) !== -1) {
client.queryQueue.splice(client.queryQueue.indexOf(query), 1)
}
};
}
Client.prototype.setTypeParser = function(oid, format, parseFn) {
return this._types.setTypeParser(oid, format, parseFn);
};
Client.prototype.setTypeParser = function (oid, format, parseFn) {
return this._types.setTypeParser(oid, format, parseFn)
}
Client.prototype.getTypeParser = function(oid, format) {
return this._types.getTypeParser(oid, format);
};
Client.prototype.getTypeParser = function (oid, format) {
return this._types.getTypeParser(oid, format)
}
// Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c
Client.prototype.escapeIdentifier = function(str) {
Client.prototype.escapeIdentifier = function (str) {
var escaped = '"'
var escaped = '"';
for(var i = 0; i < str.length; i++) {
var c = str[i];
if(c === '"') {
escaped += c + c;
for (var i = 0; i < str.length; i++) {
var c = str[i]
if (c === '"') {
escaped += c + c
} else {
escaped += c;
escaped += c
}
}
escaped += '"';
escaped += '"'
return escaped;
};
return escaped
}
// Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c
Client.prototype.escapeLiteral = function(str) {
Client.prototype.escapeLiteral = function (str) {
var hasBackslash = false
var escaped = '\''
var hasBackslash = false;
var escaped = '\'';
for(var i = 0; i < str.length; i++) {
var c = str[i];
if(c === '\'') {
escaped += c + c;
for (var i = 0; i < str.length; i++) {
var c = str[i]
if (c === '\'') {
escaped += c + c
} else if (c === '\\') {
escaped += c + c;
hasBackslash = true;
escaped += c + c
hasBackslash = true
} else {
escaped += c;
escaped += c
}
}
escaped += '\'';
escaped += '\''
if(hasBackslash === true) {
escaped = ' E' + escaped;
if (hasBackslash === true) {
escaped = ' E' + escaped
}
return escaped;
};
return escaped
}
Client.prototype._pulseQueryQueue = function() {
if(this.readyForQuery===true) {
this.activeQuery = this.queryQueue.shift();
if(this.activeQuery) {
this.readyForQuery = false;
this.hasExecuted = true;
this.activeQuery.submit(this.connection);
} else if(this.hasExecuted) {
this.activeQuery = null;
this.emit('drain');
Client.prototype._pulseQueryQueue = function () {
if (this.readyForQuery === true) {
this.activeQuery = this.queryQueue.shift()
if (this.activeQuery) {
this.readyForQuery = false
this.hasExecuted = true
this.activeQuery.submit(this.connection)
} else if (this.hasExecuted) {
this.activeQuery = null
this.emit('drain')
}
}
};
}
Client.prototype.copyFrom = function (text) {
throw new Error("For PostgreSQL COPY TO/COPY FROM support npm install pg-copy-streams");
};
Client.prototype.copyTo = function (text) {
throw new Error("For PostgreSQL COPY TO/COPY FROM support npm install pg-copy-streams");
};
var DeprecatedEmitterQuery = utils.deprecateEventEmitter(Query);
Client.prototype.query = function(config, values, callback) {
//can take in strings, config object or query object
var query = (typeof config.submit == 'function') ? config :
new DeprecatedEmitterQuery(config, values, callback);
if(this.binary && !query.binary) {
query.binary = true;
}
if(query._result) {
query._result._getTypeParser = this._types.getTypeParser.bind(this._types);
Client.prototype.query = function (config, values, callback) {
// can take in strings, config object or query object
var query
var result
if (typeof config.submit === 'function') {
result = query = config
if (typeof values === 'function') {
query.callback = query.callback || values
}
} else {
query = new Query(config, values, callback)
if (!query.callback) {
let resolveOut, rejectOut
result = new Promise((resolve, reject) => {
resolveOut = resolve
rejectOut = reject
})
query.callback = (err, res) => err ? rejectOut(err) : resolveOut(res)
}
}
this.queryQueue.push(query);
this._pulseQueryQueue();
return query;
};
if (this.binary && !query.binary) {
query.binary = true
}
if (query._result) {
query._result._getTypeParser = this._types.getTypeParser.bind(this._types)
}
Client.prototype.end = function(cb) {
this._ending = true;
this.connection.end();
this.queryQueue.push(query)
this._pulseQueryQueue()
return result
}
Client.prototype.end = function (cb) {
this._ending = true
if (this.activeQuery) {
// if we have an active query we need to force a disconnect
// on the socket - otherwise a hung query could block end forever
this.connection.stream.destroy(new Error('Connection terminated by user'))
return
}
if (cb) {
this.connection.once('end', cb);
this.connection.end()
this.connection.once('end', cb)
} else {
return new global.Promise((resolve, reject) => {
this.connection.end()
this.connection.once('end', resolve)
})
}
};
Client.md5 = function(string) {
return crypto.createHash('md5').update(string, 'utf-8').digest('hex');
};
}
// expose a Query constructor
Client.Query = Query;
Client.Query = Query
module.exports = Client;
module.exports = Client

View File

@ -1,3 +1,4 @@
'use strict'
/**
* Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
* All rights reserved.
@ -6,111 +7,110 @@
* README.md file in the root directory of this source tree.
*/
var url = require('url');
var dns = require('dns');
var dns = require('dns')
var defaults = require('./defaults');
var defaults = require('./defaults')
var val = function(key, config, envVar) {
var val = function (key, config, envVar) {
if (envVar === undefined) {
envVar = process.env[ 'PG' + key.toUpperCase() ];
envVar = process.env[ 'PG' + key.toUpperCase() ]
} else if (envVar === false) {
// do nothing ... use false
} else {
envVar = process.env[ envVar ];
envVar = process.env[ envVar ]
}
return config[key] ||
envVar ||
defaults[key];
};
defaults[key]
}
//parses a connection string
var parse = require('pg-connection-string').parse;
// parses a connection string
var parse = require('pg-connection-string').parse
var useSsl = function() {
switch(process.env.PGSSLMODE) {
case "disable":
return false;
case "prefer":
case "require":
case "verify-ca":
case "verify-full":
return true;
var useSsl = function () {
switch (process.env.PGSSLMODE) {
case 'disable':
return false
case 'prefer':
case 'require':
case 'verify-ca':
case 'verify-full':
return true
}
return defaults.ssl;
};
return defaults.ssl
}
var ConnectionParameters = function(config) {
//if a string is passed, it is a raw connection string so we parse it into a config
config = typeof config == 'string' ? parse(config) : (config || {});
//if the config has a connectionString defined, parse IT into the config we use
//this will override other default values with what is stored in connectionString
if(config.connectionString) {
config = parse(config.connectionString);
var ConnectionParameters = function (config) {
// if a string is passed, it is a raw connection string so we parse it into a config
config = typeof config === 'string' ? parse(config) : (config || {})
// if the config has a connectionString defined, parse IT into the config we use
// this will override other default values with what is stored in connectionString
if (config.connectionString) {
config = parse(config.connectionString)
}
this.user = val('user', config);
this.database = val('database', config);
this.port = parseInt(val('port', config), 10);
this.host = val('host', config);
this.password = val('password', config);
this.binary = val('binary', config);
this.ssl = typeof config.ssl === 'undefined' ? useSsl() : config.ssl;
this.client_encoding = val("client_encoding", config);
this.replication = val("replication", config);
//a domain socket begins with '/'
this.isDomainSocket = (!(this.host||'').indexOf('/'));
this.user = val('user', config)
this.database = val('database', config)
this.port = parseInt(val('port', config), 10)
this.host = val('host', config)
this.password = val('password', config)
this.binary = val('binary', config)
this.ssl = typeof config.ssl === 'undefined' ? useSsl() : config.ssl
this.client_encoding = val('client_encoding', config)
this.replication = val('replication', config)
// a domain socket begins with '/'
this.isDomainSocket = (!(this.host || '').indexOf('/'))
this.application_name = val('application_name', config, 'PGAPPNAME');
this.fallback_application_name = val('fallback_application_name', config, false);
};
this.application_name = val('application_name', config, 'PGAPPNAME')
this.fallback_application_name = val('fallback_application_name', config, false)
}
// Convert arg to a string, surround in single quotes, and escape single quotes and backslashes
var quoteParamValue = function(value) {
return "'" + ('' + value).replace(/\\/g, "\\\\").replace(/'/g, "\\'") + "'";
};
var quoteParamValue = function (value) {
return "'" + ('' + value).replace(/\\/g, '\\\\').replace(/'/g, "\\'") + "'"
}
var add = function(params, config, paramName) {
var value = config[paramName];
if(value) {
params.push(paramName + "=" + quoteParamValue(value));
var add = function (params, config, paramName) {
var value = config[paramName]
if (value) {
params.push(paramName + '=' + quoteParamValue(value))
}
};
}
ConnectionParameters.prototype.getLibpqConnectionString = function(cb) {
var params = [];
add(params, this, 'user');
add(params, this, 'password');
add(params, this, 'port');
add(params, this, 'application_name');
add(params, this, 'fallback_application_name');
ConnectionParameters.prototype.getLibpqConnectionString = function (cb) {
var params = []
add(params, this, 'user')
add(params, this, 'password')
add(params, this, 'port')
add(params, this, 'application_name')
add(params, this, 'fallback_application_name')
var ssl = typeof this.ssl === 'object' ? this.ssl : {sslmode: this.ssl};
add(params, ssl, 'sslmode');
add(params, ssl, 'sslca');
add(params, ssl, 'sslkey');
add(params, ssl, 'sslcert');
if(this.database) {
params.push("dbname=" + quoteParamValue(this.database));
}
if(this.replication) {
params.push("replication=" + quoteParamValue(this.replication));
}
if(this.host) {
params.push("host=" + quoteParamValue(this.host));
}
if(this.isDomainSocket) {
return cb(null, params.join(' '));
}
if(this.client_encoding) {
params.push("client_encoding=" + quoteParamValue(this.client_encoding));
}
dns.lookup(this.host, function(err, address) {
if(err) return cb(err, null);
params.push("hostaddr=" + quoteParamValue(address));
return cb(null, params.join(' '));
});
};
var ssl = typeof this.ssl === 'object' ? this.ssl : {sslmode: this.ssl}
add(params, ssl, 'sslmode')
add(params, ssl, 'sslca')
add(params, ssl, 'sslkey')
add(params, ssl, 'sslcert')
module.exports = ConnectionParameters;
if (this.database) {
params.push('dbname=' + quoteParamValue(this.database))
}
if (this.replication) {
params.push('replication=' + quoteParamValue(this.replication))
}
if (this.host) {
params.push('host=' + quoteParamValue(this.host))
}
if (this.isDomainSocket) {
return cb(null, params.join(' '))
}
if (this.client_encoding) {
params.push('client_encoding=' + quoteParamValue(this.client_encoding))
}
dns.lookup(this.host, function (err, address) {
if (err) return cb(err, null)
params.push('hostaddr=' + quoteParamValue(address))
return cb(null, params.join(' '))
})
}
module.exports = ConnectionParameters

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,4 @@
'use strict'
/**
* Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
* All rights reserved.
@ -6,53 +7,53 @@
* README.md file in the root directory of this source tree.
*/
var defaults = module.exports = {
module.exports = {
// database host. defaults to localhost
host: 'localhost',
//database user's name
// database user's name
user: process.platform === 'win32' ? process.env.USERNAME : process.env.USER,
//name of database to connect
// name of database to connect
database: process.platform === 'win32' ? process.env.USERNAME : process.env.USER,
//database user's password
// database user's password
password: null,
// a Postgres connection string to be used instead of setting individual connection items
// NOTE: Setting this value will cause it to override any other value (such as database or user) defined
// in the defaults object.
connectionString : undefined,
connectionString: undefined,
//database port
// database port
port: 5432,
//number of rows to return at a time from a prepared statement's
//portal. 0 will return all rows at once
// number of rows to return at a time from a prepared statement's
// portal. 0 will return all rows at once
rows: 0,
// binary result mode
binary: false,
//Connection pool options - see https://github.com/coopernurse/node-pool
//number of connections to use in connection pool
//0 will disable connection pooling
// Connection pool options - see https://github.com/coopernurse/node-pool
// number of connections to use in connection pool
// 0 will disable connection pooling
poolSize: 10,
//max milliseconds a client can go unused before it is removed
//from the pool and destroyed
// max milliseconds a client can go unused before it is removed
// from the pool and destroyed
poolIdleTimeout: 30000,
//frequency to check for idle clients within the client pool
// frequency to check for idle clients within the client pool
reapIntervalMillis: 1000,
//if true the most recently released resources will be the first to be allocated
// if true the most recently released resources will be the first to be allocated
returnToHead: false,
//pool log function / boolean
// pool log function / boolean
poolLog: false,
client_encoding: "",
client_encoding: '',
ssl: false,
@ -60,15 +61,15 @@ var defaults = module.exports = {
fallback_application_name: undefined,
parseInputDatesAsUTC: false
};
}
var pgTypes = require('pg-types');
var pgTypes = require('pg-types')
// save default parsers
var parseBigInteger = pgTypes.getTypeParser(20, 'text');
var parseBigIntegerArray = pgTypes.getTypeParser(1016, 'text');
var parseBigInteger = pgTypes.getTypeParser(20, 'text')
var parseBigIntegerArray = pgTypes.getTypeParser(1016, 'text')
//parse int8 so you can get your count values as actual numbers
module.exports.__defineSetter__("parseInt8", function(val) {
pgTypes.setTypeParser(20, 'text', val ? pgTypes.getTypeParser(23, 'text') : parseBigInteger);
pgTypes.setTypeParser(1016, 'text', val ? pgTypes.getTypeParser(1007, 'text') : parseBigIntegerArray);
});
// parse int8 so you can get your count values as actual numbers
module.exports.__defineSetter__('parseInt8', function (val) {
pgTypes.setTypeParser(20, 'text', val ? pgTypes.getTypeParser(23, 'text') : parseBigInteger)
pgTypes.setTypeParser(1016, 'text', val ? pgTypes.getTypeParser(1007, 'text') : parseBigIntegerArray)
})

View File

@ -1,3 +1,4 @@
'use strict'
/**
* Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
* All rights reserved.
@ -6,109 +7,54 @@
* README.md file in the root directory of this source tree.
*/
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var Client = require('./client');
var defaults = require('./defaults');
var Connection = require('./connection');
var ConnectionParameters = require('./connection-parameters');
var poolFactory = require('./pool-factory');
var util = require('util')
var Client = require('./client')
var defaults = require('./defaults')
var Connection = require('./connection')
var Pool = require('pg-pool')
var PG = function(clientConstructor) {
EventEmitter.call(this);
this.defaults = defaults;
this.Client = clientConstructor;
this.Query = this.Client.Query;
this.Pool = poolFactory(this.Client);
this._pools = [];
this.Connection = Connection;
this.types = require('pg-types');
};
util.inherits(PG, EventEmitter);
PG.prototype.end = util.deprecate(function() {
var self = this;
var keys = Object.keys(this._pools);
var count = keys.length;
if(count === 0) {
self.emit('end');
} else {
keys.forEach(function(key) {
var pool = self._pools[key];
delete self._pools[key];
pool.pool.drain(function() {
pool.pool.destroyAllNow(function() {
count--;
if(count === 0) {
self.emit('end');
}
});
});
});
}
}, 'PG.end is deprecated - please see the upgrade guide at https://node-postgres.com/guides/upgrading');
PG.prototype.connect = util.deprecate(function(config, callback) {
if(typeof config == "function") {
callback = config;
config = null;
}
if (typeof config == 'string') {
config = new ConnectionParameters(config);
const poolFactory = (Client) => {
var BoundPool = function (options) {
var config = { Client: Client }
for (var key in options) {
config[key] = options[key]
}
return new Pool(config)
}
config = config || {};
util.inherits(BoundPool, Pool)
//for backwards compatibility
config.max = config.max || config.poolSize || defaults.poolSize;
config.idleTimeoutMillis = config.idleTimeoutMillis || config.poolIdleTimeout || defaults.poolIdleTimeout;
config.log = config.log || config.poolLog || defaults.poolLog;
return BoundPool
}
var poolName = JSON.stringify(config);
this._pools[poolName] = this._pools[poolName] || new this.Pool(config);
var pool = this._pools[poolName];
if(!pool.listeners('error').length) {
//propagate errors up to pg object
pool.on('error', function(e) {
this.emit('error', e, e.client);
}.bind(this));
}
return pool.connect(callback);
}, 'PG.connect is deprecated - please see the upgrade guide at https://node-postgres.com/guides/upgrading');
var PG = function (clientConstructor) {
this.defaults = defaults
this.Client = clientConstructor
this.Query = this.Client.Query
this.Pool = poolFactory(this.Client)
this._pools = []
this.Connection = Connection
this.types = require('pg-types')
}
// cancel the query running on the given client
PG.prototype.cancel = util.deprecate(function(config, client, query) {
if(client.native) {
return client.cancel(query);
}
var c = config;
//allow for no config to be passed
if(typeof c === 'function') {
c = defaults;
}
var cancellingClient = new this.Client(c);
cancellingClient.cancel(client, query);
}, 'PG.cancel is deprecated - use client.cancel instead');
if(typeof process.env.NODE_PG_FORCE_NATIVE != 'undefined') {
module.exports = new PG(require('./native'));
if (typeof process.env.NODE_PG_FORCE_NATIVE !== 'undefined') {
module.exports = new PG(require('./native'))
} else {
module.exports = new PG(Client);
module.exports = new PG(Client)
//lazy require native module...the native module may not have installed
module.exports.__defineGetter__("native", function() {
delete module.exports.native;
var native = null;
// lazy require native module...the native module may not have installed
module.exports.__defineGetter__('native', function () {
delete module.exports.native
var native = null
try {
native = new PG(require('./native'));
native = new PG(require('./native'))
} catch (err) {
if (err.code !== 'MODULE_NOT_FOUND') {
throw err;
throw err
}
console.error(err.message);
console.error(err.message)
}
module.exports.native = native;
return native;
});
module.exports.native = native
return native
})
}

226
lib/native/client.js Normal file
View File

@ -0,0 +1,226 @@
'use strict'
/**
* Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* README.md file in the root directory of this source tree.
*/
var Native = require('pg-native')
var TypeOverrides = require('../type-overrides')
var semver = require('semver')
var pkg = require('../../package.json')
var assert = require('assert')
var EventEmitter = require('events').EventEmitter
var util = require('util')
var ConnectionParameters = require('../connection-parameters')
var msg = 'Version >= ' + pkg.minNativeVersion + ' of pg-native required.'
assert(semver.gte(Native.version, pkg.minNativeVersion), msg)
var NativeQuery = require('./query')
var Client = module.exports = function (config) {
EventEmitter.call(this)
config = config || {}
this._types = new TypeOverrides(config.types)
this.native = new Native({
types: this._types
})
this._queryQueue = []
this._connected = false
this._connecting = false
// keep these on the object for legacy reasons
// for the time being. TODO: deprecate all this jazz
var cp = this.connectionParameters = new ConnectionParameters(config)
this.user = cp.user
this.password = cp.password
this.database = cp.database
this.host = cp.host
this.port = cp.port
// a hash to hold named queries
this.namedQueries = {}
}
Client.Query = NativeQuery
util.inherits(Client, EventEmitter)
// connect to the backend
// pass an optional callback to be called once connected
// or with an error if there was a connection error
// if no callback is passed and there is a connection error
// the client will emit an error event.
Client.prototype.connect = function (cb) {
var self = this
var onError = function (err) {
if (cb) return cb(err)
return self.emit('error', err)
}
var result
if (!cb) {
var resolveOut, rejectOut
cb = (err) => err ? rejectOut(err) : resolveOut()
result = new global.Promise(function (resolve, reject) {
resolveOut = resolve
rejectOut = reject
})
}
if (this._connecting) {
process.nextTick(() => cb(new Error('Client has already been connected. You cannot reuse a client.')))
return result
}
this._connecting = true
this.connectionParameters.getLibpqConnectionString(function (err, conString) {
if (err) return onError(err)
self.native.connect(conString, function (err) {
if (err) return onError(err)
// set internal states to connected
self._connected = true
// handle connection errors from the native layer
self.native.on('error', function (err) {
// error will be handled by active query
if (self._activeQuery && self._activeQuery.state !== 'end') {
return
}
self.emit('error', err)
})
self.native.on('notification', function (msg) {
self.emit('notification', {
channel: msg.relname,
payload: msg.extra
})
})
// signal we are connected now
self.emit('connect')
self._pulseQueryQueue(true)
// possibly call the optional callback
if (cb) cb()
})
})
return result
}
// send a query to the server
// this method is highly overloaded to take
// 1) string query, optional array of parameters, optional function callback
// 2) object query with {
// string query
// optional array values,
// optional function callback instead of as a separate parameter
// optional string name to name & cache the query plan
// optional string rowMode = 'array' for an array of results
// }
Client.prototype.query = function (config, values, callback) {
if (typeof config.submit === 'function') {
// accept query(new Query(...), (err, res) => { }) style
if (typeof values === 'function') {
config.callback = values
}
this._queryQueue.push(config)
this._pulseQueryQueue()
return config
}
var query = new NativeQuery(config, values, callback)
var result
if (!query.callback) {
let resolveOut, rejectOut
result = new Promise((resolve, reject) => {
resolveOut = resolve
rejectOut = reject
})
query.callback = (err, res) => err ? rejectOut(err) : resolveOut(res)
}
this._queryQueue.push(query)
this._pulseQueryQueue()
return result
}
// disconnect from the backend server
Client.prototype.end = function (cb) {
var self = this
if (!this._connected) {
this.once('connect', this.end.bind(this, cb))
}
var result
if (!cb) {
var resolve, reject
cb = (err) => err ? reject(err) : resolve()
result = new global.Promise(function (res, rej) {
resolve = res
reject = rej
})
}
this.native.end(function () {
// send an error to the active query
if (self._hasActiveQuery()) {
var msg = 'Connection terminated'
self._queryQueue.length = 0
self._activeQuery.handleError(new Error(msg))
}
self.emit('end')
if (cb) cb()
})
return result
}
Client.prototype._hasActiveQuery = function () {
return this._activeQuery && this._activeQuery.state !== 'error' && this._activeQuery.state !== 'end'
}
Client.prototype._pulseQueryQueue = function (initialConnection) {
if (!this._connected) {
return
}
if (this._hasActiveQuery()) {
return
}
var query = this._queryQueue.shift()
if (!query) {
if (!initialConnection) {
this.emit('drain')
}
return
}
this._activeQuery = query
query.submit(this)
var self = this
query.once('_done', function () {
self._pulseQueryQueue()
})
}
// attempt to cancel an in-progress query
Client.prototype.cancel = function (query) {
if (this._activeQuery === query) {
this.native.cancel(function () {})
} else if (this._queryQueue.indexOf(query) !== -1) {
this._queryQueue.splice(this._queryQueue.indexOf(query), 1)
}
}
Client.prototype.setTypeParser = function (oid, format, parseFn) {
return this._types.setTypeParser(oid, format, parseFn)
}
Client.prototype.getTypeParser = function (oid, format) {
return this._types.getTypeParser(oid, format)
}

View File

@ -1,234 +1,2 @@
/**
* Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* README.md file in the root directory of this source tree.
*/
var Native = require('pg-native');
var TypeOverrides = require('../type-overrides');
var semver = require('semver');
var pkg = require('../../package.json');
var assert = require('assert');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var ConnectionParameters = require('../connection-parameters');
var msg = 'Version >= ' + pkg.minNativeVersion + ' of pg-native required.';
assert(semver.gte(Native.version, pkg.minNativeVersion), msg);
var NativeQuery = require('./query');
var Client = module.exports = function(config) {
EventEmitter.call(this);
config = config || {};
this._types = new TypeOverrides(config.types);
this.native = new Native({
types: this._types
});
this._queryQueue = [];
this._connected = false;
//keep these on the object for legacy reasons
//for the time being. TODO: deprecate all this jazz
var cp = this.connectionParameters = new ConnectionParameters(config);
this.user = cp.user;
this.password = cp.password;
this.database = cp.database;
this.host = cp.host;
this.port = cp.port;
//a hash to hold named queries
this.namedQueries = {};
};
Client.Query = NativeQuery;
util.inherits(Client, EventEmitter);
//connect to the backend
//pass an optional callback to be called once connected
//or with an error if there was a connection error
//if no callback is passed and there is a connection error
//the client will emit an error event.
Client.prototype.connect = function(cb) {
var self = this;
var onError = function(err) {
if(cb) return cb(err);
return self.emit('error', err);
};
this.connectionParameters.getLibpqConnectionString(function(err, conString) {
if(err) return onError(err);
self.native.connect(conString, function(err) {
if(err) return onError(err);
//set internal states to connected
self._connected = true;
//handle connection errors from the native layer
self.native.on('error', function(err) {
//error will be handled by active query
if(self._activeQuery && self._activeQuery.state != 'end') {
return;
}
self.emit('error', err);
});
self.native.on('notification', function(msg) {
self.emit('notification', {
channel: msg.relname,
payload: msg.extra
});
});
//signal we are connected now
self.emit('connect');
self._pulseQueryQueue(true);
//possibly call the optional callback
if(cb) cb();
});
});
};
//send a query to the server
//this method is highly overloaded to take
//1) string query, optional array of parameters, optional function callback
//2) object query with {
// string query
// optional array values,
// optional function callback instead of as a separate parameter
// optional string name to name & cache the query plan
// optional string rowMode = 'array' for an array of results
// }
Client.prototype.query = function(config, values, callback) {
var query = new NativeQuery(this.native);
//support query('text', ...) style calls
if(typeof config == 'string') {
query.text = config;
}
//support passing everything in via a config object
if(typeof config == 'object') {
query.text = config.text;
query.values = config.values;
query.name = config.name;
query.callback = config.callback;
query._arrayMode = config.rowMode == 'array';
}
//support query({...}, function() {}) style calls
//& support query(..., ['values'], ...) style calls
if(typeof values == 'function') {
query.callback = values;
}
else if(util.isArray(values)) {
query.values = values;
}
if(typeof callback == 'function') {
query.callback = callback;
}
this._queryQueue.push(query);
this._pulseQueryQueue();
return query;
};
var DeprecatedQuery = require('../utils').deprecateEventEmitter(NativeQuery);
//send a query to the server
//this method is highly overloaded to take
//1) string query, optional array of parameters, optional function callback
//2) object query with {
// string query
// optional array values,
// optional function callback instead of as a separate parameter
// optional string name to name & cache the query plan
// optional string rowMode = 'array' for an array of results
// }
Client.prototype.query = function(config, values, callback) {
if (typeof config.submit == 'function') {
// accept query(new Query(...), (err, res) => { }) style
if (typeof values == 'function') {
config.callback = values;
}
this._queryQueue.push(config);
this._pulseQueryQueue();
return config;
}
var query = new DeprecatedQuery(config, values, callback);
this._queryQueue.push(query);
this._pulseQueryQueue();
return query;
};
//disconnect from the backend server
Client.prototype.end = function(cb) {
var self = this;
if(!this._connected) {
this.once('connect', this.end.bind(this, cb));
}
this.native.end(function() {
//send an error to the active query
if(self._hasActiveQuery()) {
var msg = 'Connection terminated';
self._queryQueue.length = 0;
self._activeQuery.handleError(new Error(msg));
}
self.emit('end');
if(cb) cb();
});
};
Client.prototype._hasActiveQuery = function() {
return this._activeQuery && this._activeQuery.state != 'error' && this._activeQuery.state != 'end';
};
Client.prototype._pulseQueryQueue = function(initialConnection) {
if(!this._connected) {
return;
}
if(this._hasActiveQuery()) {
return;
}
var query = this._queryQueue.shift();
if(!query) {
if(!initialConnection) {
this.emit('drain');
}
return;
}
this._activeQuery = query;
query.submit(this);
var self = this;
var pulseOnDone = function() {
self._pulseQueryQueue();
query.removeListener('_done', pulseOnDone);
};
query._on('_done', pulseOnDone);
};
//attempt to cancel an in-progress query
Client.prototype.cancel = function(query) {
if(this._activeQuery == query) {
this.native.cancel(function() {});
} else if (this._queryQueue.indexOf(query) != -1) {
this._queryQueue.splice(this._queryQueue.indexOf(query), 1);
}
};
Client.prototype.setTypeParser = function(oid, format, parseFn) {
return this._types.setTypeParser(oid, format, parseFn);
};
Client.prototype.getTypeParser = function(oid, format) {
return this._types.getTypeParser(oid, format);
};
'use strict'
module.exports = require('./client')

View File

@ -1,3 +1,4 @@
'use strict'
/**
* Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
* All rights reserved.
@ -6,155 +7,155 @@
* README.md file in the root directory of this source tree.
*/
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var utils = require('../utils');
var NativeResult = require('./result');
var EventEmitter = require('events').EventEmitter
var util = require('util')
var utils = require('../utils')
var NativeQuery = module.exports = function(config, values, callback) {
EventEmitter.call(this);
config = utils.normalizeQueryConfig(config, values, callback);
this.text = config.text;
this.values = config.values;
this.name = config.name;
this.callback = config.callback;
this.state = 'new';
this._arrayMode = config.rowMode == 'array';
var NativeQuery = module.exports = function (config, values, callback) {
EventEmitter.call(this)
config = utils.normalizeQueryConfig(config, values, callback)
this.text = config.text
this.values = config.values
this.name = config.name
this.callback = config.callback
this.state = 'new'
this._arrayMode = config.rowMode === 'array'
//if the 'row' event is listened for
//then emit them as they come in
//without setting singleRowMode to true
//this has almost no meaning because libpq
//reads all rows into memory befor returning any
this._emitRowEvents = false;
this._on('newListener', function(event) {
if(event === 'row') this._emitRowEvents = true;
}.bind(this));
};
// if the 'row' event is listened for
// then emit them as they come in
// without setting singleRowMode to true
// this has almost no meaning because libpq
// reads all rows into memory befor returning any
this._emitRowEvents = false
this.on('newListener', function (event) {
if (event === 'row') this._emitRowEvents = true
}.bind(this))
}
util.inherits(NativeQuery, EventEmitter);
util.inherits(NativeQuery, EventEmitter)
// TODO - remove in 7.0
// this maintains backwards compat so someone could instantiate a query
// manually: `new Query().then()`...
NativeQuery._on = NativeQuery.on;
NativeQuery._once = NativeQuery.once;
var errorFieldMap = {
'sqlState': 'code',
'statementPosition': 'position',
'messagePrimary': 'message',
'context': 'where',
'schemaName': 'schema',
'tableName': 'table',
'columnName': 'column',
'dataTypeName': 'dataType',
'constraintName': 'constraint',
'sourceFile': 'file',
'sourceLine': 'line',
'sourceFunction': 'routine'
}
NativeQuery.prototype.then = function(onSuccess, onFailure) {
return this._getPromise().then(onSuccess, onFailure);
};
NativeQuery.prototype.catch = function(callback) {
return this._getPromise().catch(callback);
};
NativeQuery.prototype._getPromise = function() {
if (this._promise) return this._promise;
this._promise = new Promise(function(resolve, reject) {
var onEnd = function (result) {
this.removeListener('error', onError);
this.removeListener('end', onEnd);
resolve(result);
};
var onError = function (err) {
this.removeListener('error', onError);
this.removeListener('end', onEnd);
reject(err);
};
this._on('end', onEnd);
this._on('error', onError);
}.bind(this));
return this._promise;
};
NativeQuery.prototype.promise = util.deprecate(function() {
return this._getPromise();
}, 'Query.promise() is deprecated - see the upgrade guide at https://node-postgres.com/guides/upgrading');
NativeQuery.prototype.handleError = function(err) {
var self = this;
//copy pq error fields into the error object
var fields = self.native.pq.resultErrorFields();
if(fields) {
for(var key in fields) {
err[key] = fields[key];
NativeQuery.prototype.handleError = function (err) {
var self = this
// copy pq error fields into the error object
var fields = self.native.pq.resultErrorFields()
if (fields) {
for (var key in fields) {
var normalizedFieldName = errorFieldMap[key] || key
err[normalizedFieldName] = fields[key]
}
}
if(self.callback) {
self.callback(err);
if (self.callback) {
self.callback(err)
} else {
self.emit('error', err);
self.emit('error', err)
}
self.state = 'error';
};
self.state = 'error'
}
NativeQuery.prototype.submit = function(client) {
this.state = 'running';
var self = this;
self.native = client.native;
client.native.arrayMode = this._arrayMode;
NativeQuery.prototype.then = function (onSuccess, onFailure) {
return this._getPromise().then(onSuccess, onFailure)
}
var after = function(err, rows) {
client.native.arrayMode = false;
setImmediate(function() {
self.emit('_done');
});
NativeQuery.prototype.catch = function (callback) {
return this._getPromise().catch(callback)
}
//handle possible query error
if(err) {
return self.handleError(err);
NativeQuery.prototype._getPromise = function () {
if (this._promise) return this._promise
this._promise = new Promise(function (resolve, reject) {
this._once('end', resolve)
this._once('error', reject)
}.bind(this))
return this._promise
}
NativeQuery.prototype.submit = function (client) {
this.state = 'running'
var self = this
this.native = client.native
client.native.arrayMode = this._arrayMode
var after = function (err, rows, results) {
client.native.arrayMode = false
setImmediate(function () {
self.emit('_done')
})
// handle possible query error
if (err) {
return self.handleError(err)
}
var result = new NativeResult();
result.addCommandComplete(self.native.pq);
result.rows = rows;
//emit row events for each row in the result
if(self._emitRowEvents) {
rows.forEach(function(row) {
self.emit('row', row, result);
});
// emit row events for each row in the result
if (self._emitRowEvents) {
if (results.length > 1) {
rows.forEach((rowOfRows, i) => {
rowOfRows.forEach(row => {
self.emit('row', row, results[i])
})
})
} else {
rows.forEach(function (row) {
self.emit('row', row, results)
})
}
}
//handle successful result
self.state = 'end';
self.emit('end', result);
if(self.callback) {
self.callback(null, result);
// handle successful result
self.state = 'end'
self.emit('end', results)
if (self.callback) {
self.callback(null, results)
}
};
if(process.domain) {
after = process.domain.bind(after);
}
//named query
if(this.name) {
if (process.domain) {
after = process.domain.bind(after)
}
// named query
if (this.name) {
if (this.name.length > 63) {
console.error('Warning! Postgres only supports 63 characters for query names.');
console.error('You supplied', this.name, '(', this.name.length, ')');
console.error('This can cause conflicts and silent errors executing queries');
console.error('Warning! Postgres only supports 63 characters for query names.')
console.error('You supplied', this.name, '(', this.name.length, ')')
console.error('This can cause conflicts and silent errors executing queries')
}
var values = (this.values||[]).map(utils.prepareValue);
var values = (this.values || []).map(utils.prepareValue)
//check if the client has already executed this named query
//if so...just execute it again - skip the planning phase
if(client.namedQueries[this.name]) {
return this.native.execute(this.name, values, after);
// check if the client has already executed this named query
// if so...just execute it again - skip the planning phase
if (client.namedQueries[this.name]) {
return client.native.execute(this.name, values, after)
}
//plan the named query the first time, then execute it
return this.native.prepare(this.name, this.text, values.length, function(err) {
if(err) return after(err);
client.namedQueries[self.name] = true;
return self.native.execute(self.name, values, after);
});
}
else if(this.values) {
var vals = this.values.map(utils.prepareValue);
this.native.query(this.text, vals, after);
// plan the named query the first time, then execute it
return client.native.prepare(this.name, this.text, values.length, function (err) {
if (err) return after(err)
client.namedQueries[self.name] = true
return self.native.execute(self.name, values, after)
})
} else if (this.values) {
if (!Array.isArray(this.values)) {
const err = new Error('Query values must be an array')
return after(err)
}
var vals = this.values.map(utils.prepareValue)
client.native.query(this.text, vals, after)
} else {
this.native.query(this.text, after);
client.native.query(this.text, after)
}
};
}

View File

@ -1,36 +0,0 @@
/**
* Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* README.md file in the root directory of this source tree.
*/
var NativeResult = module.exports = function(pq) {
this.command = null;
this.rowCount = 0;
this.rows = null;
this.fields = null;
};
NativeResult.prototype.addCommandComplete = function(pq) {
this.command = pq.cmdStatus().split(' ')[0];
this.rowCount = parseInt(pq.cmdTuples(), 10);
var nfields = pq.nfields();
if(nfields < 1) return;
this.fields = [];
for(var i = 0; i < nfields; i++) {
this.fields.push({
name: pq.fname(i),
dataTypeID: pq.ftype(i)
});
}
};
NativeResult.prototype.addRow = function(row) {
// This is empty to ensure pg code doesn't break when switching to pg-native
// pg-native loads all rows into the final result object by default.
// This is because libpg loads all rows into memory before passing the result
// to pg-native.
};

View File

@ -1,17 +0,0 @@
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;
};

View File

@ -1,3 +1,4 @@
'use strict'
/**
* Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
* All rights reserved.
@ -6,233 +7,226 @@
* README.md file in the root directory of this source tree.
*/
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var EventEmitter = require('events').EventEmitter
var util = require('util')
var Result = require('./result');
var utils = require('./utils');
var Result = require('./result')
var utils = require('./utils')
var Query = function(config, values, callback) {
var Query = function (config, values, callback) {
// use of "new" optional
if(!(this instanceof Query)) { return new Query(config, values, callback); }
if (!(this instanceof Query)) { return new Query(config, values, callback) }
config = utils.normalizeQueryConfig(config, values, callback);
config = utils.normalizeQueryConfig(config, values, callback)
this.text = config.text;
this.values = config.values;
this.rows = config.rows;
this.types = config.types;
this.name = config.name;
this.binary = config.binary;
this.stream = config.stream;
//use unique portal name each time
this.portal = config.portal || "";
this.callback = config.callback;
if(process.domain && config.callback) {
this.callback = process.domain.bind(config.callback);
this.text = config.text
this.values = config.values
this.rows = config.rows
this.types = config.types
this.name = config.name
this.binary = config.binary
this.stream = config.stream
// use unique portal name each time
this.portal = config.portal || ''
this.callback = config.callback
this._rowMode = config.rowMode
if (process.domain && config.callback) {
this.callback = process.domain.bind(config.callback)
}
this._result = new Result(config.rowMode, config.types);
this.isPreparedStatement = false;
this._canceledDueToError = false;
this._promise = null;
EventEmitter.call(this);
};
this._result = new Result(this._rowMode, this.types)
util.inherits(Query, EventEmitter);
// potential for multiple results
this._results = this._result
this.isPreparedStatement = false
this._canceledDueToError = false
this._promise = null
EventEmitter.call(this)
}
// TODO - remove in 7.0
// this maintains backwards compat so someone could instantiate a query
// manually: `new Query().then()`...
Query._on = Query.on;
Query._once = Query.once;
util.inherits(Query, EventEmitter)
Query.prototype.then = function(onSuccess, onFailure) {
return this._getPromise().then(onSuccess, onFailure);
};
Query.prototype.requiresPreparation = function () {
// named queries must always be prepared
if (this.name) { return true }
// always prepare if there are max number of rows expected per
// portal execution
if (this.rows) { return true }
// don't prepare empty text queries
if (!this.text) { return false }
// prepare if there are values
if (!this.values) { return false }
return this.values.length > 0
}
Query.prototype.catch = function(callback) {
return this._getPromise().catch(callback);
};
Query.prototype._checkForMultirow = function () {
// if we already have a result with a command property
// then we've already executed one query in a multi-statement simple query
// turn our results into an array of results
if (this._result.command) {
if (!Array.isArray(this._results)) {
this._results = [this._result]
}
this._result = new Result(this._rowMode, this.types)
this._results.push(this._result)
}
}
Query.prototype._getPromise = function () {
if (this._promise) return this._promise;
this._promise = new Promise(function(resolve, reject) {
var onEnd = function (result) {
this.removeListener('error', onError);
this.removeListener('end', onEnd);
resolve(result);
};
var onError = function (err) {
this.removeListener('error', onError);
this.removeListener('end', onEnd);
reject(err);
};
this._on('end', onEnd);
this._on('error', onError);
}.bind(this));
return this._promise;
};
// associates row metadata from the supplied
// message with this query object
// metadata used when parsing row results
Query.prototype.handleRowDescription = function (msg) {
this._checkForMultirow()
this._result.addFields(msg.fields)
this._accumulateRows = this.callback || !this.listeners('row').length
}
Query.prototype.promise = util.deprecate(function() {
return this._getPromise();
}, 'Query.promise() is deprecated - see the upgrade guide at https://node-postgres.com/guides/upgrading');
Query.prototype.requiresPreparation = function() {
//named queries must always be prepared
if(this.name) { return true; }
//always prepare if there are max number of rows expected per
//portal execution
if(this.rows) { return true; }
//don't prepare empty text queries
if(!this.text) { return false; }
//prepare if there are values
if(!this.values) { return false; }
return this.values.length > 0;
};
//associates row metadata from the supplied
//message with this query object
//metadata used when parsing row results
Query.prototype.handleRowDescription = function(msg) {
this._result.addFields(msg.fields);
this._accumulateRows = this.callback || !this.listeners('row').length;
};
Query.prototype.handleDataRow = function(msg) {
var row;
Query.prototype.handleDataRow = function (msg) {
var row
if (this._canceledDueToError) {
return;
return
}
try {
row = this._result.parseRow(msg.fields);
row = this._result.parseRow(msg.fields)
} catch (err) {
this._canceledDueToError = err;
return;
this._canceledDueToError = err
return
}
this.emit('row', row, this._result);
this.emit('row', row, this._result)
if (this._accumulateRows) {
this._result.addRow(row);
this._result.addRow(row)
}
};
}
Query.prototype.handleCommandComplete = function(msg, con) {
this._result.addCommandComplete(msg);
//need to sync after each command complete of a prepared statement
if(this.isPreparedStatement) {
con.sync();
}
};
//if a named prepared statement is created with empty query text
//the backend will send an emptyQuery message but *not* a command complete message
//execution on the connection will hang until the backend receives a sync message
Query.prototype.handleEmptyQuery = function(con) {
Query.prototype.handleCommandComplete = function (msg, con) {
this._checkForMultirow()
this._result.addCommandComplete(msg)
// need to sync after each command complete of a prepared statement
if (this.isPreparedStatement) {
con.sync();
con.sync()
}
};
}
Query.prototype.handleReadyForQuery = function(con) {
if(this._canceledDueToError) {
return this.handleError(this._canceledDueToError, con);
// if a named prepared statement is created with empty query text
// the backend will send an emptyQuery message but *not* a command complete message
// execution on the connection will hang until the backend receives a sync message
Query.prototype.handleEmptyQuery = function (con) {
if (this.isPreparedStatement) {
con.sync()
}
if(this.callback) {
this.callback(null, this._result);
}
this.emit('end', this._result);
};
}
Query.prototype.handleError = function(err, connection) {
//need to sync after error during a prepared statement
if(this.isPreparedStatement) {
connection.sync();
Query.prototype.handleReadyForQuery = function (con) {
if (this._canceledDueToError) {
return this.handleError(this._canceledDueToError, con)
}
if(this._canceledDueToError) {
err = this._canceledDueToError;
this._canceledDueToError = false;
if (this.callback) {
this.callback(null, this._results)
}
//if callback supplied do not emit error event as uncaught error
//events will bubble up to node process
if(this.callback) {
return this.callback(err);
}
this.emit('error', err);
};
this.emit('end', this._results)
}
Query.prototype.submit = function(connection) {
if(this.requiresPreparation()) {
this.prepare(connection);
Query.prototype.handleError = function (err, connection) {
// need to sync after error during a prepared statement
if (this.isPreparedStatement) {
connection.sync()
}
if (this._canceledDueToError) {
err = this._canceledDueToError
this._canceledDueToError = false
}
// if callback supplied do not emit error event as uncaught error
// events will bubble up to node process
if (this.callback) {
return this.callback(err)
}
this.emit('error', err)
}
Query.prototype.submit = function (connection) {
if (typeof this.text !== 'string' && typeof this.name !== 'string') {
const err = new Error('A query must have either text or a name. Supplying neither is unsupported.')
connection.emit('error', err)
connection.emit('readyForQuery')
return
}
if (this.values && !Array.isArray(this.values)) {
const err = new Error('Query values must be an array')
connection.emit('error', err)
connection.emit('readyForQuery')
return
}
if (this.requiresPreparation()) {
this.prepare(connection)
} else {
connection.query(this.text);
connection.query(this.text)
}
};
}
Query.prototype.hasBeenParsed = function(connection) {
return this.name && connection.parsedStatements[this.name];
};
Query.prototype.hasBeenParsed = function (connection) {
return this.name && connection.parsedStatements[this.name]
}
Query.prototype.handlePortalSuspended = function(connection) {
this._getRows(connection, this.rows);
};
Query.prototype.handlePortalSuspended = function (connection) {
this._getRows(connection, this.rows)
}
Query.prototype._getRows = function(connection, rows) {
Query.prototype._getRows = function (connection, rows) {
connection.execute({
portal: this.portalName,
rows: rows
}, true);
connection.flush();
};
}, true)
connection.flush()
}
Query.prototype.prepare = function(connection) {
var self = this;
//prepared statements need sync to be called after each command
//complete or when an error is encountered
this.isPreparedStatement = true;
//TODO refactor this poor encapsulation
if(!this.hasBeenParsed(connection)) {
Query.prototype.prepare = function (connection) {
var self = this
// prepared statements need sync to be called after each command
// complete or when an error is encountered
this.isPreparedStatement = true
// TODO refactor this poor encapsulation
if (!this.hasBeenParsed(connection)) {
connection.parse({
text: self.text,
name: self.name,
types: self.types
}, true);
}, true)
}
if(self.values) {
self.values = self.values.map(utils.prepareValue);
if (self.values) {
self.values = self.values.map(utils.prepareValue)
}
//http://developer.postgresql.org/pgdocs/postgres/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY
// http://developer.postgresql.org/pgdocs/postgres/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY
connection.bind({
portal: self.portalName,
statement: self.name,
values: self.values,
binary: self.binary
}, true);
}, true)
connection.describe({
type: 'P',
name: self.portalName || ""
}, true);
name: self.portalName || ''
}, true)
this._getRows(connection, this.rows);
};
this._getRows(connection, this.rows)
}
Query.prototype.handleCopyInResponse = function (connection) {
if(this.stream) this.stream.startStreamingToConnection(connection);
else connection.sendCopyFail('No source stream defined');
};
if (this.stream) this.stream.startStreamingToConnection(connection)
else connection.sendCopyFail('No source stream defined')
}
Query.prototype.handleCopyData = function (msg, connection) {
var chunk = msg.chunk;
if(this.stream) {
this.stream.handleChunk(chunk);
var chunk = msg.chunk
if (this.stream) {
this.stream.handleChunk(chunk)
}
//if there are no stream (for example when copy to query was sent by
//query method instead of copyTo) error will be handled
//on copyOutResponse event, so silently ignore this error here
};
module.exports = Query;
// if there are no stream (for example when copy to query was sent by
// query method instead of copyTo) error will be handled
// on copyOutResponse event, so silently ignore this error here
}
module.exports = Query

View File

@ -1,3 +1,4 @@
'use strict'
/**
* Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
* All rights reserved.
@ -6,110 +7,110 @@
* README.md file in the root directory of this source tree.
*/
var types = require('pg-types');
var types = require('pg-types')
//result object returned from query
//in the 'end' event and also
//passed as second argument to provided callback
var Result = function(rowMode) {
this.command = null;
this.rowCount = null;
this.oid = null;
this.rows = [];
this.fields = [];
this._parsers = [];
this.RowCtor = null;
this.rowAsArray = rowMode == "array";
if(this.rowAsArray) {
this.parseRow = this._parseRowAsArray;
// result object returned from query
// in the 'end' event and also
// passed as second argument to provided callback
var Result = function (rowMode) {
this.command = null
this.rowCount = null
this.oid = null
this.rows = []
this.fields = []
this._parsers = []
this.RowCtor = null
this.rowAsArray = rowMode === 'array'
if (this.rowAsArray) {
this.parseRow = this._parseRowAsArray
}
};
}
var matchRegexp = /([A-Za-z]+) ?(\d+ )?(\d+)?/;
var matchRegexp = /([A-Za-z]+) ?(\d+ )?(\d+)?/
//adds a command complete message
Result.prototype.addCommandComplete = function(msg) {
var match;
if(msg.text) {
//pure javascript
match = matchRegexp.exec(msg.text);
// adds a command complete message
Result.prototype.addCommandComplete = function (msg) {
var match
if (msg.text) {
// pure javascript
match = matchRegexp.exec(msg.text)
} else {
//native bindings
match = matchRegexp.exec(msg.command);
// native bindings
match = matchRegexp.exec(msg.command)
}
if(match) {
this.command = match[1];
//match 3 will only be existing on insert commands
if(match[3]) {
//msg.value is from native bindings
this.rowCount = parseInt(match[3] || msg.value, 10);
this.oid = parseInt(match[2], 10);
if (match) {
this.command = match[1]
// match 3 will only be existing on insert commands
if (match[3]) {
// msg.value is from native bindings
this.rowCount = parseInt(match[3] || msg.value, 10)
this.oid = parseInt(match[2], 10)
} else {
this.rowCount = parseInt(match[2], 10);
this.rowCount = parseInt(match[2], 10)
}
}
};
}
Result.prototype._parseRowAsArray = function(rowData) {
var row = [];
for(var i = 0, len = rowData.length; i < len; i++) {
var rawValue = rowData[i];
if(rawValue !== null) {
row.push(this._parsers[i](rawValue));
Result.prototype._parseRowAsArray = function (rowData) {
var row = []
for (var i = 0, len = rowData.length; i < len; i++) {
var rawValue = rowData[i]
if (rawValue !== null) {
row.push(this._parsers[i](rawValue))
} else {
row.push(null);
row.push(null)
}
}
return row;
};
return row
}
//rowData is an array of text or binary values
//this turns the row into a JavaScript object
Result.prototype.parseRow = function(rowData) {
return new this.RowCtor(this._parsers, rowData);
};
// rowData is an array of text or binary values
// this turns the row into a JavaScript object
Result.prototype.parseRow = function (rowData) {
return new this.RowCtor(this._parsers, rowData)
}
Result.prototype.addRow = function(row) {
this.rows.push(row);
};
Result.prototype.addRow = function (row) {
this.rows.push(row)
}
var inlineParser = function(fieldName, i) {
var inlineParser = function (fieldName, i) {
return "\nthis['" +
//fields containing single quotes will break
//the evaluated javascript unless they are escaped
//see https://github.com/brianc/node-postgres/issues/507
//Addendum: However, we need to make sure to replace all
//occurences of apostrophes, not just the first one.
//See https://github.com/brianc/node-postgres/issues/934
// fields containing single quotes will break
// the evaluated javascript unless they are escaped
// see https://github.com/brianc/node-postgres/issues/507
// Addendum: However, we need to make sure to replace all
// occurences of apostrophes, not just the first one.
// See https://github.com/brianc/node-postgres/issues/934
fieldName.replace(/'/g, "\\'") +
"'] = " +
"rowData[" + i + "] == null ? null : parsers[" + i + "](rowData[" + i + "]);";
};
'rowData[' + i + '] == null ? null : parsers[' + i + '](rowData[' + i + ']);'
}
Result.prototype.addFields = function(fieldDescriptions) {
//clears field definitions
//multiple query statements in 1 action can result in multiple sets
//of rowDescriptions...eg: 'select NOW(); select 1::int;'
//you need to reset the fields
if(this.fields.length) {
this.fields = [];
this._parsers = [];
Result.prototype.addFields = function (fieldDescriptions) {
// clears field definitions
// multiple query statements in 1 action can result in multiple sets
// of rowDescriptions...eg: 'select NOW(); select 1::int;'
// you need to reset the fields
if (this.fields.length) {
this.fields = []
this._parsers = []
}
var ctorBody = "";
for(var i = 0; i < fieldDescriptions.length; i++) {
var desc = fieldDescriptions[i];
this.fields.push(desc);
var parser = this._getTypeParser(desc.dataTypeID, desc.format || 'text');
this._parsers.push(parser);
//this is some craziness to compile the row result parsing
//results in ~60% speedup on large query result sets
ctorBody += inlineParser(desc.name, i);
var ctorBody = ''
for (var i = 0; i < fieldDescriptions.length; i++) {
var desc = fieldDescriptions[i]
this.fields.push(desc)
var parser = this._getTypeParser(desc.dataTypeID, desc.format || 'text')
this._parsers.push(parser)
// this is some craziness to compile the row result parsing
// results in ~60% speedup on large query result sets
ctorBody += inlineParser(desc.name, i)
}
if(!this.rowAsArray) {
this.RowCtor = Function("parsers", "rowData", ctorBody);
if (!this.rowAsArray) {
this.RowCtor = Function('parsers', 'rowData', ctorBody)
}
};
}
Result.prototype._getTypeParser = types.getTypeParser;
Result.prototype._getTypeParser = types.getTypeParser
module.exports = Result;
module.exports = Result

View File

@ -1,3 +1,4 @@
'use strict'
/**
* Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
* All rights reserved.
@ -6,33 +7,33 @@
* README.md file in the root directory of this source tree.
*/
var types = require('pg-types');
var types = require('pg-types')
function TypeOverrides(userTypes) {
this._types = userTypes || types;
this.text = {};
this.binary = {};
function TypeOverrides (userTypes) {
this._types = userTypes || types
this.text = {}
this.binary = {}
}
TypeOverrides.prototype.getOverrides = function(format) {
switch(format) {
case 'text': return this.text;
case 'binary': return this.binary;
default: return {};
TypeOverrides.prototype.getOverrides = function (format) {
switch (format) {
case 'text': return this.text
case 'binary': return this.binary
default: return {}
}
};
}
TypeOverrides.prototype.setTypeParser = function(oid, format, parseFn) {
if(typeof format == 'function') {
parseFn = format;
format = 'text';
TypeOverrides.prototype.setTypeParser = function (oid, format, parseFn) {
if (typeof format === 'function') {
parseFn = format
format = 'text'
}
this.getOverrides(format)[oid] = parseFn;
};
this.getOverrides(format)[oid] = parseFn
}
TypeOverrides.prototype.getTypeParser = function(oid, format) {
format = format || 'text';
return this.getOverrides(format)[oid] || this._types.getTypeParser(oid, format);
};
TypeOverrides.prototype.getTypeParser = function (oid, format) {
format = format || 'text'
return this.getOverrides(format)[oid] || this._types.getTypeParser(oid, format)
}
module.exports = TypeOverrides;
module.exports = TypeOverrides

View File

@ -1,3 +1,4 @@
'use strict'
/**
* Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
* All rights reserved.
@ -6,162 +7,143 @@
* README.md file in the root directory of this source tree.
*/
var util = require('util');
const crypto = require('crypto')
var defaults = require('./defaults');
const defaults = require('./defaults')
function escapeElement(elementRepresentation) {
function escapeElement (elementRepresentation) {
var escaped = elementRepresentation
.replace(/\\/g, '\\\\')
.replace(/"/g, '\\"');
.replace(/"/g, '\\"')
return '"' + escaped + '"';
return '"' + escaped + '"'
}
// convert a JS array to a postgres array literal
// uses comma separator so won't work for types like box that use
// a different array separator.
function arrayString(val) {
var result = '{';
for (var i = 0 ; i < val.length; i++) {
if(i > 0) {
result = result + ',';
function arrayString (val) {
var result = '{'
for (var i = 0; i < val.length; i++) {
if (i > 0) {
result = result + ','
}
if(val[i] === null || typeof val[i] === 'undefined') {
result = result + 'NULL';
}
else if(Array.isArray(val[i])) {
result = result + arrayString(val[i]);
}
else if(val[i] instanceof Buffer) {
result += '\\\\x' + val[i].toString('hex');
}
else
{
result += escapeElement(prepareValue(val[i]));
}
}
result = result + '}';
return result;
}
//converts values from javascript types
//to their 'raw' counterparts for use as a postgres parameter
//note: you can override this function to provide your own conversion mechanism
//for complex types, etc...
var prepareValue = function(val, seen) {
if (val instanceof Buffer) {
return val;
}
if(val instanceof Date) {
if(defaults.parseInputDatesAsUTC) {
return dateToStringUTC(val);
if (val[i] === null || typeof val[i] === 'undefined') {
result = result + 'NULL'
} else if (Array.isArray(val[i])) {
result = result + arrayString(val[i])
} else if (val[i] instanceof Buffer) {
result += '\\\\x' + val[i].toString('hex')
} else {
return dateToString(val);
result += escapeElement(prepareValue(val[i]))
}
}
if(Array.isArray(val)) {
return arrayString(val);
}
if(val === null || typeof val === 'undefined') {
return null;
}
if(typeof val === 'object') {
return prepareObject(val, seen);
}
return val.toString();
};
result = result + '}'
return result
}
function prepareObject(val, seen) {
if(val.toPostgres && typeof val.toPostgres === 'function') {
seen = seen || [];
// converts values from javascript types
// to their 'raw' counterparts for use as a postgres parameter
// note: you can override this function to provide your own conversion mechanism
// for complex types, etc...
var prepareValue = function (val, seen) {
if (val instanceof Buffer) {
return val
}
if (val instanceof Date) {
if (defaults.parseInputDatesAsUTC) {
return dateToStringUTC(val)
} else {
return dateToString(val)
}
}
if (Array.isArray(val)) {
return arrayString(val)
}
if (val === null || typeof val === 'undefined') {
return null
}
if (typeof val === 'object') {
return prepareObject(val, seen)
}
return val.toString()
}
function prepareObject (val, seen) {
if (val.toPostgres && typeof val.toPostgres === 'function') {
seen = seen || []
if (seen.indexOf(val) !== -1) {
throw new Error('circular reference detected while preparing "' + val + '" for query');
throw new Error('circular reference detected while preparing "' + val + '" for query')
}
seen.push(val);
seen.push(val)
return prepareValue(val.toPostgres(prepareValue), seen);
return prepareValue(val.toPostgres(prepareValue), seen)
}
return JSON.stringify(val);
return JSON.stringify(val)
}
function pad(number, digits) {
number = "" +number;
while(number.length < digits)
number = "0" + number;
return number;
function pad (number, digits) {
number = '' + number
while (number.length < digits) { number = '0' + number }
return number
}
function dateToString(date) {
var offset = -date.getTimezoneOffset();
function dateToString (date) {
var offset = -date.getTimezoneOffset()
var ret = pad(date.getFullYear(), 4) + '-' +
pad(date.getMonth() + 1, 2) + '-' +
pad(date.getDate(), 2) + 'T' +
pad(date.getHours(), 2) + ':' +
pad(date.getMinutes(), 2) + ':' +
pad(date.getSeconds(), 2) + '.' +
pad(date.getMilliseconds(), 3);
pad(date.getMilliseconds(), 3)
if(offset < 0) {
ret += "-";
offset *= -1;
}
else
ret += "+";
if (offset < 0) {
ret += '-'
offset *= -1
} else { ret += '+' }
return ret + pad(Math.floor(offset/60), 2) + ":" + pad(offset%60, 2);
return ret + pad(Math.floor(offset / 60), 2) + ':' + pad(offset % 60, 2)
}
function dateToStringUTC(date) {
function dateToStringUTC (date) {
var ret = pad(date.getUTCFullYear(), 4) + '-' +
pad(date.getUTCMonth() + 1, 2) + '-' +
pad(date.getUTCDate(), 2) + 'T' +
pad(date.getUTCHours(), 2) + ':' +
pad(date.getUTCMinutes(), 2) + ':' +
pad(date.getUTCSeconds(), 2) + '.' +
pad(date.getUTCMilliseconds(), 3);
pad(date.getUTCMonth() + 1, 2) + '-' +
pad(date.getUTCDate(), 2) + 'T' +
pad(date.getUTCHours(), 2) + ':' +
pad(date.getUTCMinutes(), 2) + ':' +
pad(date.getUTCSeconds(), 2) + '.' +
pad(date.getUTCMilliseconds(), 3)
return ret + "+00:00";
return ret + '+00:00'
}
function normalizeQueryConfig (config, values, callback) {
//can take in strings or config objects
config = (typeof(config) == 'string') ? { text: config } : config;
if(values) {
if(typeof values === 'function') {
config.callback = values;
// can take in strings or config objects
config = (typeof (config) === 'string') ? { text: config } : config
if (values) {
if (typeof values === 'function') {
config.callback = values
} else {
config.values = values;
config.values = values
}
}
if(callback) {
config.callback = callback;
if (callback) {
config.callback = callback
}
return config;
return config
}
var queryEventEmitterOverloadDeprecationMessage = 'Using the automatically created return value from client.query as an event emitter is deprecated and will be removed in pg@7.0. Please see the upgrade guide at https://node-postgres.com/guides/upgrading';
var deprecateEventEmitter = function(Emitter) {
var Result = function () {
Emitter.apply(this, arguments);
};
util.inherits(Result, Emitter);
Result.prototype._on = Result.prototype.on;
Result.prototype._once = Result.prototype.once;
Result.prototype.on = util.deprecate(Result.prototype.on, queryEventEmitterOverloadDeprecationMessage);
Result.prototype.once = util.deprecate(Result.prototype.once, queryEventEmitterOverloadDeprecationMessage);
return Result;
};
const md5 = function (string) {
return crypto.createHash('md5').update(string, 'utf-8').digest('hex')
}
module.exports = {
prepareValue: function prepareValueWrapper (value) {
//this ensures that extra arguments do not get passed into prepareValue
//by accident, eg: from calling values.map(utils.prepareValue)
return prepareValue(value);
// this ensures that extra arguments do not get passed into prepareValue
// by accident, eg: from calling values.map(utils.prepareValue)
return prepareValue(value)
},
normalizeQueryConfig: normalizeQueryConfig,
deprecateEventEmitter: deprecateEventEmitter,
};
md5: md5
}

View File

@ -1,6 +1,6 @@
{
"name": "pg",
"version": "6.4.1",
"version": "6.2.4",
"description": "PostgreSQL client - pure javascript & libpq with the same API",
"keywords": [
"postgres",
@ -21,26 +21,28 @@
"buffer-writer": "1.0.1",
"packet-reader": "0.3.1",
"pg-connection-string": "0.1.3",
"pg-pool": "1.*",
"pg-pool": "2.*",
"pg-types": "1.*",
"pgpass": "1.*",
"pgpass": "1.x",
"semver": "4.3.2"
},
"devDependencies": {
"async": "0.9.0",
"co": "4.6.0",
"jshint": "2.5.2",
"lodash": "4.13.1",
"pg-copy-streams": "0.3.0",
"promise-polyfill": "5.2.1"
"eslint": "4.2.0",
"eslint-config-standard": "10.2.1",
"eslint-plugin-import": "2.7.0",
"eslint-plugin-node": "5.1.0",
"eslint-plugin-promise": "3.5.0",
"eslint-plugin-standard": "3.0.1",
"pg-copy-streams": "0.3.0"
},
"minNativeVersion": "1.7.0",
"minNativeVersion": "2.0.0",
"scripts": {
"changelog": "npm i github-changes && ./node_modules/.bin/github-changes -o brianc -r node-postgres -d pulls -a -v",
"test": "make test-all connectionString=postgres://postgres@localhost:5432/postgres"
"test": "make test-all"
},
"license": "MIT",
"engines": {
"node": ">= 0.8.0"
"node": ">= 4.0.0"
}
}

View File

@ -1,32 +1,33 @@
var args = require(__dirname + '/../test/cli');
var pg = require(__dirname + '/../lib');
'use strict'
var args = require(__dirname + '/../test/cli')
var pg = require(__dirname + '/../lib')
var people = [
{name: 'Aaron', age: 10},
{name: 'Brian', age: 20},
{name: 'Chris', age: 30},
{name: 'David', age: 40},
{name: 'Elvis', age: 50},
{name: 'Frank', age: 60},
{name: 'Grace', age: 70},
{name: 'Haley', age: 80},
{name: 'Irma', age: 90},
{name: 'Jenny', age: 100},
{name: 'Kevin', age: 110},
{name: 'Larry', age: 120},
{name: 'Aaron', age: 10},
{name: 'Brian', age: 20},
{name: 'Chris', age: 30},
{name: 'David', age: 40},
{name: 'Elvis', age: 50},
{name: 'Frank', age: 60},
{name: 'Grace', age: 70},
{name: 'Haley', age: 80},
{name: 'Irma', age: 90},
{name: 'Jenny', age: 100},
{name: 'Kevin', age: 110},
{name: 'Larry', age: 120},
{name: 'Michelle', age: 130},
{name: 'Nancy', age: 140},
{name: 'Olivia', age: 150},
{name: 'Peter', age: 160},
{name: 'Quinn', age: 170},
{name: 'Ronda', age: 180},
{name: 'Shelley', age: 190},
{name: 'Tobias', age: 200},
{name: 'Uma', age: 210},
{name: 'Veena', age: 220},
{name: 'Wanda', age: 230},
{name: 'Xavier', age: 240},
{name: 'Yoyo', age: 250},
{name: 'Nancy', age: 140},
{name: 'Olivia', age: 150},
{name: 'Peter', age: 160},
{name: 'Quinn', age: 170},
{name: 'Ronda', age: 180},
{name: 'Shelley', age: 190},
{name: 'Tobias', age: 200},
{name: 'Uma', age: 210},
{name: 'Veena', age: 220},
{name: 'Wanda', age: 230},
{name: 'Xavier', age: 240},
{name: 'Yoyo', age: 250},
{name: 'Zanzabar', age: 260}
]
@ -36,19 +37,16 @@ var con = new pg.Client({
user: args.user,
password: args.password,
database: args.database
});
con.connect();
var query = con.query("drop table if exists person");
query.on('end', function() {
console.log("Dropped table 'person'")
});
con.query("create table person(id serial, name varchar(10), age integer)").on('end', function(){
console.log("Created table person");
console.log("Filling it with people");
});
people.map(function(person) {
return con.query("insert into person(name, age) values('"+person.name + "', '" + person.age + "')");
}).pop().on('end', function(){
console.log("Inserted 26 people");
con.end();
});
})
con.connect()
var query = con.query('drop table if exists person')
con.query('create table person(id serial, name varchar(10), age integer)', (err, res) => {
console.log('Created table person')
console.log('Filling it with people')
})
people.map(function (person) {
return con.query(new pg.Query("insert into person(name, age) values('" + person.name + "', '" + person.age + "')"))
}).pop().on('end', function () {
console.log('Inserted 26 people')
con.end()
})

View File

@ -1,23 +1,23 @@
var pg = require(__dirname + '/../lib');
var args = require(__dirname + '/../test/cli');
'use strict'
var pg = require(__dirname + '/../lib')
var args = require(__dirname + '/../test/cli')
var queries = [
"select CURRENT_TIMESTAMP",
'select CURRENT_TIMESTAMP',
"select interval '1 day' + interval '1 hour'",
"select TIMESTAMP 'today'"];
queries.forEach(function(query) {
"select TIMESTAMP 'today'"]
queries.forEach(function (query) {
var client = new pg.Client({
user: args.user,
database: args.database,
password: args.password
});
client.connect();
})
client.connect()
client
.query(query)
.on('row', function(row) {
console.log(row);
client.end();
});
});
.on('row', function (row) {
console.log(row)
client.end()
})
})

View File

@ -1,6 +1,7 @@
var helper = require(__dirname + "/../test/integration/test-helper");
var pg = helper.pg;
pg.connect(helper.config, assert.success(function(client) {
var query = client.query('select oid, typname from pg_type where typtype = \'b\' order by oid');
query.on('row', console.log);
'use strict'
var helper = require(__dirname + '/../test/integration/test-helper')
var pg = helper.pg
pg.connect(helper.config, assert.success(function (client) {
var query = client.query('select oid, typname from pg_type where typtype = \'b\' order by oid')
query.on('row', console.log)
}))

View File

@ -1,69 +1,70 @@
BufferList = function() {
this.buffers = [];
};
var p = BufferList.prototype;
'use strict'
global.BufferList = function () {
this.buffers = []
}
var p = BufferList.prototype
p.add = function(buffer, front) {
this.buffers[front ? "unshift" : "push"](buffer);
return this;
};
p.add = function (buffer, front) {
this.buffers[front ? 'unshift' : 'push'](buffer)
return this
}
p.addInt16 = function(val, front) {
return this.add(Buffer([(val >>> 8),(val >>> 0)]),front);
};
p.addInt16 = function (val, front) {
return this.add(Buffer.from([(val >>> 8), (val >>> 0)]), front)
}
p.getByteLength = function(initial) {
return this.buffers.reduce(function(previous, current){
return previous + current.length;
},initial || 0);
};
p.getByteLength = function (initial) {
return this.buffers.reduce(function (previous, current) {
return previous + current.length
}, initial || 0)
}
p.addInt32 = function(val, first) {
return this.add(Buffer([
p.addInt32 = function (val, first) {
return this.add(Buffer.from([
(val >>> 24 & 0xFF),
(val >>> 16 & 0xFF),
(val >>> 8 & 0xFF),
(val >>> 0 & 0xFF)
]),first);
};
]), first)
}
p.addCString = function(val, front) {
var len = Buffer.byteLength(val);
var buffer = new Buffer(len+1);
buffer.write(val);
buffer[len] = 0;
return this.add(buffer, front);
};
p.addCString = function (val, front) {
var len = Buffer.byteLength(val)
var buffer = Buffer.alloc(len + 1)
buffer.write(val)
buffer[len] = 0
return this.add(buffer, front)
}
p.addChar = function(char, first) {
return this.add(Buffer(char,'utf8'), first);
};
p.addChar = function (char, first) {
return this.add(Buffer.from(char, 'utf8'), first)
}
p.join = function(appendLength, char) {
var length = this.getByteLength();
if(appendLength) {
this.addInt32(length+4, true);
return this.join(false, char);
p.join = function (appendLength, char) {
var length = this.getByteLength()
if (appendLength) {
this.addInt32(length + 4, true)
return this.join(false, char)
}
if(char) {
this.addChar(char, true);
length++;
if (char) {
this.addChar(char, true)
length++
}
var result = Buffer(length);
var index = 0;
this.buffers.forEach(function(buffer) {
buffer.copy(result, index, 0);
index += buffer.length;
});
return result;
};
var result = Buffer.alloc(length)
var index = 0
this.buffers.forEach(function (buffer) {
buffer.copy(result, index, 0)
index += buffer.length
})
return result
}
BufferList.concat = function() {
var total = new BufferList();
for(var i = 0; i < arguments.length; i++) {
total.add(arguments[i]);
BufferList.concat = function () {
var total = new BufferList()
for (var i = 0; i < arguments.length; i++) {
total.add(arguments[i])
}
return total.join();
};
return total.join()
}
module.exports = BufferList;
module.exports = BufferList

View File

@ -1,24 +1,25 @@
var ConnectionParameters = require(__dirname + '/../lib/connection-parameters');
var config = new ConnectionParameters(process.argv[2]);
'use strict'
var ConnectionParameters = require(__dirname + '/../lib/connection-parameters')
var config = new ConnectionParameters(process.argv[2])
for(var i = 0; i < process.argv.length; i++) {
switch(process.argv[i].toLowerCase()) {
case 'native':
config.native = true;
break;
case 'binary':
config.binary = true;
break;
case 'down':
config.down = true;
break;
default:
break;
for (var i = 0; i < process.argv.length; i++) {
switch (process.argv[i].toLowerCase()) {
case 'native':
config.native = true
break
case 'binary':
config.binary = true
break
case 'down':
config.down = true
break
default:
break
}
}
if(process.env['PG_TEST_NATIVE']) {
config.native = true;
if (process.env['PG_TEST_NATIVE']) {
config.native = true
}
module.exports = config;
module.exports = config

View File

@ -1,173 +1,208 @@
var helper = require(__dirname + '/../test-helper');
var pg = helper.pg;
'use strict'
var helper = require(__dirname + '/../test-helper')
var pg = helper.pg
var log = function() {
//console.log.apply(console, arguments);
}
var suite = new helper.Suite()
var sink = new helper.Sink(5, 10000, function() {
log("ending connection pool: %j", helper.config);
pg.end(helper.config);
});
test('api', function() {
log("connecting to %j", helper.config)
//test weird callback behavior with node-pool
pg.connect(helper.config, function(err) {
assert.isNull(err);
arguments[1].emit('drain');
arguments[2]();
});
pg.connect(helper.config, assert.calls(function(err, client, done) {
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))');
['the flaming lips', 'wolf parade', 'radiohead', 'bright eyes', 'the beach boys', 'dead black hearts'].forEach(function(bandName) {
var query = client.query("INSERT INTO band (name) VALUES ('"+ bandName +"')")
});
test('simple query execution',assert.calls( function() {
log("executing simple query")
client.query("SELECT * FROM band WHERE name = 'the beach boys'", assert.calls(function(err, result) {
assert.lengthIs(result.rows, 1)
assert.equal(result.rows.pop().name, 'the beach boys')
log("simple query executed")
}));
}))
test('prepared statement execution',assert.calls( function() {
log("executing prepared statement 1")
client.query('SELECT * FROM band WHERE name = $1', ['dead black hearts'],assert.calls( function(err, result) {
log("Prepared statement 1 finished")
assert.lengthIs(result.rows, 1);
assert.equal(result.rows.pop().name, 'dead black hearts');
}))
log("executing prepared statement two")
client.query('SELECT * FROM band WHERE name LIKE $1 ORDER BY name', ['the %'], assert.calls(function(err, result) {
log("prepared statement two finished")
assert.lengthIs(result.rows, 2);
assert.equal(result.rows.pop().name, 'the flaming lips');
assert.equal(result.rows.pop().name, 'the beach boys');
sink.add();
done();
}))
}))
}))
suite.test('pool callback behavior', done => {
// test weird callback behavior with node-pool
const pool = new pg.Pool()
pool.connect(function (err) {
assert(!err)
arguments[1].emit('drain')
arguments[2]()
pool.end(done)
})
})
test('executing nested queries', function() {
pg.connect(helper.config, assert.calls(function(err, client, done) {
assert.isNull(err);
log("connected for nested queriese")
client.query('select now as now from NOW()', assert.calls(function(err, result) {
assert.equal(new Date().getYear(), result.rows[0].now.getYear())
client.query('select now as now_again FROM NOW()', assert.calls(function() {
client.query('select * FROM NOW()', assert.calls(function() {
log('all nested queries recieved')
assert.ok('all queries hit')
sink.add();
done();
}))
}))
}))
}))
suite.test('callback API', done => {
const client = new helper.Client()
client.query('CREATE TEMP TABLE peep(name text)')
client.query('INSERT INTO peep(name) VALUES ($1)', ['brianc'])
const config = {
text: 'INSERT INTO peep(name) VALUES ($1)',
values: ['brian']
}
client.query(config)
client.query('INSERT INTO peep(name) VALUES ($1)', ['aaron'])
client.query('SELECT * FROM peep ORDER BY name', (err, res) => {
assert(!err)
assert.equal(res.rowCount, 3)
assert.deepEqual(res.rows, [
{
name: 'aaron'
},
{
name: 'brian'
},
{
name: 'brianc'
}
])
done()
})
client.connect(err => {
assert(!err)
client.once('drain', () => client.end())
})
})
test('raises error if cannot connect', function() {
var connectionString = "pg://sfalsdkf:asdf@localhost/ieieie";
log("trying to connect to invalid place for error")
pg.connect(connectionString, assert.calls(function(err, client, done) {
assert.ok(err, 'should have raised an error')
log("invalid connection supplied error to callback")
sink.add();
done();
}))
})
test("query errors are handled and do not bubble if callback is provded", function() {
pg.connect(helper.config, assert.calls(function(err, client, done) {
assert.isNull(err)
log("checking for query error")
client.query("SELECT OISDJF FROM LEIWLISEJLSE", assert.calls(function(err, result) {
assert.ok(err);
log("query error supplied error to callback")
sink.add();
done();
}))
}))
})
test('callback is fired once and only once', function() {
pg.connect(helper.config, assert.calls(function(err, client, done) {
assert.isNull(err);
client.query("CREATE TEMP TABLE boom(name varchar(10))");
var callCount = 0;
client.query([
"INSERT INTO boom(name) VALUES('hai')",
"INSERT INTO boom(name) VALUES('boom')",
"INSERT INTO boom(name) VALUES('zoom')",
].join(";"), function(err, callback) {
assert.equal(callCount++, 0, "Call count should be 0. More means this callback fired more than once.");
sink.add();
done();
suite.test('executing nested queries', function (done) {
const pool = new pg.Pool()
pool.connect(
assert.calls(function (err, client, release) {
assert(!err)
client.query(
'select now as now from NOW()',
assert.calls(function (err, result) {
assert.equal(new Date().getYear(), result.rows[0].now.getYear())
client.query(
'select now as now_again FROM NOW()',
assert.calls(function () {
client.query(
'select * FROM NOW()',
assert.calls(function () {
assert.ok('all queries hit')
release()
pool.end(done)
})
)
})
)
})
)
})
}))
)
})
test('can provide callback and config object', function() {
pg.connect(helper.config, assert.calls(function(err, client, done) {
assert.isNull(err);
client.query({
name: 'boom',
text: 'select NOW()'
}, assert.calls(function(err, result) {
assert.isNull(err);
assert.equal(result.rows[0].now.getYear(), new Date().getYear())
done();
}))
}))
suite.test('raises error if cannot connect', function () {
var connectionString = 'pg://sfalsdkf:asdf@localhost/ieieie'
const pool = new pg.Pool({ connectionString: connectionString })
pool.connect(
assert.calls(function (err, client, done) {
assert.ok(err, 'should have raised an error')
done()
})
)
})
test('can provide callback and config and parameters', function() {
pg.connect(helper.config, assert.calls(function(err, client, done) {
assert.isNull(err);
var config = {
text: 'select $1::text as val'
};
client.query(config, ['hi'], assert.calls(function(err, result) {
assert.isNull(err);
assert.equal(result.rows.length, 1);
assert.equal(result.rows[0].val, 'hi');
done();
}))
}))
suite.test('query errors are handled and do not bubble if callback is provded', function (done) {
const pool = new pg.Pool()
pool.connect(
assert.calls(function (err, client, release) {
assert(!err)
client.query(
'SELECT OISDJF FROM LEIWLISEJLSE',
assert.calls(function (err, result) {
assert.ok(err)
release()
pool.end(done)
})
)
})
)
}
)
suite.test('callback is fired once and only once', function (done) {
const pool = new pg.Pool()
pool.connect(
assert.calls(function (err, client, release) {
assert(!err)
client.query('CREATE TEMP TABLE boom(name varchar(10))')
var callCount = 0
client.query(
[
"INSERT INTO boom(name) VALUES('hai')",
"INSERT INTO boom(name) VALUES('boom')",
"INSERT INTO boom(name) VALUES('zoom')"
].join(';'),
function (err, callback) {
assert.equal(
callCount++,
0,
'Call count should be 0. More means this callback fired more than once.'
)
release()
pool.end(done)
}
)
})
)
})
test('null and undefined are both inserted as NULL', function() {
pg.connect(helper.config, assert.calls(function(err, client, done) {
assert.isNull(err);
client.query("CREATE TEMP TABLE my_nulls(a varchar(1), b varchar(1), c integer, d integer, e date, f date)");
client.query("INSERT INTO my_nulls(a,b,c,d,e,f) VALUES ($1,$2,$3,$4,$5,$6)", [ null, undefined, null, undefined, null, undefined ]);
client.query("SELECT * FROM my_nulls", assert.calls(function(err, result) {
assert.isNull(err);
assert.equal(result.rows.length, 1);
assert.isNull(result.rows[0].a);
assert.isNull(result.rows[0].b);
assert.isNull(result.rows[0].c);
assert.isNull(result.rows[0].d);
assert.isNull(result.rows[0].e);
assert.isNull(result.rows[0].f);
done();
}))
}))
suite.test('can provide callback and config object', function (done) {
const pool = new pg.Pool()
pool.connect(
assert.calls(function (err, client, release) {
assert(!err)
client.query(
{
name: 'boom',
text: 'select NOW()'
},
assert.calls(function (err, result) {
assert(!err)
assert.equal(result.rows[0].now.getYear(), new Date().getYear())
release()
pool.end(done)
})
)
})
)
})
suite.test('can provide callback and config and parameters', function (done) {
const pool = new pg.Pool()
pool.connect(
assert.calls(function (err, client, release) {
assert(!err)
var config = {
text: 'select $1::text as val'
}
client.query(
config,
['hi'],
assert.calls(function (err, result) {
assert(!err)
assert.equal(result.rows.length, 1)
assert.equal(result.rows[0].val, 'hi')
release()
pool.end(done)
})
)
})
)
})
suite.test('null and undefined are both inserted as NULL', function (done) {
const pool = new pg.Pool()
pool.connect(
assert.calls(function (err, client, release) {
assert(!err)
client.query(
'CREATE TEMP TABLE my_nulls(a varchar(1), b varchar(1), c integer, d integer, e date, f date)'
)
client.query(
'INSERT INTO my_nulls(a,b,c,d,e,f) VALUES ($1,$2,$3,$4,$5,$6)',
[null, undefined, null, undefined, null, undefined]
)
client.query(
'SELECT * FROM my_nulls',
assert.calls(function (err, result) {
assert(!err)
assert.equal(result.rows.length, 1)
assert.isNull(result.rows[0].a)
assert.isNull(result.rows[0].b)
assert.isNull(result.rows[0].c)
assert.isNull(result.rows[0].d)
assert.isNull(result.rows[0].e)
assert.isNull(result.rows[0].f)
pool.end(done)
release()
})
)
})
)
})

View File

@ -1,96 +1,99 @@
return;
var helper = require('./test-helper');
var Client = helper.Client;
'use strict'
var helper = require('./test-helper')
var Client = helper.Client
var conInfo = helper.config;
var suite = new helper.Suite()
function getConInfo(override) {
var newConInfo = {};
Object.keys(conInfo).forEach(function(k){
newConInfo[k] = conInfo[k];
});
Object.keys(override || {}).forEach(function(k){
newConInfo[k] = override[k];
});
return newConInfo;
var conInfo = helper.config
function getConInfo (override) {
var newConInfo = {}
Object.keys(conInfo).forEach(function (k) {
newConInfo[k] = conInfo[k]
})
Object.keys(override || {}).forEach(function (k) {
newConInfo[k] = override[k]
})
return newConInfo
}
function getAppName(conf, cb) {
var client = new Client(conf);
client.connect(assert.success(function(){
client.query('SHOW application_name', assert.success(function(res){
var appName = res.rows[0].application_name;
cb(appName);
client.end();
}));
}));
function getAppName (conf, cb) {
var client = new Client(conf)
client.connect(assert.success(function () {
client.query('SHOW application_name', assert.success(function (res) {
var appName = res.rows[0].application_name
cb(appName)
client.end()
}))
}))
}
test('No default appliation_name ', function(){
var conf = getConInfo();
getAppName(conf, function(res){
assert.strictEqual(res, '');
});
});
suite.test('No default appliation_name ', function (done) {
var conf = getConInfo()
getAppName({ }, function (res) {
assert.strictEqual(res, '')
done()
})
})
test('fallback_application_name is used', function(){
var fbAppName = 'this is my app';
suite.test('fallback_application_name is used', function (done) {
var fbAppName = 'this is my app'
var conf = getConInfo({
'fallback_application_name' : fbAppName
});
getAppName(conf, function(res){
assert.strictEqual(res, fbAppName);
});
});
'fallback_application_name': fbAppName
})
getAppName(conf, function (res) {
assert.strictEqual(res, fbAppName)
done()
})
})
test('application_name is used', function(){
var appName = 'some wired !@#$% application_name';
suite.test('application_name is used', function (done) {
var appName = 'some wired !@#$% application_name'
var conf = getConInfo({
'application_name' : appName
});
getAppName(conf, function(res){
assert.strictEqual(res, appName);
});
});
'application_name': appName
})
getAppName(conf, function (res) {
assert.strictEqual(res, appName)
done()
})
})
test('application_name has precedence over fallback_application_name', function(){
var appName = 'some wired !@#$% application_name';
var fbAppName = 'some other strange $$test$$ appname';
suite.test('application_name has precedence over fallback_application_name', function (done) {
var appName = 'some wired !@#$% application_name'
var fbAppName = 'some other strange $$test$$ appname'
var conf = getConInfo({
'application_name' : appName ,
'fallback_application_name' : fbAppName
});
getAppName(conf, function(res){
assert.strictEqual(res, appName);
});
});
'application_name': appName,
'fallback_application_name': fbAppName
})
getAppName(conf, function (res) {
assert.strictEqual(res, appName)
done()
})
})
test('application_name from connection string', function(){
var appName = 'my app';
var conParams = require(__dirname + '/../../../lib/connection-parameters');
var conf;
suite.test('application_name from connection string', function (done) {
var appName = 'my app'
var conParams = require(__dirname + '/../../../lib/connection-parameters')
var conf
if (process.argv[2]) {
conf = new conParams(process.argv[2]+'?application_name='+appName);
conf = new conParams(process.argv[2] + '?application_name=' + appName)
} else {
conf = 'postgres://?application_name='+appName;
conf = 'postgres://?application_name=' + appName
}
getAppName(conf, function(res){
assert.strictEqual(res, appName);
});
});
getAppName(conf, function (res) {
assert.strictEqual(res, appName)
done()
})
})
// TODO: make the test work for native client too
if (!helper.args.native) {
test('application_name is read from the env', function(){
var appName = process.env.PGAPPNAME = 'testest';
var conf = getConInfo({
'just some bla' : 'to fool the pool'
});
getAppName(conf, function(res){
delete process.env.PGAPPNAME;
assert.strictEqual(res, appName);
});
});
suite.test('application_name is read from the env', function (done) {
var appName = process.env.PGAPPNAME = 'testest'
getAppName({ }, function (res) {
delete process.env.PGAPPNAME
assert.strictEqual(res, appName)
done()
})
})
}

View File

@ -1,166 +1,177 @@
var helper = require(__dirname + "/test-helper");
var pg = helper.pg;
'use strict'
var helper = require(__dirname + '/test-helper')
var pg = helper.pg
test('serializing arrays', function() {
pg.connect(helper.config, assert.calls(function(err, client, done) {
assert.isNull(err);
var suite = new helper.Suite()
test('nulls', function() {
client.query('SELECT $1::text[] as array', [[null]], assert.success(function(result) {
var array = result.rows[0].array;
assert.lengthIs(array, 1);
assert.isNull(array[0]);
}));
});
const pool = new pg.Pool()
test('elements containing JSON-escaped characters', function() {
var param = '\\"\\"';
pool.connect(assert.calls(function (err, client, release) {
assert(!err)
for (var i = 1; i <= 0x1f; i++) {
param += String.fromCharCode(i);
}
suite.test('nulls', function (done) {
client.query('SELECT $1::text[] as array', [[null]], assert.success(function (result) {
var array = result.rows[0].array
assert.lengthIs(array, 1)
assert.isNull(array[0])
done()
}))
})
client.query('SELECT $1::text[] as array', [[param]], assert.success(function(result) {
var array = result.rows[0].array;
assert.lengthIs(array, 1);
assert.equal(array[0], param);
}));
suite.test('elements containing JSON-escaped characters', function (done) {
var param = '\\"\\"'
done();
});
}));
});
for (var i = 1; i <= 0x1f; i++) {
param += String.fromCharCode(i)
}
test('parsing array results', function() {
pg.connect(helper.config, assert.calls(function(err, client, done) {
assert.isNull(err);
client.query("CREATE TEMP TABLE why(names text[], numbors integer[])");
client.query('INSERT INTO why(names, numbors) VALUES(\'{"aaron", "brian","a b c" }\', \'{1, 2, 3}\')').on('error', console.log);
test('numbers', function() {
client.query('SELECT $1::text[] as array', [[param]], assert.success(function (result) {
var array = result.rows[0].array
assert.lengthIs(array, 1)
assert.equal(array[0], param)
done()
}))
})
suite.test('cleanup', () => release())
pool.connect(assert.calls(function (err, client, release) {
assert(!err)
client.query('CREATE TEMP TABLE why(names text[], numbors integer[])')
client.query(new pg.Query('INSERT INTO why(names, numbors) VALUES(\'{"aaron", "brian","a b c" }\', \'{1, 2, 3}\')')).on('error', console.log)
suite.test('numbers', function (done) {
// client.connection.on('message', console.log)
client.query('SELECT numbors FROM why', assert.success(function(result) {
assert.lengthIs(result.rows[0].numbors, 3);
assert.equal(result.rows[0].numbors[0], 1);
assert.equal(result.rows[0].numbors[1], 2);
assert.equal(result.rows[0].numbors[2], 3);
client.query('SELECT numbors FROM why', assert.success(function (result) {
assert.lengthIs(result.rows[0].numbors, 3)
assert.equal(result.rows[0].numbors[0], 1)
assert.equal(result.rows[0].numbors[1], 2)
assert.equal(result.rows[0].numbors[2], 3)
done()
}))
})
test('parses string arrays', function() {
client.query('SELECT names FROM why', assert.success(function(result) {
var names = result.rows[0].names;
assert.lengthIs(names, 3);
assert.equal(names[0], 'aaron');
assert.equal(names[1], 'brian');
assert.equal(names[2], "a b c");
}))
})
test('empty array', function(){
client.query("SELECT '{}'::text[] as names", assert.success(function(result) {
var names = result.rows[0].names;
assert.lengthIs(names, 0);
suite.test('parses string arrays', function (done) {
client.query('SELECT names FROM why', assert.success(function (result) {
var names = result.rows[0].names
assert.lengthIs(names, 3)
assert.equal(names[0], 'aaron')
assert.equal(names[1], 'brian')
assert.equal(names[2], 'a b c')
done()
}))
})
test('element containing comma', function(){
client.query("SELECT '{\"joe,bob\",jim}'::text[] as names", assert.success(function(result) {
var names = result.rows[0].names;
assert.lengthIs(names, 2);
assert.equal(names[0], 'joe,bob');
assert.equal(names[1], 'jim');
suite.test('empty array', function (done) {
client.query("SELECT '{}'::text[] as names", assert.success(function (result) {
var names = result.rows[0].names
assert.lengthIs(names, 0)
done()
}))
})
test('bracket in quotes', function(){
client.query("SELECT '{\"{\",\"}\"}'::text[] as names", assert.success(function(result) {
var names = result.rows[0].names;
assert.lengthIs(names, 2);
assert.equal(names[0], '{');
assert.equal(names[1], '}');
suite.test('element containing comma', function (done) {
client.query("SELECT '{\"joe,bob\",jim}'::text[] as names", assert.success(function (result) {
var names = result.rows[0].names
assert.lengthIs(names, 2)
assert.equal(names[0], 'joe,bob')
assert.equal(names[1], 'jim')
done()
}))
})
test('null value', function(){
client.query("SELECT '{joe,null,bob,\"NULL\"}'::text[] as names", assert.success(function(result) {
var names = result.rows[0].names;
assert.lengthIs(names, 4);
assert.equal(names[0], 'joe');
assert.equal(names[1], null);
assert.equal(names[2], 'bob');
assert.equal(names[3], 'NULL');
suite.test('bracket in quotes', function (done) {
client.query("SELECT '{\"{\",\"}\"}'::text[] as names", assert.success(function (result) {
var names = result.rows[0].names
assert.lengthIs(names, 2)
assert.equal(names[0], '{')
assert.equal(names[1], '}')
done()
}))
})
test('element containing quote char', function(){
client.query("SELECT ARRAY['joe''', 'jim', 'bob\"'] AS names", assert.success(function(result) {
var names = result.rows[0].names;
assert.lengthIs(names, 3);
assert.equal(names[0], 'joe\'');
assert.equal(names[1], 'jim');
assert.equal(names[2], 'bob"');
suite.test('null value', function (done) {
client.query("SELECT '{joe,null,bob,\"NULL\"}'::text[] as names", assert.success(function (result) {
var names = result.rows[0].names
assert.lengthIs(names, 4)
assert.equal(names[0], 'joe')
assert.equal(names[1], null)
assert.equal(names[2], 'bob')
assert.equal(names[3], 'NULL')
done()
}))
})
test('nested array', function(){
client.query("SELECT '{{1,joe},{2,bob}}'::text[] as names", assert.success(function(result) {
var names = result.rows[0].names;
assert.lengthIs(names, 2);
assert.lengthIs(names[0], 2);
assert.equal(names[0][0], '1');
assert.equal(names[0][1], 'joe');
assert.lengthIs(names[1], 2);
assert.equal(names[1][0], '2');
assert.equal(names[1][1], 'bob');
suite.test('element containing quote char', function (done) {
client.query("SELECT ARRAY['joe''', 'jim', 'bob\"'] AS names", assert.success(function (result) {
var names = result.rows[0].names
assert.lengthIs(names, 3)
assert.equal(names[0], 'joe\'')
assert.equal(names[1], 'jim')
assert.equal(names[2], 'bob"')
done()
}))
})
test('integer array', function(){
client.query("SELECT '{1,2,3}'::integer[] as names", assert.success(function(result) {
var names = result.rows[0].names;
assert.lengthIs(names, 3);
assert.equal(names[0], 1);
assert.equal(names[1], 2);
assert.equal(names[2], 3);
suite.test('nested array', function (done) {
client.query("SELECT '{{1,joe},{2,bob}}'::text[] as names", assert.success(function (result) {
var names = result.rows[0].names
assert.lengthIs(names, 2)
assert.lengthIs(names[0], 2)
assert.equal(names[0][0], '1')
assert.equal(names[0][1], 'joe')
assert.lengthIs(names[1], 2)
assert.equal(names[1][0], '2')
assert.equal(names[1][1], 'bob')
done()
}))
})
test('integer nested array', function(){
client.query("SELECT '{{1,100},{2,100},{3,100}}'::integer[] as names", assert.success(function(result) {
var names = result.rows[0].names;
assert.lengthIs(names, 3);
assert.equal(names[0][0], 1);
assert.equal(names[0][1], 100);
assert.equal(names[1][0], 2);
assert.equal(names[1][1], 100);
assert.equal(names[2][0], 3);
assert.equal(names[2][1], 100);
suite.test('integer array', function (done) {
client.query("SELECT '{1,2,3}'::integer[] as names", assert.success(function (result) {
var names = result.rows[0].names
assert.lengthIs(names, 3)
assert.equal(names[0], 1)
assert.equal(names[1], 2)
assert.equal(names[2], 3)
done()
}))
})
test('JS array parameter', function(){
client.query("SELECT $1::integer[] as names", [[[1,100],[2,100],[3,100]]], assert.success(function(result) {
var names = result.rows[0].names;
assert.lengthIs(names, 3);
assert.equal(names[0][0], 1);
assert.equal(names[0][1], 100);
assert.equal(names[1][0], 2);
assert.equal(names[1][1], 100);
suite.test('integer nested array', function (done) {
client.query("SELECT '{{1,100},{2,100},{3,100}}'::integer[] as names", assert.success(function (result) {
var names = result.rows[0].names
assert.lengthIs(names, 3)
assert.equal(names[0][0], 1)
assert.equal(names[0][1], 100)
assert.equal(names[2][0], 3);
assert.equal(names[2][1], 100);
done();
pg.end();
assert.equal(names[1][0], 2)
assert.equal(names[1][1], 100)
assert.equal(names[2][0], 3)
assert.equal(names[2][1], 100)
done()
}))
})
suite.test('JS array parameter', function (done) {
client.query('SELECT $1::integer[] as names', [[[1, 100], [2, 100], [3, 100]]], assert.success(function (result) {
var names = result.rows[0].names
assert.lengthIs(names, 3)
assert.equal(names[0][0], 1)
assert.equal(names[0][1], 100)
assert.equal(names[1][0], 2)
assert.equal(names[1][1], 100)
assert.equal(names[2][0], 3)
assert.equal(names[2][1], 100)
release()
pool.end(() => {
done()
})
}))
})
}))
})
}))

File diff suppressed because one or more lines are too long

View File

@ -1,40 +0,0 @@
var helper = require(__dirname+"/test-helper");
//before running this test make sure you run the script create-test-tables
test("cancellation of a query", function() {
var client = helper.client();
var qry = "select name from person order by name";
client.on('drain', client.end.bind(client));
var rows3 = 0;
var query1 = client.query(qry);
query1.on('row', function(row) {
throw new Error('Should not emit a row')
});
var query2 = client.query(qry);
query2.on('row', function(row) {
throw new Error('Should not emit a row')
});
var query3 = client.query(qry);
query3.on('row', function(row) {
rows3++;
});
var query4 = client.query(qry);
query4.on('row', function(row) {
throw new Error('Should not emit a row')
});
helper.pg.cancel(helper.config, client, query1);
helper.pg.cancel(helper.config, client, query2);
helper.pg.cancel(helper.config, client, query4);
assert.emits(query3, 'end', function() {
test("returned right number of rows", function() {
assert.equal(rows3, 26);
});
});
});

View File

@ -1,15 +1,18 @@
var helper = require(__dirname + '/test-helper');
var pg = helper.pg;
'use strict'
var helper = require('./test-helper')
var pg = helper.pg
//clear process.env
var realEnv = {};
for(var key in process.env) {
realEnv[key] = process.env[key];
if(!key.indexOf('PG')) delete process.env[key];
var suite = new helper.Suite()
// clear process.env
var realEnv = {}
for (var key in process.env) {
realEnv[key] = process.env[key]
if (!key.indexOf('PG')) delete process.env[key]
}
test('default values', function() {
assert.same(pg.defaults,{
suite.test('default values are used in new clients', function () {
assert.same(pg.defaults, {
user: process.env.USER,
database: process.env.USER,
password: null,
@ -17,42 +20,36 @@ test('default values', function() {
rows: 0,
poolSize: 10
})
test('are used in new clients', function() {
var client = new pg.Client();
assert.same(client,{
user: process.env.USER,
database: process.env.USER,
password: null,
port: 5432
})
var client = new pg.Client()
assert.same(client, {
user: process.env.USER,
database: process.env.USER,
password: null,
port: 5432
})
})
if(!helper.args.native) {
test('modified values', function() {
pg.defaults.user = 'boom'
pg.defaults.password = 'zap'
pg.defaults.database = 'pow'
pg.defaults.port = 1234
pg.defaults.host = 'blam'
pg.defaults.rows = 10
pg.defaults.poolSize = 0
suite.test('modified values are passed to created clients', function () {
pg.defaults.user = 'boom'
pg.defaults.password = 'zap'
pg.defaults.database = 'pow'
pg.defaults.port = 1234
pg.defaults.host = 'blam'
test('are passed into created clients', function() {
var client = new Client();
assert.same(client,{
user: 'boom',
password: 'zap',
database: 'pow',
port: 1234,
host: 'blam'
})
})
var client = new Client()
assert.same(client, {
user: 'boom',
password: 'zap',
database: 'pow',
port: 1234,
host: 'blam'
})
}
})
//restore process.env
for(var key in realEnv) {
process.env[key] = realEnv[key];
}
suite.test('cleanup', () => {
// restore process.env
for (var key in realEnv) {
process.env[key] = realEnv[key]
}
})

View File

@ -1,18 +1,20 @@
var helper = require(__dirname + '/test-helper');
return console.log('TODO: get this working for non-native client');
'use strict'
const helper = require('./test-helper')
const Client = helper.pg.Client
const suite = new helper.Suite()
helper.config.types = {
getTypeParser: function() {
return function() {
return 'okay!'
}
const client = new Client({
types: {
getTypeParser: () => () => 'okay!'
}
};
})
helper.pg.connect(helper.config, assert.success(function(client, done) {
client.query('SELECT NOW() as val', assert.success(function(res) {
assert.equal(res.rows[0].val, 'okay!');
done();
helper.pg.end();
}));
}));
suite.test('custom type parser in client config', (done) => {
client.connect()
.then(() => {
client.query('SELECT NOW() as val', assert.success(function (res) {
assert.equal(res.rows[0].val, 'okay!')
client.end().then(done)
}))
})
})

View File

@ -1,23 +0,0 @@
var helper = require('./test-helper')
process.on('warning', function (warning) {
console.log(warning)
throw new Error('Should not emit deprecation warning')
})
var client = new helper.pg.Client()
client.connect(function (err) {
if (err) throw err
client.query('SELECT NOW()')
.then(function (res) {
client.query('SELECT NOW()', function () {
client.end(function () {
})
})
}).catch(function (err) {
setImmediate(function () {
throw err
})
})
})

View File

@ -1,17 +1,20 @@
var helper = require(__dirname+'/test-helper');
var client = helper.client();
'use strict'
var helper = require('./test-helper')
const suite = new helper.Suite()
test("empty query message handling", function() {
assert.emits(client, 'drain', function() {
client.end();
});
client.query({text: ""});
});
test('callback supported', assert.calls(function() {
client.query("", function(err, result) {
assert.isNull(err);
assert.empty(result.rows);
suite.test('empty query message handling', function (done) {
const client = helper.client()
assert.emits(client, 'drain', function () {
client.end(done)
})
}))
client.query({text: ''})
})
suite.test('callback supported', function (done) {
const client = helper.client()
client.query('', function (err, result) {
assert(!err)
assert.empty(result.rows)
client.end(done)
})
})

View File

@ -1,6 +0,0 @@
var helper = require('./test-helper')
var client = helper.client(assert.success(function() {
client.end(assert.success(function() {
}))
}))

View File

@ -1,197 +1,204 @@
var helper = require(__dirname + '/test-helper');
var util = require('util');
'use strict'
var helper = require('./test-helper')
var util = require('util')
test('non-query error with callback', function () {
var client = new Client({
user:'asldkfjsadlfkj'
});
client.connect(assert.calls(function (err) {
assert(err);
}));
});
var pg = helper.pg
const Client = pg.Client
test('non-query error', function() {
var client = new Client({
user:'asldkfjsadlfkj'
});
assert.emits(client, 'error');
client.connect();
});
var createErorrClient = function () {
var client = helper.client()
client.once('error', function (err) {
assert.fail('Client shoud not throw error during query execution')
})
client.on('drain', client.end.bind(client))
return client
}
var createErorrClient = function() {
var client = helper.client();
client.once('error', function(err) {
//console.log('error', util.inspect(err));
assert.fail('Client shoud not throw error during query execution');
});
client.on('drain', client.end.bind(client));
return client;
};
const suite = new helper.Suite('error handling')
test('error handling', function() {
test('within a simple query', function() {
var client = createErorrClient();
suite.test('sending non-array argument as values causes an error callback', (done) => {
const client = new Client()
client.connect(() => {
client.query('select $1::text as name', 'foo', (err) => {
assert(err instanceof Error)
client.query('SELECT $1::text as name', ['foo'], (err, res) => {
assert.equal(res.rows[0].name, 'foo')
client.end(done)
})
})
})
})
var query = client.query("select omfg from yodas_dsflsd where pixistix = 'zoiks!!!'");
suite.test('re-using connections results in error callback', (done) => {
const client = new Client()
client.connect(() => {
client.connect(err => {
assert(err instanceof Error)
client.end(done)
})
})
})
assert.emits(query, 'error', function(error) {
assert.equal(error.severity, "ERROR");
});
});
suite.test('re-using connections results in promise rejection', (done) => {
const client = new Client()
client.connect().then(() => {
client.connect().catch(err => {
assert(err instanceof Error)
client.end().then(done)
})
})
})
test('within a prepared statement', function() {
suite.test('query receives error on client shutdown', function (done) {
var client = new Client()
client.connect(assert.success(function () {
const config = {
text: 'select pg_sleep(5)',
name: 'foobar'
}
let queryError
client.query(new pg.Query(config), assert.calls(function (err, res) {
assert(err instanceof Error)
queryError = err
}))
setTimeout(() => client.end(), 50)
client.once('end', () => {
assert(queryError instanceof Error)
done()
})
}))
})
var client = createErorrClient();
var ensureFuture = function (testClient, done) {
var goodQuery = testClient.query(new pg.Query('select age from boom'))
assert.emits(goodQuery, 'row', function (row) {
assert.equal(row.age, 28)
done()
})
}
var q = client.query({text: "CREATE TEMP TABLE boom(age integer); INSERT INTO boom (age) VALUES (28);", binary: false});
suite.test('when query is parsing', (done) => {
var client = createErorrClient()
test("when query is parsing", function() {
var q = client.query({ text: 'CREATE TEMP TABLE boom(age integer); INSERT INTO boom (age) VALUES (28);' })
//this query wont parse since there ain't no table named bang
// this query wont parse since there isn't a table named bang
var query = client.query(new pg.Query({
text: 'select * from bang where name = $1',
values: ['0']
}))
var ensureFuture = function(testClient) {
test("client can issue more queries successfully", function() {
var goodQuery = testClient.query("select age from boom");
assert.emits(goodQuery, 'row', function(row) {
assert.equal(row.age, 28);
});
});
};
assert.emits(query, 'error', function (err) {
ensureFuture(client, done)
})
})
var query = client.query({
text: "select * from bang where name = $1",
values: ['0']
});
suite.test('when a query is binding', function (done) {
var client = createErorrClient()
test("query emits the error", function() {
assert.emits(query, 'error', function(err) {
ensureFuture(client);
});
});
var q = client.query({ text: 'CREATE TEMP TABLE boom(age integer); INSERT INTO boom (age) VALUES (28);' })
test("when a query is binding", function() {
var query = client.query(new pg.Query({
text: 'select * from boom where age = $1',
values: ['asldkfjasdf']
}))
var query = client.query({
text: 'select * from boom where age = $1',
values: ['asldkfjasdf']
});
assert.emits(query, 'error', function (err) {
assert.equal(err.severity, 'ERROR')
ensureFuture(client, done)
})
})
test("query emits the error", function() {
suite.test('non-query error with callback', function (done) {
var client = new Client({
user: 'asldkfjsadlfkj'
})
client.connect(assert.calls(function (error, client) {
assert(error instanceof Error)
done()
}))
})
assert.emits(query, 'error', function(err) {
test('error has right severity', function() {
assert.equal(err.severity, "ERROR");
})
ensureFuture(client);
});
});
//TODO how to test for errors during execution?
});
});
});
test('non-query error', function() {
var client = new Client({
user:'asldkfjsadlfkj'
});
assert.emits(client, 'error');
client.connect();
});
test('non-query error with callback', function() {
var client = new Client({
user:'asldkfjsadlfkj'
});
client.connect(assert.calls(function(error, client) {
assert.ok(error);
}));
});
});
test('non-error calls supplied callback', function() {
suite.test('non-error calls supplied callback', function (done) {
var client = new Client({
user: helper.args.user,
password: helper.args.password,
host: helper.args.host,
port: helper.args.port,
database: helper.args.database
});
client.connect(assert.calls(function(err) {
assert.ifError(err);
client.end();
}))
});
test('when connecting to invalid host', function() {
//this test fails about 30% on travis and only on travis...
//I'm not sure what the cause could be
if(process.env.TRAVIS) return false;
var client = new Client({
user: 'aslkdjfsdf',
password: '1234',
host: 'asldkfjasdf!!#1308140.com'
});
var delay = 5000;
var tid = setTimeout(function() {
var msg = "When connecting to an invalid host the error event should be emitted but it has been " + delay + " and still no error event."
assert(false, msg);
}, delay);
client.on('error', function() {
clearTimeout(tid);
})
client.connect();
});
test('when connecting to invalid host with callback', function() {
client.connect(assert.calls(function (err) {
assert.ifError(err)
client.end(done)
}))
})
suite.test('when connecting to an invalid host with callback', function (done) {
var client = new Client({
user: 'brian',
password: '1234',
host: 'asldkfjasdf!!#1308140.com'
});
client.connect(function(error, client) {
assert(error);
});
});
user: 'very invalid username'
})
client.connect(function (error, client) {
assert(error instanceof Error)
done()
})
})
test('multiple connection errors (gh#31)', function() {
return false;
test('with single client', function() {
//don't run yet...this test fails...need to think of fix
var client = new Client({
user: 'blaksdjf',
password: 'omfsadfas',
host: helper.args.host,
port: helper.args.port,
database: helper.args.database
});
client.connect();
assert.emits(client, 'error', function(e) {
client.connect();
assert.emits(client, 'error');
});
});
suite.test('when connecting to invalid host with promise', function (done) {
var client = new Client({
user: 'very invalid username'
})
client.connect().catch((e) => done())
})
test('with callback method', function() {
var badConString = "postgres://aslkdfj:oi14081@"+helper.args.host+":"+helper.args.port+"/"+helper.args.database;
return false;
});
});
suite.test('non-query error', function (done) {
var client = new Client({
user: 'asldkfjsadlfkj'
})
client.connect()
.catch(e => {
assert(e instanceof Error)
done()
})
})
test('query receives error on client shutdown', function() {
var client = new Client(helper.config);
client.connect(assert.calls(function() {
client.query('SELECT pg_sleep(5)', assert.calls(function(err, res) {
assert(err);
}));
client.end();
assert.emits(client, 'end');
}));
});
suite.test('within a simple query', (done) => {
var client = createErorrClient()
var query = client.query(new pg.Query("select eeeee from yodas_dsflsd where pixistix = 'zoiks!!!'"))
assert.emits(query, 'error', function (error) {
assert.equal(error.severity, 'ERROR')
done()
})
})
suite.test('connected, idle client error', (done) => {
const client = new Client()
client.connect((err) => {
if (err) {
throw new Error('Should not receive error callback after connection')
}
setImmediate(() => {
(client.connection || client.native).emit('error', new Error('expected'))
})
})
client.on('error', (err) => {
assert.equal(err.message, 'expected')
client.end(done)
})
})
suite.test('cannot pass non-string values to query as text', (done) => {
const client = new Client()
client.connect()
client.query({ text: { } }, (err) => {
assert(err)
client.query({ }, (err) => {
client.on('drain', () => {
client.end(done)
})
})
})
})

View File

@ -1,39 +0,0 @@
return;
/**
* helper needs to be loaded for the asserts but it alos proloads
* client which we don't want here
*
*/
var helper = require(__dirname+"/test-helper")
, path = require('path')
;
var paths = {
'pg' : path.join(__dirname, '..', '..', '..', 'lib', 'index.js') ,
'query_js' : path.join(__dirname, '..', '..', '..', 'lib', 'query.js') ,
'query_native' : path.join(__dirname, '..', '..', '..', 'lib', 'native', 'query.js') ,
};
/**
* delete the modules we are concerned about from the
* module cache, so they get loaded cleanly and the env
* var can kick in ...
*/
function emptyCache(){
Object.keys(require.cache).forEach(function(key){
delete require.cache[key];
});
};
emptyCache();
process.env.NODE_PG_FORCE_NATIVE = '1';
var pg = require( paths.pg );
var query_native = require( paths.query_native );
var query_js = require( paths.query_js );
assert.deepEqual(pg.Client.Query, query_native);
assert.notDeepEqual(pg.Client.Query, query_js);
emptyCache();
delete process.env.NODE_PG_FORCE_NATIVE

View File

@ -1,22 +1,22 @@
var helper = require(__dirname + '/test-helper');
'use strict'
var helper = require('./test-helper')
const pool = new helper.pg.Pool()
helper.pg.connect(helper.config, assert.success(function(client, done) {
var types = require('pg-types');
//1231 = numericOID
types.setTypeParser(1700, function(){
return 'yes';
pool.connect(assert.success(function (client, done) {
var types = require('pg-types')
// 1231 = numericOID
types.setTypeParser(1700, function () {
return 'yes'
})
types.setTypeParser(1700, 'binary', function(){
return 'yes';
types.setTypeParser(1700, 'binary', function () {
return 'yes'
})
var bignum = '294733346389144765940638005275322203805';
client.query('CREATE TEMP TABLE bignumz(id numeric)');
client.query('INSERT INTO bignumz(id) VALUES ($1)', [bignum]);
client.query('SELECT * FROM bignumz', assert.success(function(result) {
var bignum = '294733346389144765940638005275322203805'
client.query('CREATE TEMP TABLE bignumz(id numeric)')
client.query('INSERT INTO bignumz(id) VALUES ($1)', [bignum])
client.query('SELECT * FROM bignumz', assert.success(function (result) {
assert.equal(result.rows[0].id, 'yes')
helper.pg.end();
done();
done()
pool.end()
}))
}));
//custom type converter
}))

View File

@ -1,38 +1,28 @@
var helper = require(__dirname + '/test-helper');
var assert = require('assert');
//if you want binary support, pull request me!
if (helper.config.binary) {
console.log('binary mode does not support JSON right now');
return;
}
'use strict'
var helper = require('./test-helper')
var assert = require('assert')
test('can read and write json', function() {
helper.pg.connect(helper.config, function(err, client, done) {
assert.ifError(err);
helper.versionGTE(client, '9.2.0', assert.success(function(jsonSupported) {
if(!jsonSupported) {
console.log('skip json test on older versions of postgres');
done();
return helper.pg.end();
}
client.query('CREATE TEMP TABLE stuff(id SERIAL PRIMARY KEY, data JSON)');
var value ={name: 'Brian', age: 250, alive: true, now: new Date()};
client.query('INSERT INTO stuff (data) VALUES ($1)', [value]);
client.query('SELECT * FROM stuff', assert.success(function(result) {
assert.equal(result.rows.length, 1);
assert.equal(typeof result.rows[0].data, 'object');
var row = result.rows[0].data;
assert.strictEqual(row.name, value.name);
assert.strictEqual(row.age, value.age);
assert.strictEqual(row.alive, value.alive);
test('row should have "now" as a date', function() {
return false;
assert(row.now instanceof Date, 'row.now should be a date instance but is ' + typeof row.now);
});
assert.equal(JSON.stringify(row.now), JSON.stringify(value.now));
done();
helper.pg.end();
}));
}));
});
});
const pool = new helper.pg.Pool()
pool.connect(assert.success(function (client, done) {
helper.versionGTE(client, '9.2.0', assert.success(function (jsonSupported) {
if (!jsonSupported) {
console.log('skip json test on older versions of postgres')
done()
return pool.end()
}
client.query('CREATE TEMP TABLE stuff(id SERIAL PRIMARY KEY, data JSON)')
var value = { name: 'Brian', age: 250, alive: true, now: new Date() }
client.query('INSERT INTO stuff (data) VALUES ($1)', [value])
client.query('SELECT * FROM stuff', assert.success(function (result) {
assert.equal(result.rows.length, 1)
assert.equal(typeof result.rows[0].data, 'object')
var row = result.rows[0].data
assert.strictEqual(row.name, value.name)
assert.strictEqual(row.age, value.age)
assert.strictEqual(row.alive, value.alive)
assert.equal(JSON.stringify(row.now), JSON.stringify(value.now))
done()
pool.end()
}))
}))
}))

View File

@ -0,0 +1,69 @@
'use strict'
const assert = require('assert')
const co = require('co')
const helper = require('./test-helper')
const suite = new helper.Suite('multiple result sets')
suite.test('two select results work', co.wrap(function * () {
const client = new helper.Client()
yield client.connect()
const results = yield client.query(`SELECT 'foo'::text as name; SELECT 'bar'::text as baz`)
assert(Array.isArray(results))
assert.equal(results[0].fields[0].name, 'name')
assert.deepEqual(results[0].rows, [{ name: 'foo' }])
assert.equal(results[1].fields[0].name, 'baz')
assert.deepEqual(results[1].rows, [{ baz: 'bar' }])
return client.end()
}))
suite.test('multiple selects work', co.wrap(function * () {
const client = new helper.Client()
yield client.connect()
const text = `
SELECT * FROM generate_series(2, 4) as foo;
SELECT * FROM generate_series(8, 10) as bar;
SELECT * FROM generate_series(20, 22) as baz;
`
const results = yield client.query(text)
assert(Array.isArray(results))
assert.equal(results[0].fields[0].name, 'foo')
assert.deepEqual(results[0].rows, [{ foo: 2 }, { foo: 3 }, { foo: 4 }])
assert.equal(results[1].fields[0].name, 'bar')
assert.deepEqual(results[1].rows, [{ bar: 8 }, { bar: 9 }, { bar: 10 }])
assert.equal(results[2].fields[0].name, 'baz')
assert.deepEqual(results[2].rows, [{ baz: 20 }, { baz: 21 }, { baz: 22 }])
assert.equal(results.length, 3)
return client.end()
}))
suite.test('mixed queries and statements', co.wrap(function * () {
const client = new helper.Client()
yield client.connect()
const text = `
CREATE TEMP TABLE weather(type text);
INSERT INTO weather(type) VALUES ('rain');
SELECT * FROM weather;
`
const results = yield client.query(text)
assert(Array.isArray(results))
assert.equal(results[0].command, 'CREATE')
assert.equal(results[1].command, 'INSERT')
assert.equal(results[2].command, 'SELECT')
return client.end()
}))

View File

@ -1,11 +1,11 @@
var co = require('co')
'use strict'
var buffers = require('../../test-buffers')
var helper = require('./test-helper')
var suite = new helper.Suite()
var net = require('net')
var Server = function(response) {
var Server = function (response) {
this.server = undefined
this.socket = undefined
this.response = response
@ -38,7 +38,7 @@ Server.prototype.start = function (cb) {
var options = {
host: 'localhost',
port: port,
port: port
}
this.server.listen(options.port, options.host, function () {
cb(options)
@ -55,13 +55,18 @@ Server.prototype.close = function (cb) {
var testServer = function (server, cb) {
// wait for our server to start
server.start(function(options) {
server.start(function (options) {
// connect a client to it
var client = new helper.Client(options)
client.connect()
.catch((err) => {
assert(err instanceof Error)
clearTimeout(timeoutId)
server.close(cb)
})
// after 50 milliseconds, drop the client
setTimeout(function() {
setTimeout(function () {
server.drop()
}, 50)
@ -69,22 +74,15 @@ var testServer = function (server, cb) {
var timeoutId = setTimeout(function () {
throw new Error('Client should have emitted an error but it did not.')
}, 5000)
// return our wait token
client.on('error', function () {
clearTimeout(timeoutId)
server.close(cb)
})
})
}
// test being disconnected after readyForQuery
const respondingServer = new Server(buffers.readyForQuery())
testServer(respondingServer, function () {
process.stdout.write('.')
// test being disconnected from a server that never responds
const silentServer = new Server()
testServer(silentServer, function () {
process.stdout.write('.')
})
suite.test('readyForQuery server', (done) => {
const respondingServer = new Server(buffers.readyForQuery())
testServer(respondingServer, done)
})
suite.test('silent server', (done) => {
const silentServer = new Server()
testServer(silentServer, done)
})

View File

@ -1,41 +1,39 @@
var helper = require(__dirname + '/test-helper');
'use strict'
var helper = require('./test-helper')
const suite = new helper.Suite()
test("noData message handling", function() {
var client = helper.client();
suite.test('noData message handling', function () {
var client = helper.client()
var q = client.query({
name: 'boom',
text: 'create temp table boom(id serial, size integer)'
});
})
client.query({
name: 'insert',
text: 'insert into boom(size) values($1)',
values: [100]
}, function(err, result) {
if(err) {
console.log(err);
throw err;
}, function (err, result) {
if (err) {
console.log(err)
throw err
}
});
})
client.query({
name: 'insert',
text: 'insert into boom(size) values($1)',
values: [101]
});
})
var query = client.query({
name: 'fetch',
text: 'select size from boom where size < $1',
values: [101]
});
}, (err, res) => {
var row = res.rows[0]
assert.strictEqual(row.size, 100)
})
assert.emits(query, 'row', function(row) {
assert.strictEqual(row.size,100)
});
client.on('drain', client.end.bind(client));
});
client.on('drain', client.end.bind(client))
})

View File

@ -1,23 +1,28 @@
var helper = require(__dirname + '/test-helper');
var pg = helper.pg;
var config = helper.config;
'use strict'
var helper = require('./test-helper')
var pg = helper.pg
const suite = new helper.Suite()
const pool = new pg.Pool()
test('can access results when no rows are returned', function() {
if(config.native) return false;
var checkResult = function(result) {
assert(result.fields, 'should have fields definition');
assert.equal(result.fields.length, 1);
assert.equal(result.fields[0].name, 'val');
assert.equal(result.fields[0].dataTypeID, 25);
pg.end();
};
suite.test('can access results when no rows are returned', function (done) {
var checkResult = function (result) {
assert(result.fields, 'should have fields definition')
assert.equal(result.fields.length, 1)
assert.equal(result.fields[0].name, 'val')
assert.equal(result.fields[0].dataTypeID, 25)
}
pg.connect(config, assert.success(function(client, done) {
var query = client.query('select $1::text as val limit 0', ['hi'], assert.success(function(result) {
checkResult(result);
done();
}));
pool.connect(
assert.success(function (client, release) {
const q = new pg.Query('select $1::text as val limit 0', ['hi'])
var query = client.query(q, assert.success(function (result) {
checkResult(result)
release()
pool.end(done)
})
)
assert.emits(query, 'end', checkResult);
}));
});
assert.emits(query, 'end', checkResult)
})
)
})

View File

@ -1,45 +1,56 @@
var helper = require(__dirname + '/test-helper');
'use strict'
var helper = require('./test-helper')
const suite = new helper.Suite()
test('emits notice message', function() {
//TODO this doesn't work on all versions of postgres
return false;
var client = helper.client();
client.query('create temp table boom(id serial, size integer)');
assert.emits(client, 'notice', function(notice) {
assert.ok(notice != null);
//TODO ending connection after notice generates weird errors
process.nextTick(function() {
client.end();
})
});
})
test('emits notify message', function() {
var client = helper.client();
client.query('LISTEN boom', assert.calls(function() {
var otherClient = helper.client();
otherClient.query('LISTEN boom', assert.calls(function() {
assert.emits(client, 'notification', function(msg) {
//make sure PQfreemem doesn't invalidate string pointers
setTimeout(function() {
assert.equal(msg.channel, 'boom');
assert.ok(msg.payload == 'omg!' /*9.x*/ || msg.payload == '' /*8.x*/, "expected blank payload or correct payload but got " + msg.message)
client.end()
suite.test('emits notify message', function (done) {
var client = helper.client()
client.query('LISTEN boom', assert.calls(function () {
var otherClient = helper.client()
var bothEmitted = -1
otherClient.query('LISTEN boom', assert.calls(function () {
assert.emits(client, 'notification', function (msg) {
// make sure PQfreemem doesn't invalidate string pointers
setTimeout(function () {
assert.equal(msg.channel, 'boom')
assert.ok(msg.payload == 'omg!' /* 9.x */ || msg.payload == '' /* 8.x */, 'expected blank payload or correct payload but got ' + msg.message)
client.end(++bothEmitted ? done : undefined)
}, 100)
})
assert.emits(otherClient, 'notification', function (msg) {
assert.equal(msg.channel, 'boom')
otherClient.end(++bothEmitted ? done : undefined)
})
});
assert.emits(otherClient, 'notification', function(msg) {
assert.equal(msg.channel, 'boom');
otherClient.end();
});
client.query("NOTIFY boom, 'omg!'", function(err, q) {
if(err) {
//notify not supported with payload on 8.x
client.query("NOTIFY boom")
client.query("NOTIFY boom, 'omg!'", function (err, q) {
if (err) {
// notify not supported with payload on 8.x
client.query('NOTIFY boom')
}
});
}));
}));
})
}))
}))
})
// this test fails on travis due to their config
suite.test('emits notice message', false, function (done) {
if (helper.args.native) {
console.error('need to get notice message working on native')
return done()
}
// TODO this doesn't work on all versions of postgres
var client = helper.client()
const text = `
DO language plpgsql $$
BEGIN
RAISE NOTICE 'hello, world!';
END
$$;
`
client.query(text, () => {
client.end()
})
assert.emits(client, 'notice', function (notice) {
assert.ok(notice != null)
done()
})
})

View File

@ -1,25 +1,29 @@
'use strict'
var helper = require(__dirname + '/../test-helper');
var pg = helper.pg;
test('ability to turn on and off parser', function() {
if(helper.args.binary) return false;
pg.connect(helper.config, assert.success(function(client, done) {
pg.defaults.parseInt8 = true;
client.query('CREATE TEMP TABLE asdf(id SERIAL PRIMARY KEY)');
client.query('SELECT COUNT(*) as "count", \'{1,2,3}\'::bigint[] as array FROM asdf', assert.success(function(res) {
assert.strictEqual(0, res.rows[0].count);
assert.strictEqual(1, res.rows[0].array[0]);
assert.strictEqual(2, res.rows[0].array[1]);
assert.strictEqual(3, res.rows[0].array[2]);
pg.defaults.parseInt8 = false;
client.query('SELECT COUNT(*) as "count", \'{1,2,3}\'::bigint[] as array FROM asdf', assert.success(function(res) {
done();
assert.strictEqual('0', res.rows[0].count);
assert.strictEqual('1', res.rows[0].array[0]);
assert.strictEqual('2', res.rows[0].array[1]);
assert.strictEqual('3', res.rows[0].array[2]);
pg.end();
}));
}));
}));
});
var helper = require('../test-helper')
var pg = helper.pg
const suite = new helper.Suite()
const pool = new pg.Pool(helper.config)
suite.test('ability to turn on and off parser', function () {
if (helper.args.binary) return false
pool.connect(assert.success(function (client, done) {
pg.defaults.parseInt8 = true
client.query('CREATE TEMP TABLE asdf(id SERIAL PRIMARY KEY)')
client.query('SELECT COUNT(*) as "count", \'{1,2,3}\'::bigint[] as array FROM asdf', assert.success(function (res) {
assert.strictEqual(0, res.rows[0].count)
assert.strictEqual(1, res.rows[0].array[0])
assert.strictEqual(2, res.rows[0].array[1])
assert.strictEqual(3, res.rows[0].array[2])
pg.defaults.parseInt8 = false
client.query('SELECT COUNT(*) as "count", \'{1,2,3}\'::bigint[] as array FROM asdf', assert.success(function (res) {
done()
assert.strictEqual('0', res.rows[0].count)
assert.strictEqual('1', res.rows[0].array[0])
assert.strictEqual('2', res.rows[0].array[1])
assert.strictEqual('3', res.rows[0].array[2])
pool.end()
}))
}))
}))
})

View File

@ -1,214 +1,142 @@
var helper = require(__dirname +'/test-helper');
'use strict'
var helper = require('./test-helper')
var Query = helper.pg.Query
test("simple, unnamed prepared statement", function(){
var client = helper.client();
var suite = new helper.Suite()
var query = client.query({
text: 'select age from person where name = $1',
values: ['Brian']
});
;(function () {
var client = helper.client()
client.on('drain', client.end.bind(client))
assert.emits(query, 'row', function(row) {
assert.equal(row.age, 20);
});
var queryName = 'user by age and like name'
var parseCount = 0
assert.emits(query, 'end', function() {
client.end();
});
});
test("use interval in prepared statement", function(){
return;
var client = helper.client();
client.query('SELECT interval \'15 days 2 months 3 years 6:12:05\' as interval', assert.success(function(result) {
var interval = result.rows[0].interval;
var query = client.query({
text: 'select cast($1 as interval) as interval',
values: [interval]
});
assert.emits(query, 'row', function(row) {
assert.equal(row.interval.seconds, 5);
assert.equal(row.interval.minutes, 12);
assert.equal(row.interval.hours, 6);
assert.equal(row.interval.days, 15);
assert.equal(row.interval.months, 2);
assert.equal(row.interval.years, 3);
});
assert.emits(query, 'end', function() {
client.end();
});
}));
});
test("named prepared statement", function() {
var client = helper.client();
client.on('drain', client.end.bind(client));
var queryName = "user by age and like name";
var parseCount = 0;
test("first named prepared statement",function() {
var query = client.query({
suite.test('first named prepared statement', function (done) {
var query = client.query(new Query({
text: 'select name from person where age <= $1 and name LIKE $2',
values: [20, 'Bri%'],
name: queryName
});
}))
assert.emits(query, 'row', function(row) {
assert.equal(row.name, 'Brian');
});
assert.emits(query, 'row', function (row) {
assert.equal(row.name, 'Brian')
})
assert.emits(query, 'end', function() {
});
});
query.on('end', () => done())
})
test("second named prepared statement with same name & text", function() {
var cachedQuery = client.query({
suite.test('second named prepared statement with same name & text', function (done) {
var cachedQuery = client.query(new Query({
text: 'select name from person where age <= $1 and name LIKE $2',
name: queryName,
values: [10, 'A%']
});
}))
assert.emits(cachedQuery, 'row', function(row) {
assert.equal(row.name, 'Aaron');
});
assert.emits(cachedQuery, 'row', function (row) {
assert.equal(row.name, 'Aaron')
})
assert.emits(cachedQuery, 'end', function() {
});
});
cachedQuery.on('end', () => done())
})
test("with same name, but the query text not even there batman!", function() {
var q = client.query({
suite.test('with same name, but without query text', function (done) {
var q = client.query(new Query({
name: queryName,
values: [30, '%n%']
});
}))
test("gets first row", function() {
assert.emits(q, 'row', function(row) {
assert.equal(row.name, "Aaron");
assert.emits(q, 'row', function (row) {
assert.equal(row.name, 'Aaron')
test("gets second row", function() {
assert.emits(q, 'row', function(row) {
assert.equal(row.name, "Brian");
});
});
// test second row is emitted as well
assert.emits(q, 'row', function (row) {
assert.equal(row.name, 'Brian')
})
})
});
});
q.on('end', () => done())
})
})()
assert.emits(q, 'end', function() {
;(function () {
var statementName = 'differ'
var statement1 = 'select count(*)::int4 as count from person'
var statement2 = 'select count(*)::int4 as count from person where age < $1'
});
});
});
test("prepared statements on different clients", function() {
var statementName = "differ";
var statement1 = "select count(*)::int4 as count from person";
var statement2 = "select count(*)::int4 as count from person where age < $1";
var client1Finished = false;
var client2Finished = false;
var client1 = helper.client();
var client2 = helper.client();
test("client 1 execution", function() {
var client1 = helper.client()
var client2 = helper.client()
suite.test('client 1 execution', function (done) {
var query = client1.query({
name: statementName,
text: statement1
});
test('gets right data back', function() {
assert.emits(query, 'row', function(row) {
assert.equal(row.count, 26);
});
});
}, (err, res) => {
assert(!err)
assert.equal(res.rows[0].count, 26)
done()
})
})
assert.emits(query, 'end', function() {
if(client2Finished) {
client1.end();
client2.end();
} else {
client1Finished = true;
}
});
});
test('client 2 execution', function() {
var query = client2.query({
suite.test('client 2 execution', function (done) {
var query = client2.query(new Query({
name: statementName,
text: statement2,
values: [11]
});
}))
test('gets right data', function() {
assert.emits(query, 'row', function(row) {
assert.equal(row.count, 1);
});
});
assert.emits(query, 'end', function() {
if(client1Finished) {
client1.end();
client2.end();
} else {
client2Finished = true;
}
});
});
});
test('prepared statement', function() {
var client = helper.client();
client.on('drain', client.end.bind(client));
client.query('CREATE TEMP TABLE zoom(name varchar(100));');
client.query("INSERT INTO zoom (name) VALUES ('zed')");
client.query("INSERT INTO zoom (name) VALUES ('postgres')");
client.query("INSERT INTO zoom (name) VALUES ('node postgres')");
var checkForResults = function(q) {
test('row callback fires for each result', function() {
assert.emits(q, 'row', function(row) {
assert.equal(row.name, 'node postgres');
assert.emits(q, 'row', function(row) {
assert.equal(row.name, 'postgres');
assert.emits(q, 'row', function(row) {
assert.equal(row.name, 'zed');
})
});
})
assert.emits(query, 'row', function (row) {
assert.equal(row.count, 1)
})
};
test('with small row count', function() {
var query = client.query({
name: 'get names',
text: "SELECT name FROM zoom ORDER BY name",
rows: 1
});
checkForResults(query);
assert.emits(query, 'end', function () {
done()
})
})
test('with large row count', function() {
var query = client.query({
suite.test('clean up clients', () => {
return client1.end().then(() => client2.end())
})
})()
;(function () {
var client = helper.client()
client.query('CREATE TEMP TABLE zoom(name varchar(100));')
client.query("INSERT INTO zoom (name) VALUES ('zed')")
client.query("INSERT INTO zoom (name) VALUES ('postgres')")
client.query("INSERT INTO zoom (name) VALUES ('node postgres')")
var checkForResults = function (q) {
assert.emits(q, 'row', function (row) {
assert.equal(row.name, 'node postgres')
assert.emits(q, 'row', function (row) {
assert.equal(row.name, 'postgres')
assert.emits(q, 'row', function (row) {
assert.equal(row.name, 'zed')
})
})
})
}
suite.test('with small row count', function (done) {
var query = client.query(new Query({
name: 'get names',
text: 'SELECT name FROM zoom ORDER BY name',
rows: 1
}, done))
checkForResults(query)
})
suite.test('with large row count', function (done) {
var query = client.query(new Query({
name: 'get names',
text: 'SELECT name FROM zoom ORDER BY name',
rows: 1000
})
checkForResults(query);
}, done))
checkForResults(query)
})
})
suite.test('cleanup', () => client.end())
})()

View File

@ -0,0 +1,50 @@
'use strict'
'use strict'
const helper = require('./test-helper')
const pg = helper.pg
const suite = new helper.Suite()
suite.test('valid connection completes promise', () => {
const client = new pg.Client()
return client.connect()
.then(() => {
return client.end()
.then(() => { })
})
})
suite.test('valid connection completes promise', () => {
const client = new pg.Client()
return client.connect()
.then(() => {
return client.end()
.then(() => { })
})
})
suite.test('invalid connection rejects promise', (done) => {
const client = new pg.Client({ host: 'alksdjflaskdfj' })
return client.connect()
.catch(e => {
assert(e instanceof Error)
done()
})
})
suite.test('connected client does not reject promise after connection', (done) => {
const client = new pg.Client()
return client.connect()
.then(() => {
setTimeout(() => {
client.on('error', (e) => {
assert(e instanceof Error)
client.end()
done()
})
// manually kill the connection
client.emit('error', new Error('something bad happened...but not really'))
}, 50)
})
})

View File

@ -1,33 +1,33 @@
var helper = require(__dirname + '/../test-helper');
var pg = helper.pg;
var semver = require('semver')
'use strict'
var helper = require(__dirname + '/../test-helper')
var pg = helper.pg
if (semver.lt(process.version, '0.12.0')) {
return console.log('promises are not supported in node < v0.10')
}
process.on('unhandledRejection', function(e) {
process.on('unhandledRejection', function (e) {
console.error(e, e.stack)
process.exit(1)
})
pg.connect(helper.config, assert.success(function(client, done) {
client.query('SELECT $1::text as name', ['foo'])
.then(function(result) {
assert.equal(result.rows[0].name, 'foo')
return client
})
.then(function(client) {
client.query('ALKJSDF')
.catch(function(e) {
assert(e instanceof Error)
})
})
const pool = new pg.Pool()
const suite = new helper.Suite()
client.query('SELECT 1 as num')
.then(function(result) {
assert.equal(result.rows[0].num, 1)
done()
pg.end()
})
}))
suite.test('promise API', (cb) => {
pool.connect().then((client) => {
client.query('SELECT $1::text as name', ['foo'])
.then(function (result) {
assert.equal(result.rows[0].name, 'foo')
return client
})
.then(function (client) {
client.query('ALKJSDF')
.catch(function (e) {
assert(e instanceof Error)
client.query('SELECT 1 as num')
.then(function (result) {
assert.equal(result.rows[0].num, 1)
client.release()
pool.end(cb)
})
})
})
})
})

View File

@ -1,13 +1,15 @@
var helper = require(__dirname + '/../test-helper');
var pg = helper.pg;
'use strict'
var helper = require(__dirname + '/../test-helper')
var pg = helper.pg
test('support for complex column names', function() {
pg.connect(helper.config, assert.success(function(client, done) {
client.query("CREATE TEMP TABLE t ( \"complex''column\" TEXT )");
client.query('SELECT * FROM t', assert.success(function(res) {
done();
assert.strictEqual(res.fields[0].name, "complex''column");
pg.end();
}));
}));
});
new helper.Suite().test('support for complex column names', function () {
const pool = new pg.Pool()
pool.connect(assert.success(function (client, done) {
client.query("CREATE TEMP TABLE t ( \"complex''column\" TEXT )")
client.query('SELECT * FROM t', assert.success(function (res) {
done()
assert.strictEqual(res.fields[0].name, "complex''column")
pool.end()
}))
}))
})

View File

@ -1,88 +1,98 @@
var helper = require(__dirname + '/test-helper');
var util = require('util');
'use strict'
var helper = require('./test-helper')
var Query = helper.pg.Query
var util = require('util')
function killIdleQuery(targetQuery) {
var client2 = new Client(helper.args);
var suite = new helper.Suite()
suite.test('client end during query execution of prepared statement', function (done) {
var client = new Client()
client.connect(assert.success(function () {
var sleepQuery = 'select pg_sleep($1)'
var queryConfig = {
name: 'sleep query',
text: sleepQuery,
values: [5]
}
var queryInstance = new Query(queryConfig, assert.calls(function (err, result) {
assert.equal(err.message, 'Connection terminated')
done()
}))
var query1 = client.query(queryInstance)
query1.on('error', function (err) {
assert.fail('Prepared statement should not emit error')
})
query1.on('row', function (row) {
assert.fail('Prepared statement should not emit row')
})
query1.on('end', function (err) {
assert.fail('Prepared statement when executed should not return before being killed')
})
client.end()
}))
})
function killIdleQuery (targetQuery, cb) {
var client2 = new Client(helper.args)
var pidColName = 'procpid'
var queryColName = 'current_query';
client2.connect(assert.success(function() {
helper.versionGTE(client2, '9.2.0', assert.success(function(isGreater) {
if(isGreater) {
pidColName = 'pid';
queryColName = 'query';
var queryColName = 'current_query'
client2.connect(assert.success(function () {
helper.versionGTE(client2, '9.2.0', assert.success(function (isGreater) {
if (isGreater) {
pidColName = 'pid'
queryColName = 'query'
}
var killIdleQuery = "SELECT " + pidColName + ", (SELECT pg_terminate_backend(" + pidColName + ")) AS killed FROM pg_stat_activity WHERE " + queryColName + " = $1";
client2.query(killIdleQuery, [targetQuery], assert.calls(function(err, res) {
assert.ifError(err);
assert.equal(res.rows.length, 1);
client2.end();
assert.emits(client2, 'end');
}));
}));
}));
var killIdleQuery = 'SELECT ' + pidColName + ', (SELECT pg_terminate_backend(' + pidColName + ')) AS killed FROM pg_stat_activity WHERE ' + queryColName + ' = $1'
client2.query(killIdleQuery, [targetQuery], assert.calls(function (err, res) {
assert.ifError(err)
assert.equal(res.rows.length, 1)
client2.end(cb)
assert.emits(client2, 'end')
}))
}))
}))
}
test('query killed during query execution of prepared statement', function() {
if(helper.args.native) {
return false;
suite.test('query killed during query execution of prepared statement', function (done) {
if (helper.args.native) {
return done()
}
var client = new Client(helper.args);
client.connect(assert.success(function() {
var sleepQuery = 'select pg_sleep($1)';
var client = new Client(helper.args)
client.connect(assert.success(function () {
var sleepQuery = 'select pg_sleep($1)'
const queryConfig = {
name: 'sleep query',
text: sleepQuery,
values: [5],
};
values: [5]
}
// client should emit an error because it is unexpectedly disconnected
assert.emits(client, 'error')
var query1 = client.query(queryConfig, assert.calls(function(err, result) {
assert.equal(err.message, 'terminating connection due to administrator command');
}));
var query1 = client.query(new Query(queryConfig), assert.calls(function (err, result) {
assert.equal(err.message, 'terminating connection due to administrator command')
}))
query1.on('error', function(err) {
assert.fail('Prepared statement should not emit error');
});
query1.on('error', function (err) {
assert.fail('Prepared statement should not emit error')
})
query1.on('row', function(row) {
assert.fail('Prepared statement should not emit row');
});
query1.on('row', function (row) {
assert.fail('Prepared statement should not emit row')
})
query1.on('end', function(err) {
assert.fail('Prepared statement when executed should not return before being killed');
});
query1.on('end', function (err) {
assert.fail('Prepared statement when executed should not return before being killed')
})
killIdleQuery(sleepQuery);
}));
});
test('client end during query execution of prepared statement', function() {
var client = new Client(helper.args);
client.connect(assert.success(function() {
var sleepQuery = 'select pg_sleep($1)';
var query1 = client.query({
name: 'sleep query',
text: sleepQuery,
values: [5] },
assert.calls(function(err, result) {
assert.equal(err.message, 'Connection terminated');
}));
query1.on('error', function(err) {
assert.fail('Prepared statement should not emit error');
});
query1.on('row', function(row) {
assert.fail('Prepared statement should not emit row');
});
query1.on('end', function(err) {
assert.fail('Prepared statement when executed should not return before being killed');
});
client.end();
}));
});
killIdleQuery(sleepQuery, done)
}))
})

View File

@ -1,10 +1,13 @@
var helper = require(__dirname + '/test-helper');
"use strict";
var helper = require('./test-helper');
var util = require('util');
var Query = helper.pg.Query;
test('error during query execution', function() {
var client = new Client(helper.args);
client.connect(assert.success(function() {
var sleepQuery = 'select pg_sleep(5)';
var queryText = 'select pg_sleep(10)'
var sleepQuery = new Query(queryText);
var pidColName = 'procpid'
var queryColName = 'current_query';
helper.versionGTE(client, '9.2.0', assert.success(function(isGreater) {
@ -25,20 +28,22 @@ test('error during query execution', function() {
setTimeout(function() {
var client2 = new Client(helper.args);
client2.connect(assert.success(function() {
var killIdleQuery = "SELECT " + pidColName + ", (SELECT pg_terminate_backend(" + pidColName + ")) AS killed FROM pg_stat_activity WHERE " + queryColName + " = $1";
client2.query(killIdleQuery, [sleepQuery], assert.calls(function(err, res) {
var killIdleQuery = `SELECT ${pidColName}, (SELECT pg_cancel_backend(${pidColName})) AS killed FROM pg_stat_activity WHERE ${queryColName} LIKE $1`;
client2.query(killIdleQuery, [queryText], assert.calls(function(err, res) {
assert.ifError(err);
assert.equal(res.rows.length, 1);
assert(res.rows.length > 0);
client2.end();
assert.emits(client2, 'end');
}));
}));
}, 100)
}, 300)
}));
}));
});
if(helper.config.native) return;
if (helper.config.native) {
return
}
test('9.3 column error fields', function() {
var client = new Client(helper.args);
@ -48,12 +53,10 @@ test('9.3 column error fields', function() {
return client.end();
}
client.query('DROP TABLE IF EXISTS column_err_test');
client.query('CREATE TABLE column_err_test(a int NOT NULL)');
client.query('CREATE TEMP TABLE column_err_test(a int NOT NULL)');
client.query('INSERT INTO column_err_test(a) VALUES (NULL)', function (err) {
assert.equal(err.severity, 'ERROR');
assert.equal(err.code, '23502');
assert.equal(err.schema, 'public');
assert.equal(err.table, 'column_err_test');
assert.equal(err.column, 'a');
return client.end();
@ -71,13 +74,11 @@ test('9.3 constraint error fields', function() {
return client.end();
}
client.query('DROP TABLE IF EXISTS constraint_err_test');
client.query('CREATE TABLE constraint_err_test(a int PRIMARY KEY)');
client.query('CREATE TEMP TABLE constraint_err_test(a int PRIMARY KEY)');
client.query('INSERT INTO constraint_err_test(a) VALUES (1)');
client.query('INSERT INTO constraint_err_test(a) VALUES (1)', function (err) {
assert.equal(err.severity, 'ERROR');
assert.equal(err.code, '23505');
assert.equal(err.schema, 'public');
assert.equal(err.table, 'constraint_err_test');
assert.equal(err.constraint, 'constraint_err_test_pkey');
return client.end();

View File

@ -1,7 +1,8 @@
//test for issue #320
'use strict'
// test for issue #320
//
var helper = require('./test-helper');
var helper = require('./test-helper')
var client = new helper.pg.Client(helper.config);
client.connect();
client.end();
var client = new helper.pg.Client(helper.config)
client.connect()
client.end()

View File

@ -1,36 +1,32 @@
var helper = require(__dirname + "/test-helper");
var pg = helper.pg;
'use strict'
var helper = require('./test-helper')
var pg = helper.pg
test('should return insert metadata', function() {
pg.connect(helper.config, assert.calls(function(err, client, done) {
assert.isNull(err);
const pool = new pg.Pool()
new helper.Suite().test('should return insert metadata', function () {
pool.connect(assert.calls(function (err, client, done) {
assert(!err)
helper.versionGTE(client, '9.0.0', assert.success(function(hasRowCount) {
client.query("CREATE TEMP TABLE zugzug(name varchar(10))", assert.calls(function(err, result) {
assert.isNull(err);
assert.equal(result.oid, null);
assert.equal(result.command, 'CREATE');
helper.versionGTE(client, '9.0.0', assert.success(function (hasRowCount) {
client.query('CREATE TEMP TABLE zugzug(name varchar(10))', assert.calls(function (err, result) {
assert(!err)
assert.equal(result.oid, null)
assert.equal(result.command, 'CREATE')
var q = client.query("INSERT INTO zugzug(name) VALUES('more work?')", assert.calls(function(err, result) {
assert.isNull(err);
assert.equal(result.command, "INSERT");
assert.equal(result.rowCount, 1);
var q = client.query("INSERT INTO zugzug(name) VALUES('more work?')", assert.calls(function (err, result) {
assert(!err)
assert.equal(result.command, 'INSERT')
assert.equal(result.rowCount, 1)
client.query('SELECT * FROM zugzug', assert.calls(function(err, result) {
assert.isNull(err);
if(hasRowCount) assert.equal(result.rowCount, 1);
assert.equal(result.command, 'SELECT');
process.nextTick(pg.end.bind(pg));
}));
}));
assert.emits(q, 'end', function(result) {
assert.equal(result.command, "INSERT");
if(hasRowCount) assert.equal(result.rowCount, 1);
done();
});
}));
}));
}));
});
client.query('SELECT * FROM zugzug', assert.calls(function (err, result) {
assert(!err)
if (hasRowCount) assert.equal(result.rowCount, 1)
assert.equal(result.command, 'SELECT')
done()
process.nextTick(pool.end.bind(pool))
}))
}))
}))
}))
}))
})

View File

@ -1,33 +1,31 @@
var util = require('util');
var helper = require('./test-helper');
'use strict'
var util = require('util')
var helper = require('./test-helper')
var Client = helper.Client;
var Client = helper.Client
var conInfo = helper.config;
var conInfo = helper.config
test('returns results as array', function() {
var client = new Client(conInfo);
var checkRow = function(row) {
assert(util.isArray(row), 'row should be an array');
assert.equal(row.length, 4);
assert.equal(row[0].getFullYear(), new Date().getFullYear());
assert.strictEqual(row[1], 1);
assert.strictEqual(row[2], 'hai');
assert.strictEqual(row[3], null);
test('returns results as array', function () {
var client = new Client(conInfo)
var checkRow = function (row) {
assert(util.isArray(row), 'row should be an array')
assert.equal(row.length, 4)
assert.equal(row[0].getFullYear(), new Date().getFullYear())
assert.strictEqual(row[1], 1)
assert.strictEqual(row[2], 'hai')
assert.strictEqual(row[3], null)
}
client.connect(assert.success(function() {
client.connect(assert.success(function () {
var config = {
text: 'SELECT NOW(), 1::int, $1::text, null',
values: ['hai'],
rowMode: 'array'
};
var query = client.query(config, assert.success(function(result) {
assert.equal(result.rows.length, 1);
checkRow(result.rows[0]);
client.end();
}));
assert.emits(query, 'row', function(row) {
checkRow(row);
});
}));
});
}
var query = client.query(config, assert.success(function (result) {
assert.equal(result.rows.length, 1)
checkRow(result.rows[0])
client.end()
}))
}))
})

View File

@ -1,37 +1,38 @@
var helper = require('./test-helper');
'use strict'
var helper = require('./test-helper')
var Client = helper.Client;
var Client = helper.Client
var conInfo = helper.config;
var conInfo = helper.config
var checkResult = function(result) {
assert(result.fields);
assert.equal(result.fields.length, 3);
var fields = result.fields;
assert.equal(fields[0].name, 'now');
assert.equal(fields[1].name, 'num');
assert.equal(fields[2].name, 'texty');
assert.equal(fields[0].dataTypeID, 1184);
assert.equal(fields[1].dataTypeID, 23);
assert.equal(fields[2].dataTypeID, 25);
};
var checkResult = function (result) {
assert(result.fields)
assert.equal(result.fields.length, 3)
var fields = result.fields
assert.equal(fields[0].name, 'now')
assert.equal(fields[1].name, 'num')
assert.equal(fields[2].name, 'texty')
assert.equal(fields[0].dataTypeID, 1184)
assert.equal(fields[1].dataTypeID, 23)
assert.equal(fields[2].dataTypeID, 25)
}
test('row descriptions on result object', function() {
var client = new Client(conInfo);
client.connect(assert.success(function() {
client.query('SELECT NOW() as now, 1::int as num, $1::text as texty', ["hello"], assert.success(function(result) {
checkResult(result);
client.end();
}));
}));
});
test('row descriptions on result object', function () {
var client = new Client(conInfo)
client.connect(assert.success(function () {
client.query('SELECT NOW() as now, 1::int as num, $1::text as texty', ['hello'], assert.success(function (result) {
checkResult(result)
client.end()
}))
}))
})
test('row description on no rows', function() {
var client = new Client(conInfo);
client.connect(assert.success(function() {
client.query('SELECT NOW() as now, 1::int as num, $1::text as texty LIMIT 0', ["hello"], assert.success(function(result) {
checkResult(result);
client.end();
}));
}));
});
test('row description on no rows', function () {
var client = new Client(conInfo)
client.connect(assert.success(function () {
client.query('SELECT NOW() as now, 1::int as num, $1::text as texty LIMIT 0', ['hello'], assert.success(function (result) {
checkResult(result)
client.end()
}))
}))
})

View File

@ -1,111 +1,92 @@
var helper = require(__dirname+"/test-helper");
//before running this test make sure you run the script create-test-tables
test("simple query interface", function() {
'use strict'
var helper = require('./test-helper')
var Query = helper.pg.Query
var client = helper.client();
// before running this test make sure you run the script create-test-tables
test('simple query interface', function () {
var client = helper.client()
var query = client.query("select name from person order by name");
var query = client.query(new Query('select name from person order by name'))
client.on('drain', client.end.bind(client));
client.on('drain', client.end.bind(client))
var rows = [];
query.on('row', function(row, result) {
assert.ok(result);
rows.push(row['name']);
});
query.once('row', function(row) {
var rows = []
query.on('row', function (row, result) {
assert.ok(result)
rows.push(row['name'])
})
query.once('row', function (row) {
test('Can iterate through columns', function () {
var columnCount = 0;
for (column in row) {
columnCount++;
var columnCount = 0
for (var column in row) {
columnCount++
}
if ('length' in row) {
assert.lengthIs(row, columnCount, 'Iterating through the columns gives a different length from calling .length.');
assert.lengthIs(row, columnCount, 'Iterating through the columns gives a different length from calling .length.')
}
});
});
})
})
assert.emits(query, 'end', function() {
test("returned right number of rows", function() {
assert.lengthIs(rows, 26);
});
test("row ordering", function(){
assert.equal(rows[0], "Aaron");
assert.equal(rows[25], "Zanzabar");
});
});
});
assert.emits(query, 'end', function () {
test('returned right number of rows', function () {
assert.lengthIs(rows, 26)
})
test('row ordering', function () {
assert.equal(rows[0], 'Aaron')
assert.equal(rows[25], 'Zanzabar')
})
})
})
test("simple query interface using addRow", function() {
var client = helper.client();
var query = client.query("select name from person order by name");
client.on('drain', client.end.bind(client));
query.on('row', function(row, result) {
assert.ok(result);
result.addRow(row);
});
query.on('end', function(result) {
assert.lengthIs(result.rows, 26, "result returned wrong number of rows");
assert.lengthIs(result.rows, result.rowCount);
assert.equal(result.rows[0].name, "Aaron");
assert.equal(result.rows[25].name, "Zanzabar");
});
});
test("prepared statements do not mutate params", function() {
var client = helper.client();
test('prepared statements do not mutate params', function () {
var client = helper.client()
var params = [1]
var query = client.query("select name from person where $1 = 1 order by name", params);
var query = client.query(new Query('select name from person where $1 = 1 order by name', params))
assert.deepEqual(params, [1])
client.on('drain', client.end.bind(client));
client.on('drain', client.end.bind(client))
query.on('row', function(row, result) {
assert.ok(result);
result.addRow(row);
});
const rows = []
query.on('row', function (row, result) {
assert.ok(result)
rows.push(row)
})
query.on('end', function(result) {
assert.lengthIs(result.rows, 26, "result returned wrong number of rows");
assert.lengthIs(result.rows, result.rowCount);
assert.equal(result.rows[0].name, "Aaron");
assert.equal(result.rows[25].name, "Zanzabar");
});
});
query.on('end', function (result) {
assert.lengthIs(rows, 26, 'result returned wrong number of rows')
assert.lengthIs(rows, result.rowCount)
assert.equal(rows[0].name, 'Aaron')
assert.equal(rows[25].name, 'Zanzabar')
})
})
test("multiple simple queries", function() {
var client = helper.client();
test('multiple simple queries', function () {
var client = helper.client()
client.query({ text: "create temp table bang(id serial, name varchar(5));insert into bang(name) VALUES('boom');"})
client.query("insert into bang(name) VALUES ('yes');");
var query = client.query("select name from bang");
assert.emits(query, 'row', function(row) {
assert.equal(row['name'], 'boom');
assert.emits(query, 'row', function(row) {
assert.equal(row['name'],'yes');
});
});
client.on('drain', client.end.bind(client));
});
client.query("insert into bang(name) VALUES ('yes');")
var query = client.query(new Query('select name from bang'))
assert.emits(query, 'row', function (row) {
assert.equal(row['name'], 'boom')
assert.emits(query, 'row', function (row) {
assert.equal(row['name'], 'yes')
})
})
client.on('drain', client.end.bind(client))
})
test("multiple select statements", function() {
var client = helper.client();
client.query("create temp table boom(age integer); insert into boom(age) values(1); insert into boom(age) values(2); insert into boom(age) values(3)");
client.query({text: "create temp table bang(name varchar(5)); insert into bang(name) values('zoom');"});
var result = client.query({text: "select age from boom where age < 2; select name from bang"});
assert.emits(result, 'row', function(row) {
assert.strictEqual(row['age'], 1);
assert.emits(result, 'row', function(row) {
assert.strictEqual(row['name'], 'zoom');
});
});
client.on('drain', client.end.bind(client));
});
test('multiple select statements', function () {
var client = helper.client()
client.query('create temp table boom(age integer); insert into boom(age) values(1); insert into boom(age) values(2); insert into boom(age) values(3)')
client.query({text: "create temp table bang(name varchar(5)); insert into bang(name) values('zoom');"})
var result = client.query(new Query({text: 'select age from boom where age < 2; select name from bang'}))
assert.emits(result, 'row', function (row) {
assert.strictEqual(row['age'], 1)
assert.emits(result, 'row', function (row) {
assert.strictEqual(row['name'], 'zoom')
})
})
client.on('drain', client.end.bind(client))
})

View File

@ -1,14 +1,15 @@
var pg = require(__dirname + '/../../../lib');
var config = require(__dirname + '/test-helper').config;
test('can connect with ssl', function() {
return false;
'use strict'
var pg = require(__dirname + '/../../../lib')
var config = require(__dirname + '/test-helper').config
test('can connect with ssl', function () {
return false
config.ssl = {
rejectUnauthorized: false
};
pg.connect(config, assert.success(function(client) {
return false;
client.query('SELECT NOW()', assert.success(function() {
pg.end();
}));
}));
});
}
pg.connect(config, assert.success(function (client) {
return false
client.query('SELECT NOW()', assert.success(function () {
pg.end()
}))
}))
})

View File

@ -1,3 +1,4 @@
var helper = require(__dirname+'/../test-helper');
'use strict'
var helper = require('./../test-helper')
module.exports = helper;
module.exports = helper

View File

@ -1,29 +1,34 @@
var helper = require(__dirname + '/../test-helper');
var exec = require('child_process').exec;
'use strict'
var helper = require('./../test-helper')
var exec = require('child_process').exec
var oldTz = process.env.TZ;
process.env.TZ = 'Europe/Berlin';
var oldTz = process.env.TZ
process.env.TZ = 'Europe/Berlin'
var date = new Date();
var date = new Date()
helper.pg.connect(helper.config, function(err, client, done) {
assert.isNull(err);
const pool = new helper.pg.Pool()
const suite = new helper.Suite()
test('timestamp without time zone', function() {
client.query("SELECT CAST($1 AS TIMESTAMP WITHOUT TIME ZONE) AS \"val\"", [ date ], function(err, result) {
assert.isNull(err);
assert.equal(result.rows[0].val.getTime(), date.getTime());
pool.connect(function (err, client, done) {
assert(!err)
test('timestamp with time zone', function() {
client.query("SELECT CAST($1 AS TIMESTAMP WITH TIME ZONE) AS \"val\"", [ date ], function(err, result) {
assert.isNull(err);
assert.equal(result.rows[0].val.getTime(), date.getTime());
suite.test('timestamp without time zone', function (cb) {
client.query('SELECT CAST($1 AS TIMESTAMP WITHOUT TIME ZONE) AS "val"', [date], function (err, result) {
assert(!err)
assert.equal(result.rows[0].val.getTime(), date.getTime())
cb()
})
})
done();
helper.pg.end();
process.env.TZ = oldTz;
});
});
});
});
});
suite.test('timestamp with time zone', function (cb) {
client.query('SELECT CAST($1 AS TIMESTAMP WITH TIME ZONE) AS "val"', [date], function (err, result) {
assert(!err)
assert.equal(result.rows[0].val.getTime(), date.getTime())
done()
pool.end(cb)
process.env.TZ = oldTz
})
})
})

View File

@ -1,72 +1,76 @@
var helper = require(__dirname + '/test-helper');
'use strict'
var helper = require('./test-helper')
const suite = new helper.Suite()
const pg = helper.pg
var sink = new helper.Sink(2, function() {
helper.pg.end();
});
const client = new pg.Client()
client.connect(assert.success(function () {
client.query('begin')
test('a single connection transaction', function() {
helper.pg.connect(helper.config, assert.success(function(client, done) {
var getZed = {
text: 'SELECT * FROM person WHERE name = $1',
values: ['Zed']
}
client.query('begin');
suite.test('name should not exist in the database', function (done) {
client.query(getZed, assert.calls(function (err, result) {
assert(!err)
assert.empty(result.rows)
done()
}))
})
var getZed = {
text: 'SELECT * FROM person WHERE name = $1',
values: ['Zed']
};
suite.test('can insert name', (done) => {
client.query('INSERT INTO person(name, age) VALUES($1, $2)', ['Zed', 270], assert.calls(function (err, result) {
assert(!err)
done()
}))
})
test('Zed should not exist in the database', function() {
client.query(getZed, assert.calls(function(err, result) {
assert.isNull(err);
assert.empty(result.rows);
}))
})
suite.test('name should exist in the database', function (done) {
client.query(getZed, assert.calls(function (err, result) {
assert(!err)
assert.equal(result.rows[0].name, 'Zed')
done()
}))
})
client.query("INSERT INTO person(name, age) VALUES($1, $2)", ['Zed', 270], assert.calls(function(err, result) {
assert.isNull(err)
}));
suite.test('rollback', (done) => {
client.query('rollback', done)
})
test('Zed should exist in the database', function() {
client.query(getZed, assert.calls(function(err, result) {
assert.isNull(err);
assert.equal(result.rows[0].name, 'Zed');
}))
})
suite.test('name should not exist in the database', function (done) {
client.query(getZed, assert.calls(function (err, result) {
assert(!err)
assert.empty(result.rows)
client.end(done)
}))
})
}))
client.query('rollback');
test('Zed should not exist in the database', function() {
client.query(getZed, assert.calls(function(err, result) {
assert.isNull(err);
assert.empty(result.rows);
done();
sink.add();
}))
suite.test('gh#36', function (cb) {
const pool = new pg.Pool()
pool.connect(assert.success(function (client, done) {
client.query('BEGIN')
client.query({
name: 'X',
text: 'SELECT $1::INTEGER',
values: [0]
}, assert.calls(function (err, result) {
if (err) throw err
assert.equal(result.rows.length, 1)
}))
client.query({
name: 'X',
text: 'SELECT $1::INTEGER',
values: [0]
}, assert.calls(function (err, result) {
if (err) throw err
assert.equal(result.rows.length, 1)
}))
client.query('COMMIT', function () {
done()
pool.end(cb)
})
}))
})
test('gh#36', function() {
helper.pg.connect(helper.config, assert.success(function(client, done) {
client.query("BEGIN");
client.query({
name: 'X',
text: "SELECT $1::INTEGER",
values: [0]
}, assert.calls(function(err, result) {
if(err) throw err;
assert.equal(result.rows.length, 1);
}))
client.query({
name: 'X',
text: "SELECT $1::INTEGER",
values: [0]
}, assert.calls(function(err, result) {
if(err) throw err;
assert.equal(result.rows.length, 1);
}))
client.query("COMMIT", function() {
sink.add();
done();
})
}));
})

View File

@ -1,52 +1,57 @@
var helper = require(__dirname + '/test-helper');
var sink;
'use strict'
var helper = require(__dirname + '/test-helper')
var pg = helper.pg
var sink
const suite = new helper.Suite()
var testForTypeCoercion = function(type){
helper.pg.connect(helper.config, function(err, client, done) {
assert.isNull(err);
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) {
var testForTypeCoercion = function (type) {
const pool = new pg.Pool()
suite.test(`test type coercion ${type.name}`, (cb) => {
pool.connect(function (err, client, done) {
assert(!err)
client.query('create temp table test_type(col ' + type.name + ')', assert.calls(function (err, result) {
assert(!err)
var insertQuery = client.query('insert into test_type(col) VALUES($1)',[val],assert.calls(function(err, result) {
assert.isNull(err);
}));
type.values.forEach(function (val) {
var insertQuery = client.query('insert into test_type(col) VALUES($1)', [val], assert.calls(function (err, result) {
assert(!err)
}))
var query = client.query({
name: 'get type ' + type.name ,
var query = client.query(new pg.Query({
name: 'get type ' + type.name,
text: 'select col from test_type'
});
query.on('error', function(err) {
console.log(err);
throw err;
});
}))
assert.emits(query, 'row', function(row) {
var expected = val + " (" + typeof val + ")";
var returned = row.col + " (" + typeof row.col + ")";
assert.strictEqual(row.col, val, "expected " + type.name + " of " + expected + " but got " + returned);
}, "row should have been called for " + type.name + " of " + val);
query.on('error', function (err) {
console.log(err)
throw err
})
client.query('delete from test_type');
});
assert.emits(query, 'row', function (row) {
var expected = val + ' (' + typeof val + ')'
var returned = row.col + ' (' + typeof row.col + ')'
assert.strictEqual(row.col, val, 'expected ' + type.name + ' of ' + expected + ' but got ' + returned)
}, 'row should have been called for ' + type.name + ' of ' + val)
client.query('drop table test_type', function() {
sink.add();
done();
});
})
}));
client.query('delete from test_type')
})
client.query('drop table test_type', function () {
done()
pool.end(cb)
})
}))
})
})
};
}
var types = [{
name: 'integer',
values: [-2147483648, -1, 0, 1, 2147483647, null]
},{
}, {
name: 'smallint',
values: [-32768, -1, 0, 1, 32767, null]
},{
}, {
name: 'bigint',
values: [
'-9223372036854775808',
@ -57,16 +62,16 @@ var types = [{
'9223372036854775807',
null
]
},{
}, {
name: 'varchar(5)',
values: ['yo', '', 'zomg!', null]
},{
}, {
name: 'oid',
values: [0, 204410, null]
},{
}, {
name: 'bool',
values: [true, false, null]
},{
}, {
name: 'numeric',
values: [
'-12.34',
@ -76,125 +81,113 @@ var types = [{
'3141592653589793238462643383279502.1618033988749894848204586834365638',
null
]
},{
}, {
name: 'real',
values: [-101.3, -1.2, 0, 1.2, 101.1, null]
},{
}, {
name: 'double precision',
values: [-101.3, -1.2, 0, 1.2, 101.1, null]
},{
}, {
name: 'timestamptz',
values: [null]
},{
}, {
name: 'timestamp',
values: [null]
},{
}, {
name: 'timetz',
values: ['13:11:12.1234-05:30',null]
},{
values: ['13:11:12.1234-05:30', null]
}, {
name: 'time',
values: ['13:12:12.321', null]
}];
}]
// ignore some tests in binary mode
if (helper.config.binary) {
types = types.filter(function(type) {
return !(type.name in {'real': 1, 'timetz':1, 'time':1, 'numeric': 1, 'bigint': 1});
});
types = types.filter(function (type) {
return !(type.name in { 'real': 1, 'timetz': 1, 'time': 1, 'numeric': 1, 'bigint': 1 })
})
}
var valueCount = 0;
types.forEach(function(type) {
valueCount += type.values.length;
})
sink = new helper.Sink(types.length + 1, function() {
helper.pg.end();
})
var valueCount = 0
types.forEach(function(type) {
types.forEach(function (type) {
testForTypeCoercion(type)
});
})
test("timestampz round trip", function() {
var now = new Date();
var client = helper.client();
client.on('error', function(err) {
console.log(err);
client.end();
});
client.query("create temp table date_tests(name varchar(10), tstz timestamptz(3))");
suite.test('timestampz round trip', function (cb) {
var now = new Date()
var client = helper.client()
client.query('create temp table date_tests(name varchar(10), tstz timestamptz(3))')
client.query({
text: "insert into date_tests(name, tstz)VALUES($1, $2)",
text: 'insert into date_tests(name, tstz)VALUES($1, $2)',
name: 'add date',
values: ['now', now]
});
var result = client.query({
})
var result = client.query(new pg.Query({
name: 'get date',
text: 'select * from date_tests where name = $1',
values: ['now']
});
assert.emits(result, 'row', function(row) {
var date = row.tstz;
assert.equal(date.getYear(),now.getYear());
assert.equal(date.getMonth(), now.getMonth());
assert.equal(date.getDate(), now.getDate());
assert.equal(date.getHours(), now.getHours());
assert.equal(date.getMinutes(), now.getMinutes());
assert.equal(date.getSeconds(), now.getSeconds());
test("milliseconds are equal", function() {
assert.equal(date.getMilliseconds(), now.getMilliseconds());
});
});
client.on('drain', client.end.bind(client));
});
if(!helper.config.binary) {
test('date range extremes', function() {
var client = helper.client();
client.on('error', function(err) {
console.log(err);
client.end();
});
// Set the server timeszone to the same as used for the test,
// otherwise (if server's timezone is ahead of GMT) in
// textParsers.js::parseDate() the timezone offest is added to the date;
// in the case of "275760-09-13 00:00:00 GMT" the timevalue overflows.
client.query('SET TIMEZONE TO GMT', assert.success(function(res){
// PostgreSQL supports date range of 4713 BCE to 294276 CE
// http://www.postgresql.org/docs/9.2/static/datatype-datetime.html
// ECMAScript supports date range of Apr 20 271821 BCE to Sep 13 275760 CE
// http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.1
client.query('SELECT $1::TIMESTAMPTZ as when', ["275760-09-13 00:00:00 GMT"], assert.success(function(res) {
assert.equal(res.rows[0].when.getFullYear(), 275760);
}));
client.query('SELECT $1::TIMESTAMPTZ as when', ["4713-12-31 12:31:59 BC GMT"], assert.success(function(res) {
assert.equal(res.rows[0].when.getFullYear(), -4713);
}));
client.query('SELECT $1::TIMESTAMPTZ as when', ["275760-09-13 00:00:00 -15:00"], assert.success(function(res) {
assert( isNaN(res.rows[0].when.getTime()) );
}));
client.on('drain', client.end.bind(client));
}));
});
}
helper.pg.connect(helper.config, assert.calls(function(err, client, done) {
assert.ifError(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);
sink.add();
done();
assert.emits(result, 'row', function (row) {
var date = row.tstz
assert.equal(date.getYear(), now.getYear())
assert.equal(date.getMonth(), now.getMonth())
assert.equal(date.getDate(), now.getDate())
assert.equal(date.getHours(), now.getHours())
assert.equal(date.getMinutes(), now.getMinutes())
assert.equal(date.getSeconds(), now.getSeconds())
assert.equal(date.getMilliseconds(), now.getMilliseconds())
})
}))
client.on('drain', () => {
client.end(cb)
})
})
suite.test('selecting nulls', cb => {
const pool = new pg.Pool()
pool.connect(assert.calls(function (err, client, done) {
assert.ifError(err)
client.query('select null as res;', assert.calls(function (err, res) {
assert(!err)
assert.strictEqual(res.rows[0].res, null)
}))
client.query('select 7 <> $1 as res;', [null], function (err, res) {
assert(!err)
assert.strictEqual(res.rows[0].res, null)
done()
pool.end(cb)
})
}))
})
suite.test('date range extremes', function (done) {
var client = helper.client()
// Set the server timeszone to the same as used for the test,
// otherwise (if server's timezone is ahead of GMT) in
// textParsers.js::parseDate() the timezone offest is added to the date;
// in the case of "275760-09-13 00:00:00 GMT" the timevalue overflows.
client.query('SET TIMEZONE TO GMT', assert.success(function (res) {
// PostgreSQL supports date range of 4713 BCE to 294276 CE
// http://www.postgresql.org/docs/9.2/static/datatype-datetime.html
// ECMAScript supports date range of Apr 20 271821 BCE to Sep 13 275760 CE
// http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.1
client.query('SELECT $1::TIMESTAMPTZ as when', ['275760-09-13 00:00:00 GMT'], assert.success(function (res) {
assert.equal(res.rows[0].when.getFullYear(), 275760)
}))
client.query('SELECT $1::TIMESTAMPTZ as when', ['4713-12-31 12:31:59 BC GMT'], assert.success(function (res) {
assert.equal(res.rows[0].when.getFullYear(), -4713)
}))
client.query('SELECT $1::TIMESTAMPTZ as when', ['275760-09-13 00:00:00 -15:00'], assert.success(function (res) {
assert(isNaN(res.rows[0].when.getTime()))
}))
client.on('drain', () => {
client.end(done)
})
}))
})

View File

@ -1,34 +1,37 @@
var helper = require(__dirname + '/test-helper');
'use strict'
var helper = require('./test-helper')
function testTypeParser(client, expectedResult, done) {
var boolValue = true;
client.query('CREATE TEMP TABLE parserOverrideTest(id bool)');
client.query('INSERT INTO parserOverrideTest(id) VALUES ($1)', [boolValue]);
client.query('SELECT * FROM parserOverrideTest', assert.success(function(result) {
assert.equal(result.rows[0].id, expectedResult);
helper.pg.end();
done();
}));
function testTypeParser (client, expectedResult, done) {
var boolValue = true
client.query('CREATE TEMP TABLE parserOverrideTest(id bool)')
client.query('INSERT INTO parserOverrideTest(id) VALUES ($1)', [boolValue])
client.query('SELECT * FROM parserOverrideTest', assert.success(function (result) {
assert.equal(result.rows[0].id, expectedResult)
done()
}))
}
helper.pg.connect(helper.config, assert.success(function(client1, done1) {
helper.pg.connect(helper.config, assert.success(function(client2, done2) {
var boolTypeOID = 16;
client1.setTypeParser(boolTypeOID, function(){
return 'first client';
});
client2.setTypeParser(boolTypeOID, function(){
return 'second client';
});
const pool = new helper.pg.Pool(helper.config)
pool.connect(assert.success(function (client1, done1) {
pool.connect(assert.success(function (client2, done2) {
var boolTypeOID = 16
client1.setTypeParser(boolTypeOID, function () {
return 'first client'
})
client2.setTypeParser(boolTypeOID, function () {
return 'second client'
})
client1.setTypeParser(boolTypeOID, 'binary', function(){
return 'first client binary';
});
client2.setTypeParser(boolTypeOID, 'binary', function(){
return 'second client binary';
});
client1.setTypeParser(boolTypeOID, 'binary', function () {
return 'first client binary'
})
client2.setTypeParser(boolTypeOID, 'binary', function () {
return 'second client binary'
})
testTypeParser(client1, 'first client', done1);
testTypeParser(client2, 'second client', done2);
}));
}));
testTypeParser(client1, 'first client', () => {
done1()
testTypeParser(client2, 'second client', () => done2(), pool.end())
})
}))
}))

View File

@ -0,0 +1,10 @@
'use strict'
var helper = require('./test-helper')
helper.testPoolSize(1)
helper.testPoolSize(2)
helper.testPoolSize(40)
helper.testPoolSize(200)

View File

@ -1,2 +0,0 @@
var helper = require("./test-helper")
helper.testPoolSize(2);

View File

@ -1,15 +0,0 @@
var helper = require('./test-helper')
var called = false;
test('disconnects', function() {
called = true;
var eventSink = new helper.Sink(1, function() {});
helper.pg.on('end', function() {
eventSink.add();
});
//this should exit the process
helper.pg.end();
})

View File

@ -1,30 +0,0 @@
var helper = require('./test-helper')
var called = false;
test('disconnects', function() {
var sink = new helper.Sink(4, function() {
called = true;
var eventSink = new helper.Sink(1, function() {});
helper.pg.on('end', function() {
eventSink.add();
});
//this should exit the process, killing each connection pool
helper.pg.end();
});
[helper.config, helper.config, helper.config, helper.config].forEach(function(config) {
helper.pg.connect(config, function(err, client, done) {
assert.isNull(err);
client.query("SELECT * FROM NOW()", function(err, result) {
setTimeout(function() {
assert.equal(called, false, "Should not have disconnected yet")
sink.add();
done();
}, 0)
})
})
})
})

View File

@ -1,40 +1,50 @@
var helper = require("../test-helper");
var pg = require("../../../lib");
'use strict'
var helper = require('./test-helper')
const pg = helper.pg
//first make pool hold 2 clients
pg.defaults.poolSize = 2;
// first make pool hold 2 clients
pg.defaults.poolSize = 2
//get first client
pg.connect(helper.config, assert.success(function(client, done) {
client.id = 1;
client.query('SELECT NOW()', function() {
pg.connect(helper.config, assert.success(function(client2, done2) {
client2.id = 2;
var pidColName = 'procpid';
helper.versionGTE(client2, '9.2.0', assert.success(function(isGreater) {
var killIdleQuery = 'SELECT pid, (SELECT pg_terminate_backend(pid)) AS killed FROM pg_stat_activity WHERE state = $1';
var params = ['idle'];
if(!isGreater) {
killIdleQuery = 'SELECT procpid, (SELECT pg_terminate_backend(procpid)) AS killed FROM pg_stat_activity WHERE current_query LIKE $1';
params = ['%IDLE%']
}
const pool = new pg.Pool()
//subscribe to the pg error event
assert.emits(pg, 'error', function(error, brokenClient) {
assert.ok(error);
assert.ok(brokenClient);
assert.equal(client.id, brokenClient.id);
});
const suite = new helper.Suite()
suite.test('connecting to invalid port', (cb) => {
const pool = new pg.Pool({ port: 13801 })
pool.connect().catch(e => cb())
})
//kill the connection from client
client2.query(killIdleQuery, params, assert.success(function(res) {
//check to make sure client connection actually was killed
//return client2 to the pool
done2();
pg.end();
}));
}));
}));
suite.test('errors emitted on pool', (cb) => {
// get first client
pool.connect(assert.success(function (client, done) {
client.id = 1
client.query('SELECT NOW()', function () {
pool.connect(assert.success(function (client2, done2) {
client2.id = 2
var pidColName = 'procpid'
helper.versionGTE(client2, '9.2.0', assert.success(function (isGreater) {
var killIdleQuery = 'SELECT pid, (SELECT pg_terminate_backend(pid)) AS killed FROM pg_stat_activity WHERE state = $1'
var params = ['idle']
if (!isGreater) {
killIdleQuery = 'SELECT procpid, (SELECT pg_terminate_backend(procpid)) AS killed FROM pg_stat_activity WHERE current_query LIKE $1'
params = ['%IDLE%']
}
})
}));
pool.once('error', (err, brokenClient) => {
assert.ok(err)
assert.ok(brokenClient)
assert.equal(client.id, brokenClient.id)
cb()
})
// kill the connection from client
client2.query(killIdleQuery, params, assert.success(function (res) {
// check to make sure client connection actually was killed
// return client2 to the pool
done2()
pool.end()
}))
}))
}))
})
}))
})

View File

@ -1,14 +1,12 @@
var helper = require('./test-helper');
var _ = require('lodash')
'use strict'
var helper = require('./test-helper')
const config = _.extend({ }, helper.config, { idleTimeoutMillis: 50 })
test('idle timeout', function() {
helper.pg.connect(config, assert.calls(function(err, client, done) {
assert.isNull(err);
client.query('SELECT NOW()');
//just let this one time out
//test will hang if pool doesn't timeout
done();
}));
});
new helper.Suite().test('idle timeout', function () {
const config = Object.assign({}, helper.config, { idleTimeoutMillis: 50 })
const pool = new helper.pg.Pool(config)
pool.connect(assert.calls(function (err, client, done) {
assert(!err)
client.query('SELECT NOW()')
done()
}))
})

View File

@ -1,2 +0,0 @@
var helper = require("./test-helper")
helper.testPoolSize(40);

View File

@ -1,10 +1,11 @@
var helper = require("./../test-helper")
'use strict'
var helper = require('./../test-helper')
var pg = helper.pg
var native = helper.args.native
var pool = new pg.Pool()
pool.connect(assert.calls(function(err, client, done) {
pool.connect(assert.calls(function (err, client, done) {
if (native) {
assert(client.native)
} else {

View File

@ -1,20 +0,0 @@
var helper = require('./test-helper');
//setup defaults
helper.pg.defaults.user = helper.args.user;
helper.pg.defaults.password = helper.args.password;
helper.pg.defaults.host = helper.args.host;
helper.pg.defaults.port = helper.args.port;
helper.pg.defaults.database = helper.args.database;
helper.pg.defaults.poolSize = 1;
helper.pg.connect(assert.calls(function(err, client, done) {
assert.isNull(err);
client.query('SELECT NOW()');
client.once('drain', function() {
setTimeout(function() {
helper.pg.end();
done();
}, 10);
});
}));

View File

@ -1,2 +0,0 @@
var helper = require("./test-helper")
helper.testPoolSize(1);

View File

@ -1,13 +0,0 @@
var helper = require("../test-helper");
var pg = require("../../../lib");
pg.connect(helper.config, assert.success(function(client, done) {
assert.equal(Object.keys(pg._pools).length, 1);
pg.connect(helper.config, assert.success(function(client2, done2) {
assert.equal(Object.keys(pg._pools).length, 1);
done();
done2();
pg.end();
}));
}));

View File

@ -1,32 +1,31 @@
var helper = require(__dirname + "/../test-helper");
'use strict'
var helper = require('./../test-helper')
helper.testPoolSize = function(max) {
var sink = new helper.Sink(max, function() {
helper.pg.end();
});
const suite = new helper.Suite()
test("can pool " + max + " times", function() {
for(var i = 0; i < max; i++) {
helper.pg.poolSize = 10;
test("connection #" + i + " executes", function() {
helper.pg.connect(helper.config, function(err, client, done) {
assert.isNull(err);
client.query("select * from person", function(err, result) {
assert.lengthIs(result.rows, 26)
})
client.query("select count(*) as c from person", function(err, result) {
assert.equal(result.rows[0].c, 26)
})
var query = client.query("SELECT * FROM NOW()")
query.on('end',function() {
sink.add();
done();
})
helper.testPoolSize = function (max) {
suite.test(`test ${max} queries executed on a pool rapidly`, (cb) => {
const pool = new helper.pg.Pool({ max: 10 })
var sink = new helper.Sink(max, function () {
pool.end(cb)
})
for (var i = 0; i < max; i++) {
pool.connect(function (err, client, done) {
assert(!err)
client.query('SELECT * FROM NOW()')
client.query('select generate_series(0, 25)', function (err, result) {
assert.equal(result.rows.length, 26)
})
var query = client.query('SELECT * FROM NOW()', (err) => {
assert(!err)
sink.add()
done()
})
})
}
})
}
module.exports = helper;
module.exports = Object.assign({}, helper, { suite: suite })

View File

@ -1,2 +0,0 @@
var helper = require("./test-helper")
helper.testPoolSize(200);

View File

@ -1,28 +0,0 @@
var helper = require('./test-helper')
var co = require('co')
var tid = setTimeout(function() {
throw new Error('Tests did not complete in time')
}, 1000)
co(function * () {
var client = yield helper.pg.connect()
var res = yield client.query('SELECT $1::text as name', ['foo'])
assert.equal(res.rows[0].name, 'foo')
var threw = false
try {
yield client.query('SELECT LKDSJDSLKFJ')
} catch(e) {
threw = true
}
assert(threw)
client.release()
helper.pg.end()
clearTimeout(tid)
})
.catch(function(e) {
setImmediate(function() {
throw e
})
})

View File

@ -1,5 +1,20 @@
var semver = require('semver')
if (semver.lt(process.version, '1.0.0')) {
return console.log('yield is not supported in node <= v0.12')
}
require('./yield-support-body')
'use strict'
var helper = require('./test-helper')
var co = require('co')
const pool = new helper.pg.Pool()
new helper.Suite().test('using coroutines works with promises', co.wrap(function * () {
var client = yield pool.connect()
var res = yield client.query('SELECT $1::text as name', ['foo'])
assert.equal(res.rows[0].name, 'foo')
var threw = false
try {
yield client.query('SELECT LKDSJDSLKFJ')
} catch (e) {
threw = true
}
assert(threw)
client.release()
yield pool.end()
}))

View File

@ -1,60 +1,58 @@
var helper = require(__dirname + '/test-helper');
//http://developer.postgresql.org/pgdocs/postgres/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY
'use strict'
var helper = require(__dirname + '/test-helper')
// http://developer.postgresql.org/pgdocs/postgres/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY
test('flushing once', function() {
helper.connect(function(con) {
test('flushing once', function () {
helper.connect(function (con) {
con.parse({
text: 'select * from ids'
});
})
con.bind();
con.execute();
con.flush();
con.bind()
con.execute()
con.flush()
assert.emits(con, 'parseComplete');
assert.emits(con, 'bindComplete');
assert.emits(con, 'dataRow');
assert.emits(con, 'commandComplete', function(){
con.sync();
});
assert.emits(con, 'readyForQuery', function(){
con.end();
});
assert.emits(con, 'parseComplete')
assert.emits(con, 'bindComplete')
assert.emits(con, 'dataRow')
assert.emits(con, 'commandComplete', function () {
con.sync()
})
assert.emits(con, 'readyForQuery', function () {
con.end()
})
})
})
});
});
test('sending many flushes', function () {
helper.connect(function (con) {
assert.emits(con, 'parseComplete', function () {
con.bind()
con.flush()
})
test("sending many flushes", function() {
helper.connect(function(con) {
assert.emits(con, 'bindComplete', function () {
con.execute()
con.flush()
})
assert.emits(con, 'parseComplete', function(){
con.bind();
con.flush();
});
assert.emits(con, 'bindComplete', function(){
con.execute();
con.flush();
});
assert.emits(con, 'dataRow', function(msg){
assert.equal(msg.fields[0], 1);
assert.emits(con, 'dataRow', function(msg){
assert.equal(msg.fields[0], 2);
assert.emits(con, 'commandComplete', function(){
con.sync();
});
assert.emits(con, 'readyForQuery', function(){
con.end();
});
});
});
assert.emits(con, 'dataRow', function (msg) {
assert.equal(msg.fields[0], 1)
assert.emits(con, 'dataRow', function (msg) {
assert.equal(msg.fields[0], 2)
assert.emits(con, 'commandComplete', function () {
con.sync()
})
assert.emits(con, 'readyForQuery', function () {
con.end()
})
})
})
con.parse({
text: "select * from ids order by id"
});
text: 'select * from ids order by id'
})
con.flush();
});
});
con.flush()
})
})

View File

@ -1,44 +1,45 @@
var helper = require(__dirname+"/test-helper");
var assert = require('assert');
'use strict'
var helper = require(__dirname + '/test-helper')
var assert = require('assert')
test('COPY FROM events check', function () {
helper.connect(function (con) {
var stdinStream = con.query('COPY person FROM STDIN');
helper.connect(function (con) {
var stdinStream = con.query('COPY person FROM STDIN')
con.on('copyInResponse', function () {
con.endCopyFrom();
});
con.endCopyFrom()
})
assert.emits(con, 'copyInResponse',
function () {
con.endCopyFrom();
con.endCopyFrom()
},
"backend should emit copyInResponse after COPY FROM query"
);
'backend should emit copyInResponse after COPY FROM query'
)
assert.emits(con, 'commandComplete',
function () {
con.end();
con.end()
},
"backend should emit commandComplete after COPY FROM stream ends"
'backend should emit commandComplete after COPY FROM stream ends'
)
});
});
})
})
test('COPY TO events check', function () {
helper.connect(function (con) {
var stdoutStream = con.query('COPY person TO STDOUT');
var stdoutStream = con.query('COPY person TO STDOUT')
assert.emits(con, 'copyOutResponse',
function () {
},
"backend should emit copyOutResponse after COPY TO query"
);
'backend should emit copyOutResponse after COPY TO query'
)
assert.emits(con, 'copyData',
function () {
},
"backend should emit copyData on every data row"
);
'backend should emit copyData on every data row'
)
assert.emits(con, 'copyDone',
function () {
con.end();
con.end()
},
"backend should emit copyDone after all data rows"
);
});
});
'backend should emit copyDone after all data rows'
)
})
})

View File

@ -1,15 +1,16 @@
var helper = require(__dirname + '/test-helper');
//http://www.postgresql.org/docs/8.3/static/libpq-notify.html
test('recieves notification from same connection with no payload', function() {
helper.connect(function(con) {
con.query('LISTEN boom');
assert.emits(con, 'readyForQuery', function() {
con.query("NOTIFY boom");
assert.emits(con, 'notification', function(msg) {
assert.equal(msg.payload, "");
'use strict'
var helper = require(__dirname + '/test-helper')
// http://www.postgresql.org/docs/8.3/static/libpq-notify.html
test('recieves notification from same connection with no payload', function () {
helper.connect(function (con) {
con.query('LISTEN boom')
assert.emits(con, 'readyForQuery', function () {
con.query('NOTIFY boom')
assert.emits(con, 'notification', function (msg) {
assert.equal(msg.payload, '')
assert.equal(msg.channel, 'boom')
con.end();
});
});
});
});
con.end()
})
})
})
})

View File

@ -1,25 +1,26 @@
var helper = require(__dirname+"/test-helper");
var assert = require('assert');
'use strict'
var helper = require(__dirname + '/test-helper')
var assert = require('assert')
var rows = [];
//testing the low level 1-1 mapping api of client to postgres messages
//it's cumbersome to use the api this way
test('simple query', function() {
helper.connect(function(con) {
con.query('select * from ids');
assert.emits(con, 'dataRow');
con.on('dataRow', function(msg) {
rows.push(msg.fields);
});
assert.emits(con, 'readyForQuery', function() {
con.end();
});
});
});
var rows = []
// testing the low level 1-1 mapping api of client to postgres messages
// it's cumbersome to use the api this way
test('simple query', function () {
helper.connect(function (con) {
con.query('select * from ids')
assert.emits(con, 'dataRow')
con.on('dataRow', function (msg) {
rows.push(msg.fields)
})
assert.emits(con, 'readyForQuery', function () {
con.end()
})
})
})
process.on('exit', function() {
assert.equal(rows.length, 2);
assert.equal(rows[0].length, 1);
assert.strictEqual(String(rows[0] [0]), '1');
assert.strictEqual(String(rows[1] [0]), '2');
});
process.on('exit', function () {
assert.equal(rows.length, 2)
assert.equal(rows[0].length, 1)
assert.strictEqual(String(rows[0][0]), '1')
assert.strictEqual(String(rows[1][0]), '2')
})

View File

@ -1,42 +1,43 @@
var net = require('net');
var helper = require(__dirname+'/../test-helper');
var Connection = require(__dirname + '/../../../lib/connection');
var connect = function(callback) {
var username = helper.args.user;
var database = helper.args.database;
var con = new Connection({stream: new net.Stream()});
con.on('error', function(error){
console.log(error);
throw new Error("Connection error");
});
con.connect(helper.args.port || '5432', helper.args.host || 'localhost');
con.once('connect', function() {
'use strict'
var net = require('net')
var helper = require(__dirname + '/../test-helper')
var Connection = require(__dirname + '/../../../lib/connection')
var connect = function (callback) {
var username = helper.args.user
var database = helper.args.database
var con = new Connection({stream: new net.Stream()})
con.on('error', function (error) {
console.log(error)
throw new Error('Connection error')
})
con.connect(helper.args.port || '5432', helper.args.host || 'localhost')
con.once('connect', function () {
con.startup({
user: username,
database: database
});
con.once('authenticationCleartextPassword', function(){
con.password(helper.args.password);
});
con.once('authenticationMD5Password', function(msg){
//need js client even if native client is included
var client = require(__dirname +"/../../../lib/client");
var inner = client.md5(helper.args.password+helper.args.user);
var outer = client.md5(inner + msg.salt.toString('binary'));
con.password("md5"+outer);
});
con.once('readyForQuery', function() {
con.query('create temp table ids(id integer)');
con.once('readyForQuery', function() {
con.query('insert into ids(id) values(1); insert into ids(id) values(2);');
con.once('readyForQuery', function() {
callback(con);
});
});
});
});
};
})
con.once('authenticationCleartextPassword', function () {
con.password(helper.args.password)
})
con.once('authenticationMD5Password', function (msg) {
// need js client even if native client is included
var client = require(__dirname + '/../../../lib/client')
var inner = client.md5(helper.args.password + helper.args.user)
var outer = client.md5(inner + msg.salt.toString('binary'))
con.password('md5' + outer)
})
con.once('readyForQuery', function () {
con.query('create temp table ids(id integer)')
con.once('readyForQuery', function () {
con.query('insert into ids(id) values(1); insert into ids(id) values(2);')
con.once('readyForQuery', function () {
callback(con)
})
})
})
})
}
module.exports = {
connect: connect
};
}

View File

@ -1,58 +1,53 @@
var helper = require('./test-helper')
'use strict'
var async = require('async')
var testWithoutDomain = function(cb) {
test('no domain', function() {
var helper = require('./test-helper')
var Query = helper.pg.Query
var suite = new helper.Suite()
const Pool = helper.pg.Pool
suite.test('no domain', function (cb) {
assert(!process.domain)
const pool = new Pool()
pool.connect(assert.success(function (client, done) {
assert(!process.domain)
helper.pg.connect(helper.config, assert.success(function(client, done) {
assert(!process.domain)
done()
cb()
done()
pool.end(cb)
}))
})
suite.test('with domain', function (cb) {
assert(!process.domain)
const pool = new Pool()
var domain = require('domain').create()
domain.run(function () {
var startingDomain = process.domain
assert(startingDomain)
pool.connect(assert.success(function (client, done) {
assert(process.domain, 'no domain exists in connect callback')
assert.equal(startingDomain, process.domain, 'domain was lost when checking out a client')
var query = client.query('SELECT NOW()', assert.success(function () {
assert(process.domain, 'no domain exists in query callback')
assert.equal(startingDomain, process.domain, 'domain was lost when checking out a client')
done(true)
process.domain.exit()
pool.end(cb)
}))
}))
})
})
suite.test('error on domain', function (cb) {
var domain = require('domain').create()
const pool = new Pool()
domain.on('error', function () {
pool.end(cb)
})
domain.run(function () {
pool.connect(assert.success(function (client, done) {
client.query(new Query('SELECT SLDKJFLSKDJF'))
client.on('drain', done)
}))
})
}
var testWithDomain = function(cb) {
test('with domain', function() {
assert(!process.domain)
var domain = require('domain').create()
domain.run(function() {
var startingDomain = process.domain
assert(startingDomain)
helper.pg.connect(helper.config, assert.success(function(client, done) {
assert(process.domain, 'no domain exists in connect callback')
assert.equal(startingDomain, process.domain, 'domain was lost when checking out a client')
var query = client.query('SELECT NOW()', assert.success(function() {
assert(process.domain, 'no domain exists in query callback')
assert.equal(startingDomain, process.domain, 'domain was lost when checking out a client')
done(true)
process.domain.exit()
cb()
}))
}))
})
})
}
var testErrorWithDomain = function(cb) {
test('error on domain', function() {
var domain = require('domain').create()
domain.on('error', function() {
cb()
})
domain.run(function() {
helper.pg.connect(helper.config, assert.success(function(client, done) {
client.query('SELECT SLDKJFLSKDJF')
client.on('drain', done)
}))
})
})
}
async.series([
testWithoutDomain,
testWithDomain,
testErrorWithDomain
], function() {
helper.pg.end()
})

View File

@ -1,21 +1,23 @@
var helper = require(__dirname + '/../test-helper');
var exec = require('child_process').exec;
'use strict'
var helper = require(__dirname + '/../test-helper')
var exec = require('child_process').exec
helper.pg.defaults.poolIdleTimeout = 1000;
helper.pg.defaults.poolIdleTimeout = 1000
helper.pg.connect(helper.config, function(err,client) {
client.query("SELECT pg_backend_pid()", function(err, result) {
var pid = result.rows[0].pg_backend_pid;
var psql = 'psql';
if (helper.args.host) psql = psql+' -h '+helper.args.host;
if (helper.args.port) psql = psql+' -p '+helper.args.port;
if (helper.args.user) psql = psql+' -U '+helper.args.user;
exec(psql+' -c "select pg_terminate_backend('+pid+')" template1', assert.calls(function (error, stdout, stderr) {
assert.isNull(error);
}));
});
});
const pool = new helper.pg.Pool()
pool.connect(function (err, client) {
client.query('SELECT pg_backend_pid()', function (err, result) {
var pid = result.rows[0].pg_backend_pid
var psql = 'psql'
if (helper.args.host) psql = psql + ' -h ' + helper.args.host
if (helper.args.port) psql = psql + ' -p ' + helper.args.port
if (helper.args.user) psql = psql + ' -U ' + helper.args.user
exec(psql + ' -c "select pg_terminate_backend(' + pid + ')" template1', assert.calls(function (error, stdout, stderr) {
assert.isNull(error)
}))
})
})
helper.pg.on('error', function(err, client) {
//swallow errors
});
pool.on('error', function (err, client) {
// swallow errors
})

View File

@ -1,20 +1,22 @@
var helper = require(__dirname + "/../test-helper");
var pg = helper.pg;
'use strict'
var helper = require('../test-helper')
var pg = helper.pg
test('parsing array results', function() {
pg.connect(helper.config, assert.calls(function(err, client, done) {
assert.isNull(err);
client.query("CREATE TEMP TABLE why(names text[], numbors integer[], decimals double precision[])");
client.query('INSERT INTO why(names, numbors, decimals) VALUES(\'{"aaron", "brian","a b c" }\', \'{1, 2, 3}\', \'{.1, 0.05, 3.654}\')').on('error', console.log);
test('decimals', function() {
client.query('SELECT decimals FROM why', assert.success(function(result) {
assert.lengthIs(result.rows[0].decimals, 3);
assert.equal(result.rows[0].decimals[0], 0.1);
assert.equal(result.rows[0].decimals[1], 0.05);
assert.equal(result.rows[0].decimals[2], 3.654);
done()
pg.end();
}))
})
var suite = new helper.Suite()
suite.test('parsing array decimal results', function (done) {
const pool = new pg.Pool()
pool.connect(assert.calls(function (err, client, release) {
assert(!err)
client.query('CREATE TEMP TABLE why(names text[], numbors integer[], decimals double precision[])')
client.query(new pg.Query('INSERT INTO why(names, numbors, decimals) VALUES(\'{"aaron", "brian","a b c" }\', \'{1, 2, 3}\', \'{.1, 0.05, 3.654}\')')).on('error', console.log)
client.query('SELECT decimals FROM why', assert.success(function (result) {
assert.lengthIs(result.rows[0].decimals, 3)
assert.equal(result.rows[0].decimals[0], 0.1)
assert.equal(result.rows[0].decimals[1], 0.05)
assert.equal(result.rows[0].decimals[2], 3.654)
release()
pool.end(done)
}))
}))
})

View File

@ -1,21 +1,22 @@
var helper = require('../test-helper');
var client = helper.client();
'use strict'
var helper = require('../test-helper')
var client = helper.client()
client.query('CREATE TEMP TABLE arrtest (n integer, s varchar)');
client.query("INSERT INTO arrtest VALUES (4, 'foo'), (5, 'bar'), (6, 'baz');");
client.query('CREATE TEMP TABLE arrtest (n integer, s varchar)')
client.query("INSERT INTO arrtest VALUES (4, 'foo'), (5, 'bar'), (6, 'baz');")
var qText = "SELECT \
ARRAY[1, 2, 3] AS b,\
ARRAY['xx', 'yy', 'zz'] AS c,\
ARRAY(SELECT n FROM arrtest) AS d,\
ARRAY(SELECT s FROM arrtest) AS e;";
ARRAY(SELECT s FROM arrtest) AS e;"
client.query(qText, function(err, result) {
if(err) throw err;
var row = result.rows[0];
for(var key in row) {
assert.equal(typeof row[key], 'object');
assert.equal(row[key].length, 3);
client.query(qText, function (err, result) {
if (err) throw err
var row = result.rows[0]
for (var key in row) {
assert.equal(typeof row[key], 'object')
assert.equal(row[key].length, 3)
}
client.end();
});
client.end()
})

View File

@ -1,15 +1,17 @@
var helper = require(__dirname + "/../test-helper");
var pg = helper.pg;
'use strict'
var helper = require(__dirname + '/../test-helper')
var pg = helper.pg
test('parsing array results', function() {
pg.connect(helper.config, assert.success(function(client, done) {
new helper.Suite().test('parsing array results', function (cb) {
const pool = new pg.Pool()
pool.connect(assert.success(function (client, done) {
client.query('CREATE TEMP TABLE test_table(bar integer, "baz\'s" integer)')
client.query('INSERT INTO test_table(bar, "baz\'s") VALUES(1, 1), (2, 2)')
client.query('SELECT * FROM test_table', function(err, res) {
client.query('SELECT * FROM test_table', function (err, res) {
assert.equal(res.rows[0]["baz's"], 1)
assert.equal(res.rows[1]["baz's"], 2)
done()
pg.end()
pool.end(cb)
})
}))
})

View File

@ -1,49 +1,51 @@
var async = require('async');
var helper = require('../test-helper');
'use strict'
var async = require('async')
var helper = require('../test-helper')
const suite = new helper.Suite()
var db = helper.client();
var db = helper.client()
function createTableFoo(callback){
db.query("create temp table foo(column1 int, column2 int)", callback);
function createTableFoo (callback) {
db.query('create temp table foo(column1 int, column2 int)', callback)
}
function createTableBar(callback){
db.query("create temp table bar(column1 text, column2 text)", callback);
function createTableBar (callback) {
db.query('create temp table bar(column1 text, column2 text)', callback)
}
function insertDataFoo(callback){
db.query({
name: 'insertFoo',
text: 'insert into foo values($1,$2)',
values:['one','two']
}, callback );
function insertDataFoo (callback) {
db.query({
name: 'insertFoo',
text: 'insert into foo values($1,$2)',
values: ['one', 'two']
}, callback)
}
function insertDataBar(callback){
db.query({
name: 'insertBar',
text: 'insert into bar values($1,$2)',
values:['one','two']
}, callback );
function insertDataBar (callback) {
db.query({
name: 'insertBar',
text: 'insert into bar values($1,$2)',
values: ['one', 'two']
}, callback)
}
function startTransaction(callback) {
db.query('BEGIN', callback);
function startTransaction (callback) {
db.query('BEGIN', callback)
}
function endTransaction(callback) {
db.query('COMMIT', callback);
function endTransaction (callback) {
db.query('COMMIT', callback)
}
function doTransaction(callback) {
function doTransaction (callback) {
// The transaction runs startTransaction, then all queries, then endTransaction,
// no matter if there has been an error in a query in the middle.
startTransaction(function() {
insertDataFoo(function() {
insertDataBar(function() {
endTransaction( callback );
});
});
});
startTransaction(function () {
insertDataFoo(function () {
insertDataBar(function () {
endTransaction(callback)
})
})
})
}
var steps = [
@ -53,25 +55,26 @@ var steps = [
insertDataBar
]
test('test if query fails', function() {
async.series(steps, assert.success(function() {
suite.test('test if query fails', function (done) {
async.series(steps, assert.success(function () {
db.end()
done()
}))
})
test('test if prepare works but bind fails', function() {
var client = helper.client();
suite.test('test if prepare works but bind fails', function (done) {
var client = helper.client()
var q = {
text: 'SELECT $1::int as name',
values: ['brian'],
name: 'test'
};
client.query(q, assert.calls(function(err, res) {
q.values = [1];
client.query(q, assert.calls(function(err, res) {
assert.ifError(err);
client.end();
}));
}));
});
}
client.query(q, assert.calls(function (err, res) {
q.values = [1]
client.query(q, assert.calls(function (err, res) {
assert.ifError(err)
client.end()
done()
}))
}))
})

View File

@ -1,28 +1,30 @@
var helper = require('../test-helper');
var assert = require('assert');
'use strict'
var helper = require('../test-helper')
var assert = require('assert')
helper.pg.connect(helper.config, function(err, client, done) {
if (err) throw err;
const pool = new helper.pg.Pool()
pool.connect(function (err, client, done) {
if (err) throw err
var c = 'CREATE TEMP TABLE posts (body TEXT)';
var c = 'CREATE TEMP TABLE posts (body TEXT)'
client.query(c, function(err) {
if (err) throw err;
client.query(c, function (err) {
if (err) throw err
c = 'INSERT INTO posts (body) VALUES ($1) RETURNING *';
c = 'INSERT INTO posts (body) VALUES ($1) RETURNING *'
var body = new Buffer('foo');
client.query(c, [body], function(err) {
if (err) throw err;
var body = Buffer.from('foo')
client.query(c, [body], function (err) {
if (err) throw err
body = new Buffer([]);
client.query(c, [body], function(err, res) {
done();
body = Buffer.from([])
client.query(c, [body], function (err, res) {
done()
if (err) throw err;
if (err) throw err
assert.equal(res.rows[0].body, '')
helper.pg.end();
});
});
});
});
pool.end()
})
})
})
})

View File

@ -1,10 +1,12 @@
"use strict";
var helper = require('../test-helper');
var assert = require('assert');
var copyFrom = require('pg-copy-streams').from;
if(helper.args.native) return;
helper.pg.connect(helper.config, function (err, client, done) {
const pool = new helper.pg.Pool()
pool.connect(function (err, client, done) {
if (err) throw err;
var c = 'CREATE TEMP TABLE employee (id integer, fname varchar(400), lname varchar(400))';
@ -15,7 +17,9 @@ helper.pg.connect(helper.config, function (err, client, done) {
var stream = client.query(copyFrom("COPY employee FROM STDIN"));
stream.on('end', function () {
done();
helper.pg.end();
setTimeout(() => {
pool.end()
}, 50)
});
for (var i = 1; i <= 5; i++) {

View File

@ -1,11 +1,13 @@
var helper = require(__dirname + '/../test-helper');
'use strict'
var helper = require('../test-helper')
const pool = new helper.pg.Pool()
helper.pg.connect(helper.config, function(err,client) {
pool.connect(function (err, client) {
var q = {
name: 'This is a super long query name just so I can test that an error message is properly spit out to console.error without throwing an exception or anything',
text: 'SELECT NOW()'
};
client.query(q, function() {
client.end();
});
});
}
client.query(q, function () {
client.end()
})
})

View File

@ -1,8 +1,9 @@
//client should not hang on an empty query
var helper = require('../test-helper');
var client = helper.client();
client.query({ name: 'foo1', text: null});
client.query({ name: 'foo2', text: ' ' });
client.query({ name: 'foo3', text: '' }, function(err, res) {
client.end();
});
'use strict'
// client should not hang on an empty query
var helper = require('../test-helper')
var client = helper.client()
client.query({ name: 'foo1', text: null})
client.query({ name: 'foo2', text: ' ' })
client.query({ name: 'foo3', text: '' }, function (err, res) {
client.end()
})

View File

@ -1,7 +1,8 @@
var helper = require(__dirname + '/../test-helper');
"use strict";
var helper = require('./../test-helper');
//native bindings are only installed for native tests
if(!helper.args.native) {
if (!helper.args.native) {
return;
}
@ -15,13 +16,23 @@ var NativeClient = require('../../../lib/native')
assert(pg.Client === JsClient);
assert(native.Client === NativeClient);
pg.connect(function(err, client, done) {
assert(client instanceof JsClient);
client.end();
const jsPool = new pg.Pool()
const nativePool = new native.Pool()
native.connect(function(err, client, done) {
const suite = new helper.Suite()
suite.test('js pool returns js client', cb => {
jsPool.connect(function (err, client, done) {
assert(client instanceof JsClient);
done()
jsPool.end(cb)
})
})
suite.test('native pool returns native client', cb => {
nativePool.connect(function (err, client, done) {
assert(client instanceof NativeClient);
client.end();
done()
nativePool.end(cb)
});
});
})

View File

@ -1,27 +1,27 @@
var helper = require(__dirname + '/../test-helper');
'use strict'
var helper = require('./../test-helper')
if(helper.args.native) {
Client = require(__dirname + '/../../lib/native');
helper.Client = Client;
helper.pg = helper.pg.native;
if (helper.args.native) {
Client = require('./../../lib/native')
helper.Client = Client
helper.pg = helper.pg.native
}
//creates a client from cli parameters
helper.client = function(cb) {
var client = new Client(helper.config);
client.connect(cb);
return client;
};
// creates a client from cli parameters
helper.client = function (cb) {
var client = new Client()
client.connect(cb)
return client
}
var semver = require('semver');
helper.versionGTE = function(client, versionString, callback) {
client.query('SELECT version()', assert.calls(function(err, result) {
if(err) return callback(err);
var version = result.rows[0].version.split(' ')[1];
return callback(null, semver.gte(version, versionString));
}));
};
//export parent helper stuffs
module.exports = helper;
var semver = require('semver')
helper.versionGTE = function (client, versionString, callback) {
client.query('SELECT version()', assert.calls(function (err, result) {
if (err) return callback(err)
var version = result.rows[0].version.split(' ')[1]
return callback(null, semver.gte(version, versionString))
}))
}
// export parent helper stuffs
module.exports = helper

View File

@ -1,32 +1,34 @@
var domain = require('domain');
var helper = require(__dirname + "/../test-helper");
var Client = require(__dirname + "/../../lib/native");
'use strict'
var domain = require('domain')
var helper = require('./../test-helper')
var Client = require('./../../lib/native')
const suite = new helper.Suite()
test('fires callback with results', function() {
var client = new Client(helper.config);
client.connect();
client.query('SELECT 1 as num', assert.calls(function(err, result) {
assert.isNull(err);
assert.equal(result.rows[0].num, 1);
assert.strictEqual(result.rowCount, 1);
client.query('SELECT * FROM person WHERE name = $1', ['Brian'], assert.calls(function(err, result) {
assert.isNull(err);
assert.equal(result.rows[0].name, 'Brian');
client.end();
suite.test('fires callback with results', function (done) {
var client = new Client(helper.config)
client.connect()
client.query('SELECT 1 as num', assert.calls(function (err, result) {
assert(!err)
assert.equal(result.rows[0].num, 1)
assert.strictEqual(result.rowCount, 1)
client.query('SELECT * FROM person WHERE name = $1', ['Brian'], assert.calls(function (err, result) {
assert(!err)
assert.equal(result.rows[0].name, 'Brian')
client.end(done)
}))
}));
}))
})
test('preserves domain', function() {
var dom = domain.create();
suite.test('preserves domain', function (done) {
var dom = domain.create()
dom.run(function() {
var client = new Client(helper.config);
assert.ok(dom === require('domain').active, 'domain is active');
dom.run(function () {
var client = new Client(helper.config)
assert.ok(dom === require('domain').active, 'domain is active')
client.connect()
client.query('select 1', function() {
assert.ok(dom === require('domain').active, 'domain is still active');
client.end();
});
});
client.query('select 1', function () {
assert.ok(dom === require('domain').active, 'domain is still active')
client.end(done)
})
})
})

View File

@ -1,36 +0,0 @@
var helper = require(__dirname + "/../test-helper");
var Client = require(__dirname + "/../../lib/native");
var domain = require('domain');
test('connecting with wrong parameters', function() {
var con = new Client("user=asldfkj hostaddr=127.0.0.1 port=5432 dbname=asldkfj");
assert.emits(con, 'error', function(error) {
assert.ok(error != null, "error should not be null");
con.end();
});
con.connect();
});
test('connects', function() {
var con = new Client(helper.config);
con.connect();
assert.emits(con, 'connect', function() {
test('disconnects', function() {
con.end();
})
})
})
test('preserves domain', function() {
var dom = domain.create();
dom.run(function() {
var con = new Client(helper.config);
assert.ok(dom === require('domain').active, 'domain is active');
con.connect(function() {
assert.ok(dom === require('domain').active, 'domain is still active');
con.end();
});
});
})

View File

@ -1,68 +0,0 @@
var helper = require(__dirname + "/../test-helper");
var Client = require(__dirname + "/../../lib/native");
test('query with non-text as first parameter throws error', function() {
var client = new Client(helper.config);
client.connect();
assert.emits(client, 'connect', function() {
client.end();
assert.emits(client, 'end', function() {
assert.throws(function() {
client.query({text:{fail: true}});
});
});
});
});
test('parameterized query with non-text as first parameter throws error', function() {
var client = new Client(helper.config);
client.connect();
assert.emits(client, 'connect', function() {
client.end();
assert.emits(client, 'end', function() {
assert.throws(function() {
client.query({
text: {fail: true},
values: [1, 2]
})
});
});
});
});
var connect = function(callback) {
var client = new Client(helper.config);
client.connect();
assert.emits(client, 'connect', function() {
callback(client);
})
}
test('parameterized query with non-array for second value', function() {
test('inline', function() {
connect(function(client) {
client.end();
assert.emits(client, 'end', function() {
assert.throws(function() {
client.query("SELECT *", "LKSDJF")
});
});
});
});
test('config', function() {
connect(function(client) {
client.end();
assert.emits(client, 'end', function() {
assert.throws(function() {
client.query({
text: "SELECT *",
values: "ALSDKFJ"
});
});
});
});
});
});

View File

@ -1,59 +1,34 @@
var helper = require(__dirname + "/../test-helper");
var Client = require(__dirname + "/../../lib/native");
'use strict'
var helper = require('../test-helper')
var Client = require('../../lib/native')
var Query = Client.Query
var setupClient = function() {
var client = new Client(helper.config);
client.connect();
client.query("CREATE TEMP TABLE boom(name varchar(10), age integer)");
client.query("INSERT INTO boom(name, age) VALUES('Aaron', 26)");
client.query("INSERT INTO boom(name, age) VALUES('Brian', 28)");
return client;
var setupClient = function () {
var client = new Client(helper.config)
client.connect()
client.query('CREATE TEMP TABLE boom(name varchar(10), age integer)')
client.query("INSERT INTO boom(name, age) VALUES('Aaron', 26)")
client.query("INSERT INTO boom(name, age) VALUES('Brian', 28)")
return client
}
//test('connects', function() {
//var client = new Client(helper.config);
//client.connect();
//test('good query', function() {
//var query = client.query("SELECT 1 as num, 'HELLO' as str");
//assert.emits(query, 'row', function(row) {
//test('has integer data type', function() {
//assert.strictEqual(row.num, 1);
//})
//test('has string data type', function() {
//assert.strictEqual(row.str, "HELLO")
//})
//test('emits end AFTER row event', function() {
//assert.emits(query, 'end');
//test('error query', function() {
//var query = client.query("LSKDJF");
//assert.emits(query, 'error', function(err) {
//assert.ok(err != null, "Should not have emitted null error");
//client.end();
//})
//})
//})
//})
//})
//})
test('multiple results', function() {
test('queued queries', function() {
var client = setupClient();
var q = client.query("SELECT name FROM BOOM");
assert.emits(q, 'row', function(row) {
assert.equal(row.name, 'Aaron');
assert.emits(q, 'row', function(row) {
assert.equal(row.name, "Brian");
test('multiple results', function () {
test('queued queries', function () {
var client = setupClient()
var q = client.query(new Query('SELECT name FROM BOOM'))
assert.emits(q, 'row', function (row) {
assert.equal(row.name, 'Aaron')
assert.emits(q, 'row', function (row) {
assert.equal(row.name, 'Brian')
})
})
assert.emits(q, 'end', function() {
test('query with config', function() {
var q2 = client.query({text:'SELECT 1 as num'});
assert.emits(q2, 'row', function(row) {
assert.strictEqual(row.num, 1);
assert.emits(q2, 'end', function() {
client.end();
assert.emits(q, 'end', function () {
test('query with config', function () {
var q2 = client.query(new Query({text: 'SELECT 1 as num'}))
assert.emits(q2, 'row', function (row) {
assert.strictEqual(row.num, 1)
assert.emits(q2, 'end', function () {
client.end()
})
})
})
@ -61,55 +36,55 @@ test('multiple results', function() {
})
})
test('parameterized queries', function() {
test('with a single string param', function() {
var client = setupClient();
var q = client.query("SELECT * FROM boom WHERE name = $1", ['Aaron']);
assert.emits(q, 'row', function(row) {
assert.equal(row.name, 'Aaron');
test('parameterized queries', function () {
test('with a single string param', function () {
var client = setupClient()
var q = client.query(new Query('SELECT * FROM boom WHERE name = $1', ['Aaron']))
assert.emits(q, 'row', function (row) {
assert.equal(row.name, 'Aaron')
})
assert.emits(q, 'end', function () {
client.end()
})
assert.emits(q, 'end', function() {
client.end();
});
})
test('with object config for query', function() {
var client = setupClient();
var q = client.query({
text: "SELECT name FROM boom WHERE name = $1",
test('with object config for query', function () {
var client = setupClient()
var q = client.query(new Query({
text: 'SELECT name FROM boom WHERE name = $1',
values: ['Brian']
});
assert.emits(q, 'row', function(row) {
assert.equal(row.name, 'Brian');
}))
assert.emits(q, 'row', function (row) {
assert.equal(row.name, 'Brian')
})
assert.emits(q, 'end', function() {
client.end();
assert.emits(q, 'end', function () {
client.end()
})
})
test('multiple parameters', function() {
var client = setupClient();
var q = client.query('SELECT name FROM boom WHERE name = $1 or name = $2 ORDER BY name', ['Aaron', 'Brian']);
assert.emits(q, 'row', function(row) {
assert.equal(row.name, 'Aaron');
assert.emits(q, 'row', function(row) {
assert.equal(row.name, 'Brian');
assert.emits(q, 'end', function() {
client.end();
test('multiple parameters', function () {
var client = setupClient()
var q = client.query(new Query('SELECT name FROM boom WHERE name = $1 or name = $2 ORDER BY name', ['Aaron', 'Brian']))
assert.emits(q, 'row', function (row) {
assert.equal(row.name, 'Aaron')
assert.emits(q, 'row', function (row) {
assert.equal(row.name, 'Brian')
assert.emits(q, 'end', function () {
client.end()
})
})
})
})
test('integer parameters', function() {
var client = setupClient();
var q = client.query('SELECT * FROM boom WHERE age > $1', [27]);
assert.emits(q, 'row', function(row) {
assert.equal(row.name, 'Brian');
assert.equal(row.age, 28);
});
assert.emits(q, 'end', function() {
client.end();
test('integer parameters', function () {
var client = setupClient()
var q = client.query(new Query('SELECT * FROM boom WHERE age > $1', [27]))
assert.emits(q, 'row', function (row) {
assert.equal(row.name, 'Brian')
assert.equal(row.age, 28)
})
assert.emits(q, 'end', function () {
client.end()
})
})
})

View File

@ -1,6 +1,7 @@
//this test assumes it has been run from the Makefile
//and that node_modules/pg-native has been deleted
'use strict'
// this test assumes it has been run from the Makefile
// and that node_modules/pg-native has been deleted
var assert = require('assert');
var assert = require('assert')
assert.equal(require('../../lib').native, null);
assert.equal(require('../../lib').native, null)

View File

@ -0,0 +1,21 @@
'use strict'
var assert = require('assert')
var Client = require('../../lib/client')
var NativeClient = require('../../lib/native')
var client = new Client()
var nativeClient = new NativeClient()
client.connect()
nativeClient.connect((err) => {
client.query('SELECT alsdkfj', (err) => {
client.end()
nativeClient.query('SELECT lkdasjfasd', (nativeErr) => {
for (var key in nativeErr) {
assert.equal(err[key], nativeErr[key], `Expected err.${key} to equal nativeErr.${key}`)
}
nativeClient.end()
})
})
})

Some files were not shown because too many files have changed in this diff Show More