'use strict'; var AbstractConnectionManager = require('../abstract/connection-manager') , ConnectionManager , Utils = require('../../utils') , Promise = require('../../promise') , sequelizeErrors = require('../../errors'); ConnectionManager = function(dialect, sequelize) { AbstractConnectionManager.call(this, dialect, sequelize); this.sequelize = sequelize; this.sequelize.config.port = this.sequelize.config.port || 5432; try { this.lib = sequelize.config.native ? require(sequelize.config.dialectModulePath || 'pg').native : require(sequelize.config.dialectModulePath || 'pg'); } catch (err) { throw new Error('Please install postgres package manually'); } }; Utils._.extend(ConnectionManager.prototype, AbstractConnectionManager.prototype); ConnectionManager.prototype.connect = function(config) { var self = this , connectionConfig = {}; config.user = config.username; connectionConfig = Utils._.pick(config, [ 'user', 'password', 'host', 'database', 'port' ]); if (config.dialectOptions) { Utils._.merge(connectionConfig, Utils._.pick(config.dialectOptions, [ // see [http://www.postgresql.org/docs/9.3/static/runtime-config-logging.html#GUC-APPLICATION-NAME] 'application_name', // choose the SSL mode with the PGSSLMODE environment variable // object format: [https://github.com/brianc/node-postgres/blob/master/lib/connection.js#L79] // see also [http://www.postgresql.org/docs/9.3/static/libpq-ssl.html] 'ssl', // In addition to the values accepted by the corresponding server, // you can use "auto" to determine the right encoding from the // current locale in the client (LC_CTYPE environment variable on Unix systems) 'client_encoding', // !! DONT SET THIS TO TRUE !! // (unless you know what you're doing) // see [http://www.postgresql.org/message-id/flat/bc9549a50706040852u27633f41ib1e6b09f8339d845@mail.gmail.com#bc9549a50706040852u27633f41ib1e6b09f8339d845@mail.gmail.com] 'binary' ])); } return new Promise(function (resolve, reject) { var connection = new self.lib.Client(connectionConfig) , responded = false; connection.connect(function(err) { if (err) { if (err.code) { switch (err.code) { case 'ECONNREFUSED': reject(new sequelizeErrors.ConnectionRefusedError(err)); break; case 'ENOTFOUND': reject(new sequelizeErrors.HostNotFoundError(err)); break; case 'EHOSTUNREACH': reject(new sequelizeErrors.HostNotReachableError(err)); break; case 'EINVAL': reject(new sequelizeErrors.InvalidConnectionError(err)); break; default: reject(new sequelizeErrors.ConnectionError(err)); break; } } else { reject(new sequelizeErrors.ConnectionError(err)); } return; } responded = true; resolve(connection); }); // If we didn't ever hear from the client.connect() callback the connection timeout, node-postgres does not treat this as an error since no active query was ever emitted connection.on('end', function () { if (!responded) { reject(new sequelizeErrors.ConnectionTimedOutError(new Error('Connection timed out'))); } }); // Don't let a Postgres restart (or error) to take down the whole app connection.on('error', function() { connection._invalid = true; }); }).tap(function (connection) { // Disable escape characters in strings, see https://github.com/sequelize/sequelize/issues/3545 var query = 'SET standard_conforming_strings=on;'; if (!self.sequelize.config.keepDefaultTimezone) { query += 'SET client_min_messages TO warning; SET TIME ZONE INTERVAL \'' + self.sequelize.options.timezone + '\' HOUR TO MINUTE'; } return new Promise(function (resolve, reject) { connection.query(query).on('error', function (err) { reject(err); }).on('end', function () { resolve(); }); }); }); }; ConnectionManager.prototype.disconnect = function(connection) { return new Promise(function (resolve, reject) { connection.end(); resolve(); }); }; ConnectionManager.prototype.validate = function(connection) { return connection._invalid === undefined; }; module.exports = ConnectionManager;