HTMLify
connection.js
Views: 8 | Author: cody
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | /*! * Module dependencies. */ 'use strict'; const MongooseConnection = require('../../connection'); const STATES = require('../../connectionstate'); /** * A [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) connection implementation. * * @inherits Connection * @api private */ function NativeConnection() { MongooseConnection.apply(this, arguments); this._listening = false; } /** * Expose the possible connection states. * @api public */ NativeConnection.STATES = STATES; /*! * Inherits from Connection. */ NativeConnection.prototype.__proto__ = MongooseConnection.prototype; /** * Switches to a different database using the same connection pool. * * Returns a new connection object, with the new db. If you set the `useCache` * option, `useDb()` will cache connections by `name`. * * @param {String} name The database name * @param {Object} [options] * @param {Boolean} [options.useCache=false] If true, cache results so calling `useDb()` multiple times with the same name only creates 1 connection object. * @return {Connection} New Connection Object * @api public */ NativeConnection.prototype.useDb = function(name, options) { // Return immediately if cached if (options && options.useCache && this.relatedDbs[name]) { return this.relatedDbs[name]; } // we have to manually copy all of the attributes... const newConn = new this.constructor(); newConn.name = name; newConn.base = this.base; newConn.collections = {}; newConn.models = {}; newConn.replica = this.replica; newConn.config = Object.assign({}, this.base.connection.config, newConn.config); newConn.name = this.name; newConn.options = this.options; newConn._readyState = this._readyState; newConn._closeCalled = this._closeCalled; newConn._hasOpened = this._hasOpened; newConn._listening = false; newConn.host = this.host; newConn.port = this.port; newConn.user = this.user; newConn.pass = this.pass; // First, when we create another db object, we are not guaranteed to have a // db object to work with. So, in the case where we have a db object and it // is connected, we can just proceed with setting everything up. However, if // we do not have a db or the state is not connected, then we need to wait on // the 'open' event of the connection before doing the rest of the setup // the 'connected' event is the first time we'll have access to the db object const _this = this; newConn.client = _this.client; if (this.db && this._readyState === STATES.connected) { wireup(); } else { this.once('connected', wireup); } function wireup() { newConn.client = _this.client; newConn.db = _this.client.db(name); newConn.onOpen(); // setup the events appropriately listen(newConn); } newConn.name = name; // push onto the otherDbs stack, this is used when state changes this.otherDbs.push(newConn); newConn.otherDbs.push(this); // push onto the relatedDbs cache, this is used when state changes if (options && options.useCache) { this.relatedDbs[newConn.name] = newConn; newConn.relatedDbs = this.relatedDbs; } return newConn; }; /*! * Register listeners for important events and bubble appropriately. */ function listen(conn) { if (conn.db._listening) { return; } conn.db._listening = true; conn.db.on('close', function(force) { if (conn._closeCalled) return; // the driver never emits an `open` event. auto_reconnect still // emits a `close` event but since we never get another // `open` we can't emit close if (conn.db.serverConfig.autoReconnect) { conn.readyState = STATES.disconnected; conn.emit('close'); return; } conn.onClose(force); }); conn.db.on('error', function(err) { conn.emit('error', err); }); conn.db.on('reconnect', function() { conn.readyState = STATES.connected; conn.emit('reconnect'); conn.emit('reconnected'); conn.onOpen(); }); conn.db.on('timeout', function(err) { conn.emit('timeout', err); }); conn.db.on('open', function(err, db) { if (STATES.disconnected === conn.readyState && db && db.databaseName) { conn.readyState = STATES.connected; conn.emit('reconnect'); conn.emit('reconnected'); } }); conn.db.on('parseError', function(err) { conn.emit('parseError', err); }); } /** * Closes the connection * * @param {Boolean} [force] * @param {Function} [fn] * @return {Connection} this * @api private */ NativeConnection.prototype.doClose = function(force, fn) { this.client.close(force, (err, res) => { // Defer because the driver will wait at least 1ms before finishing closing // the pool, see https://github.com/mongodb-js/mongodb-core/blob/a8f8e4ce41936babc3b9112bf42d609779f03b39/lib/connection/pool.js#L1026-L1030. // If there's queued operations, you may still get some background work // after the callback is called. setTimeout(() => fn(err, res), 1); }); return this; }; /*! * Module exports. */ module.exports = NativeConnection; |