arnaucube
arnaucube/thoughtsPublic Self-hosted repository
thoughts/node_modules/mongoose/lib/drivers/node-mongodb-native/connection.js
node_modules/mongoose/lib/drivers/node-mongodb-native/connection.jsRaw
  1/*!
  2 * Module dependencies.
  3 */
  4
  5var MongooseConnection = require('../../connection')
  6  , mongo = require('mongodb')
  7  , Db = mongo.Db
  8  , Server = mongo.Server
  9  , Mongos = mongo.Mongos
 10  , STATES = require('../../connectionstate')
 11  , ReplSetServers = mongo.ReplSetServers;
 12
 13/**
 14 * A [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) connection implementation.
 15 *
 16 * @inherits Connection
 17 * @api private
 18 */
 19
 20function NativeConnection() {
 21  MongooseConnection.apply(this, arguments);
 22  this._listening = false;
 23};
 24
 25/**
 26 * Expose the possible connection states.
 27 * @api public
 28 */
 29
 30NativeConnection.STATES = STATES;
 31
 32/*!
 33 * Inherits from Connection.
 34 */
 35
 36NativeConnection.prototype.__proto__ = MongooseConnection.prototype;
 37
 38/**
 39 * Opens the connection to MongoDB.
 40 *
 41 * @param {Function} fn
 42 * @return {Connection} this
 43 * @api private
 44 */
 45
 46NativeConnection.prototype.doOpen = function (fn) {
 47  if (this.db) {
 48    mute(this);
 49  }
 50
 51  var server = new Server(this.host, this.port, this.options.server);
 52  this.db = new Db(this.name, server, this.options.db);
 53
 54  var self = this;
 55  this.db.open(function (err) {
 56    if (err) return fn(err);
 57    listen(self);
 58    fn();
 59  });
 60
 61  return this;
 62};
 63
 64/*!
 65 * Register listeners for important events and bubble appropriately.
 66 */
 67
 68function listen (conn) {
 69  if (conn._listening) return;
 70  conn._listening = true;
 71
 72  conn.db.on('close', function(){
 73    if (conn._closeCalled) return;
 74
 75    // the driver never emits an `open` event. auto_reconnect still
 76    // emits a `close` event but since we never get another
 77    // `open` we can't emit close
 78    if (conn.db.serverConfig.autoReconnect) {
 79      conn.readyState = STATES.disconnected;
 80      conn.emit('close');
 81      return;
 82    }
 83    conn.onClose();
 84  });
 85  conn.db.on('error', function(err){
 86    conn.emit('error', err);
 87  });
 88  conn.db.on('timeout', function(err){
 89    var error = new Error(err && err.err || 'connection timeout');
 90    conn.emit('error', error);
 91  });
 92  conn.db.on('open', function (err, db) {
 93    if (STATES.disconnected === conn.readyState && db && db.databaseName) {
 94      conn.readyState = STATES.connected;
 95      conn.emit('reconnected')
 96    }
 97  })
 98}
 99
100/*!
101 * Remove listeners registered in `listen`
102 */
103
104function mute (conn) {
105  if (!conn.db) throw new Error('missing db');
106  conn.db.removeAllListeners("close");
107  conn.db.removeAllListeners("error");
108  conn.db.removeAllListeners("timeout");
109  conn.db.removeAllListeners("open");
110  conn.db.removeAllListeners("fullsetup");
111  conn._listening = false;
112}
113
114/**
115 * Opens a connection to a MongoDB ReplicaSet.
116 *
117 * See description of [doOpen](#NativeConnection-doOpen) for server options. In this case `options.replset` is also passed to ReplSetServers.
118 *
119 * @param {Function} fn
120 * @api private
121 * @return {Connection} this
122 */
123
124NativeConnection.prototype.doOpenSet = function (fn) {
125  if (this.db) {
126    mute(this);
127  }
128
129  var servers = []
130    , self = this;
131
132  this.hosts.forEach(function (server) {
133    var host = server.host || server.ipc;
134    var port = server.port || 27017;
135    servers.push(new Server(host, port, self.options.server));
136  })
137
138  var server = this.options.mongos
139    ? new Mongos(servers, this.options.mongos)
140    : new ReplSetServers(servers, this.options.replset);
141  this.db = new Db(this.name, server, this.options.db);
142
143  this.db.on('fullsetup', function () {
144    self.emit('fullsetup')
145  });
146
147  this.db.open(function (err) {
148    if (err) return fn(err);
149    fn();
150    listen(self);
151  });
152
153  return this;
154};
155
156/**
157 * Closes the connection
158 *
159 * @param {Function} fn
160 * @return {Connection} this
161 * @api private
162 */
163
164NativeConnection.prototype.doClose = function (fn) {
165  this.db.close();
166  if (fn) fn();
167  return this;
168}
169
170/**
171 * Prepares default connection options for the node-mongodb-native driver.
172 *
173 * _NOTE: `passed` options take precedence over connection string options._
174 *
175 * @param {Object} passed options that were passed directly during connection
176 * @param {Object} [connStrOptions] options that were passed in the connection string
177 * @api private
178 */
179
180NativeConnection.prototype.parseOptions = function (passed, connStrOpts) {
181  var o = passed || {};
182  o.db || (o.db = {});
183  o.auth || (o.auth = {});
184  o.server || (o.server = {});
185  o.replset || (o.replset = {});
186  o.server.socketOptions || (o.server.socketOptions = {});
187  o.replset.socketOptions || (o.replset.socketOptions = {});
188
189  var opts = connStrOpts || {};
190  Object.keys(opts).forEach(function (name) {
191    switch (name) {
192      case 'poolSize':
193        if ('undefined' == typeof o.server.poolSize) {
194          o.server.poolSize = o.replset.poolSize = opts[name];
195        }
196        break;
197      case 'slaveOk':
198        if ('undefined' == typeof o.server.slave_ok) {
199          o.server.slave_ok = opts[name];
200        }
201        break;
202      case 'autoReconnect':
203        if ('undefined' == typeof o.server.auto_reconnect) {
204          o.server.auto_reconnect = opts[name];
205        }
206        break;
207      case 'ssl':
208      case 'socketTimeoutMS':
209      case 'connectTimeoutMS':
210        if ('undefined' == typeof o.server.socketOptions[name]) {
211          o.server.socketOptions[name] = o.replset.socketOptions[name] = opts[name];
212        }
213        break;
214      case 'authdb':
215        if ('undefined' == typeof o.auth.authdb) {
216          o.auth.authdb = opts[name];
217        }
218        break;
219      case 'authSource':
220        if ('undefined' == typeof o.auth.authSource) {
221          o.auth.authSource = opts[name];
222        }
223        break;
224      case 'retries':
225      case 'reconnectWait':
226      case 'rs_name':
227        if ('undefined' == typeof o.replset[name]) {
228          o.replset[name] = opts[name];
229        }
230        break;
231      case 'replicaSet':
232        if ('undefined' == typeof o.replset.rs_name) {
233          o.replset.rs_name = opts[name];
234        }
235        break;
236      case 'readSecondary':
237        if ('undefined' == typeof o.replset.read_secondary) {
238          o.replset.read_secondary = opts[name];
239        }
240        break;
241      case 'nativeParser':
242        if ('undefined' == typeof o.db.native_parser) {
243          o.db.native_parser = opts[name];
244        }
245        break;
246      case 'w':
247      case 'safe':
248      case 'fsync':
249      case 'journal':
250      case 'wtimeoutMS':
251        if ('undefined' == typeof o.db[name]) {
252          o.db[name] = opts[name];
253        }
254        break;
255      case 'readPreference':
256        if ('undefined' == typeof o.db.read_preference) {
257          o.db.read_preference = opts[name];
258        }
259        break;
260      case 'readPreferenceTags':
261        if ('undefined' == typeof o.db.read_preference_tags) {
262          o.db.read_preference_tags = opts[name];
263        }
264        break;
265    }
266  })
267
268  if (!('auto_reconnect' in o.server)) {
269    o.server.auto_reconnect = true;
270  }
271
272  if (!o.db.read_preference) {
273    // read from primaries by default
274    o.db.read_preference = 'primary';
275  }
276
277  // mongoose creates its own ObjectIds
278  o.db.forceServerObjectId = false;
279
280  // default safe using new nomenclature
281  if (!('journal' in o.db || 'j' in o.db ||
282        'fsync' in o.db || 'safe' in o.db || 'w' in o.db)) {
283    o.db.w = 1;
284  }
285
286  validate(o);
287  return o;
288}
289
290/*!
291 * Validates the driver db options.
292 *
293 * @param {Object} o
294 */
295
296function validate (o) {
297  if (-1 === o.db.w || 0 === o.db.w) {
298    if (o.db.journal || o.db.fsync || o.db.safe) {
299      throw new Error(
300          'Invalid writeConcern: '
301        + 'w set to -1 or 0 cannot be combined with safe|fsync|journal');
302    }
303  }
304}
305
306/*!
307 * Module exports.
308 */
309
310module.exports = NativeConnection;