Source: db/mongo/ConnectionPool.js

/**
 * @file Configure MongoDB connections using the same connection pool. Uses Mongoose >4.1.0 for Promise integration
 * @version 2.0
 * @author Boris GBAHOUE
 * @module amiwo/db/mongo
 */

// =======================================================================
// BASIC SETUP
// =======================================================================
// Load the packages we need
const debug             = require('debug')('amiwo:db');
const when              = require('when');
const u                 = require('../../util');

// Mongoose helper
const mongoose          = require('mongoose');

// MongoDB module objects
const mongo             = require('mongodb').MongoClient;

// Load our objects
const GenericError      = require('../../error/GenericError');

// =======================================================================
// CONSTRUCTOR
// =======================================================================
/**
 * @class 
 * @classdesc Configure MongoDB connections using the same connection pool. Uses Mongoose >4.1.0 for Promise integration
 * 
 * @constructor
 * @param {String} name : name of this connection pool; a global variable with this name will be created referencing the connection created
 * @param {Object} uri : DB URI
 * @param {Object} [options] : connection options
 * @param {Object} [options.direct=false] : create a connection pool using Mongo direct client (not just mongoose); accessible through global variable 'name' (if options.mongoose == false) or 'name+"_direct"' (in any case)
 * @param {Object} [options.mongoose=true] : create a connection pool using Mongoose helper; accessible through global variable 'name' 
 */
function ConnectionPool(name, uri, options) {
    mongoose.Promise = when.Promise;
    
    this.uri = uri;
    this.name = name;
    let $options = u.clone(options);

    // Options processing
    if ($options == null) $options = {};
    //  - options.direct
    $options.direct = (""+$options.direct === "true") ? true : false; // null -> false
    //  - options.mongoose
    $options.mongoose = (""+$options.mongoose === "false") ? false : true; // null -> true
    this.options = $options;

    this.connection = {};
    if ($options.mongoose) {
        this.connection.mongoose = mongoose.createConnection();
        global[name] = this.connection.mongoose;
    }
    // Will create the direct connection later
};

// =======================================================================
// PUBLIC METHODS
// =======================================================================
/**
 * Open the connection to the session database.
 * Since v2.0 Creates both a Mongo (direct driver) and Mongoose connection pool (Mongoose by default, Mongo upon request)
 *
 * @returns {Promise}
 * @method
 */
ConnectionPool.prototype.connect = function(delay) {
    const self = this;

    debug("::AMIWO::MONGO::CONNECTIONPOOL::%s::CONNECT::LOG Connecting to %s", self.name, self.uri);

    // Open connection
    const promiseArray = [];

    // Mongoose
    if (self.options.mongoose) {
        promiseArray.push(
            self.connection.mongoose.open(self.uri, self.options)
            .then(function(ok) {
                debug('::AMIWO::MONGO::CONNECTIONPOOL::%s::LOG Connected to Mongo database through Mongoose', self.name);
                return when.resolve(true);

            }).catch(function(err) {
                const errorMessage = 'Error Connecting to Mongo ' + self.name + ' database through Mongoose';
                debug("::AMIWO::MONGO::CONNECTIONPOOL::%s::ERROR %s => err=%s, trace=%s", self.name, errorMessage, err, err.stack);
                
                return when.reject(new GenericError(errorMessage, err));
            })
        );
    }
    if (self.options.direct) {
        promiseArray.push(
            mongo.connect(self.uri, self.options)
            .then(function(db) {
                debug('::AMIWO::MONGO::CONNECTIONPOOL::%s::LOG Connected to Mongo database through direct driver', self.name);
                self.connection.direct = db;
                global[self.name+"_direct"] = self.connection.direct;
                if (self.options.mongoose == false) global[self.name] = self.connection.direct;
                
                return when.resolve(true);

            }).catch(function(err) {
                const errorMessage = 'Error Connecting to Mongo ' + self.name + ' database through direct driver';
                debug("::AMIWO::MONGO::CONNECTIONPOOL::%s::ERROR %s => err=%s, trace=%s", self.name, errorMessage, err, err.stack);
                
                return when.reject(new GenericError(errorMessage, err));
            })
        );
    }

    return when.all(promiseArray)
    .then(function(results) {
        // Register listeners to close the connection on exit / crashes
        process.on('exit', $exitHandler.bind(self, "exit"));
        process.on('SIGINT', $exitHandler.bind(self, "SIGINT"));
        process.on('uncaughtException', $exitHandler.bind(self, "uncaughtException"));

    }).catch(function(err) {
        // Pass it on
        return when.reject(err);
    })
};

// =======================================================================
// PRIVATE METHODS
// =======================================================================
/**
 * Close the connection to the MongoDB
 * 
 * @memberOf ConnectionPool
 * @private
 */
function $exitHandler(source) {
    if (this.connection) {
        debug("::AMIWO::MONGO::CONNECTIONPOOL::%s::EXITHANDLER::%s::LOG Closing connection to %s", this.name, source, this.uri);
        if (this.connection.mongoose) this.connection.mongoose.close();
        if (this.connection.direct) this.connection.direct.close();
        this.connection = null;
    }
}

module.exports = ConnectionPool;