mirror of
https://github.com/brianc/node-postgres.git
synced 2026-01-18 15:55:05 +00:00
commit
8cc7308835
6
.eslintrc
Normal file
6
.eslintrc
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "standard",
|
||||
"rules": {
|
||||
"no-new-func": "off"
|
||||
}
|
||||
}
|
||||
33
.travis.yml
33
.travis.yml
@ -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"
|
||||
|
||||
10
CHANGELOG.md
10
CHANGELOG.md
@ -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).
|
||||
|
||||
12
Makefile
12
Makefile
@ -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
|
||||
|
||||
591
lib/client.js
591
lib/client.js
@ -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
|
||||
|
||||
@ -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
@ -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)
|
||||
})
|
||||
|
||||
130
lib/index.js
130
lib/index.js
@ -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
226
lib/native/client.js
Normal 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)
|
||||
}
|
||||
@ -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')
|
||||
|
||||
@ -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)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -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.
|
||||
};
|
||||
@ -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;
|
||||
};
|
||||
330
lib/query.js
330
lib/query.js
@ -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
|
||||
|
||||
165
lib/result.js
165
lib/result.js
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
202
lib/utils.js
202
lib/utils.js
@ -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
|
||||
}
|
||||
|
||||
24
package.json
24
package.json
@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@ -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()
|
||||
})
|
||||
|
||||
@ -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()
|
||||
})
|
||||
})
|
||||
|
||||
@ -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)
|
||||
}))
|
||||
|
||||
@ -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
|
||||
|
||||
37
test/cli.js
37
test/cli.js
@ -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
|
||||
|
||||
@ -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()
|
||||
})
|
||||
)
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
@ -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()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@ -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
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -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]
|
||||
}
|
||||
})
|
||||
|
||||
@ -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)
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
@ -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
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -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)
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
var helper = require('./test-helper')
|
||||
|
||||
var client = helper.client(assert.success(function() {
|
||||
client.end(assert.success(function() {
|
||||
}))
|
||||
}))
|
||||
@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
}))
|
||||
|
||||
@ -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()
|
||||
}))
|
||||
}))
|
||||
}))
|
||||
|
||||
69
test/integration/client/multiple-results-tests.js
Normal file
69
test/integration/client/multiple-results-tests.js
Normal 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()
|
||||
}))
|
||||
@ -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)
|
||||
})
|
||||
|
||||
@ -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))
|
||||
})
|
||||
|
||||
@ -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)
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
@ -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()
|
||||
})
|
||||
})
|
||||
|
||||
@ -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()
|
||||
}))
|
||||
}))
|
||||
}))
|
||||
})
|
||||
|
||||
@ -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())
|
||||
})()
|
||||
|
||||
50
test/integration/client/promise-api-tests.js
Normal file
50
test/integration/client/promise-api-tests.js
Normal 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)
|
||||
})
|
||||
})
|
||||
@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -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()
|
||||
}))
|
||||
}))
|
||||
})
|
||||
|
||||
@ -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)
|
||||
}))
|
||||
})
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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))
|
||||
}))
|
||||
}))
|
||||
}))
|
||||
}))
|
||||
}))
|
||||
})
|
||||
|
||||
@ -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()
|
||||
}))
|
||||
}))
|
||||
})
|
||||
|
||||
@ -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()
|
||||
}))
|
||||
}))
|
||||
})
|
||||
|
||||
@ -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))
|
||||
})
|
||||
|
||||
@ -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()
|
||||
}))
|
||||
}))
|
||||
})
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
var helper = require(__dirname+'/../test-helper');
|
||||
'use strict'
|
||||
var helper = require('./../test-helper')
|
||||
|
||||
module.exports = helper;
|
||||
module.exports = helper
|
||||
|
||||
@ -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
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -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();
|
||||
})
|
||||
}));
|
||||
})
|
||||
|
||||
@ -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)
|
||||
})
|
||||
}))
|
||||
})
|
||||
|
||||
@ -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())
|
||||
})
|
||||
}))
|
||||
}))
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
'use strict'
|
||||
var helper = require('./test-helper')
|
||||
|
||||
helper.testPoolSize(1)
|
||||
|
||||
helper.testPoolSize(2)
|
||||
|
||||
helper.testPoolSize(40)
|
||||
|
||||
helper.testPoolSize(200)
|
||||
@ -1,2 +0,0 @@
|
||||
var helper = require("./test-helper")
|
||||
helper.testPoolSize(2);
|
||||
@ -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();
|
||||
})
|
||||
|
||||
|
||||
@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -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()
|
||||
}))
|
||||
}))
|
||||
}))
|
||||
})
|
||||
}))
|
||||
})
|
||||
|
||||
@ -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()
|
||||
}))
|
||||
})
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
var helper = require("./test-helper")
|
||||
helper.testPoolSize(40);
|
||||
@ -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 {
|
||||
|
||||
@ -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);
|
||||
});
|
||||
}));
|
||||
@ -1,2 +0,0 @@
|
||||
var helper = require("./test-helper")
|
||||
helper.testPoolSize(1);
|
||||
@ -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();
|
||||
}));
|
||||
}));
|
||||
@ -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 })
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
var helper = require("./test-helper")
|
||||
helper.testPoolSize(200);
|
||||
@ -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
|
||||
})
|
||||
})
|
||||
@ -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()
|
||||
}))
|
||||
|
||||
@ -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()
|
||||
})
|
||||
})
|
||||
|
||||
@ -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'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -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()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -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')
|
||||
})
|
||||
|
||||
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
@ -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()
|
||||
})
|
||||
|
||||
@ -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
|
||||
})
|
||||
|
||||
@ -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)
|
||||
}))
|
||||
}))
|
||||
})
|
||||
|
||||
@ -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()
|
||||
})
|
||||
|
||||
@ -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)
|
||||
})
|
||||
}))
|
||||
})
|
||||
|
||||
@ -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()
|
||||
}))
|
||||
}))
|
||||
})
|
||||
|
||||
@ -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()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -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++) {
|
||||
|
||||
@ -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()
|
||||
})
|
||||
})
|
||||
|
||||
@ -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()
|
||||
})
|
||||
|
||||
@ -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)
|
||||
});
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -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();
|
||||
});
|
||||
});
|
||||
})
|
||||
@ -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"
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -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()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -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)
|
||||
|
||||
21
test/native/native-vs-js-error-tests.js
Normal file
21
test/native/native-vs-js-error-tests.js
Normal 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
Loading…
x
Reference in New Issue
Block a user