mongodb 2.1.0-alpha → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/HISTORY.md +574 -429
  2. package/Makefile +2 -5
  3. package/README.md +108 -15
  4. package/conf.json +17 -13
  5. package/index.js +13 -2
  6. package/lib/admin.js +113 -47
  7. package/lib/aggregation_cursor.js +56 -28
  8. package/lib/apm.js +608 -0
  9. package/lib/bulk/common.js +7 -7
  10. package/lib/bulk/ordered.js +56 -17
  11. package/lib/bulk/unordered.js +52 -14
  12. package/lib/collection.js +671 -212
  13. package/lib/command_cursor.js +60 -32
  14. package/lib/cursor.js +313 -115
  15. package/lib/db.js +264 -105
  16. package/lib/gridfs/chunk.js +26 -29
  17. package/lib/gridfs/grid_store.js +150 -64
  18. package/lib/gridfs-stream/download.js +310 -0
  19. package/lib/gridfs-stream/index.js +335 -0
  20. package/lib/gridfs-stream/upload.js +450 -0
  21. package/lib/metadata.js +64 -0
  22. package/lib/mongo_client.js +69 -39
  23. package/lib/mongos.js +65 -20
  24. package/lib/replset.js +69 -34
  25. package/lib/server.js +35 -1
  26. package/lib/topology_base.js +22 -10
  27. package/lib/url_parser.js +111 -13
  28. package/lib/utils.js +9 -8
  29. package/mongolabs.js +427 -0
  30. package/package.json +8 -6
  31. package/t.js +68 -51
  32. package/test.js +12 -0
  33. package/test_boot/boot.sh +3 -0
  34. package/test_boot/ca.pem +49 -0
  35. package/test_boot/client.pem +48 -0
  36. package/test_boot/client_password.pem +51 -0
  37. package/test_boot/connect.js +29 -0
  38. package/test_boot/data/WiredTiger +2 -0
  39. package/test_boot/data/WiredTiger.lock +1 -0
  40. package/test_boot/data/WiredTiger.turtle +6 -0
  41. package/test_boot/data/WiredTiger.wt +0 -0
  42. package/test_boot/data/WiredTigerLAS.wt +0 -0
  43. package/test_boot/data/_mdb_catalog.wt +0 -0
  44. package/test_boot/data/collection-0-757073248613337118.wt +0 -0
  45. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-44-37Z-00000 +0 -0
  46. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-45-15Z-00000 +0 -0
  47. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-46-31Z-00000 +0 -0
  48. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-47-25Z-00000 +0 -0
  49. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-49-07Z-00000 +0 -0
  50. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-50-41Z-00000 +0 -0
  51. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-50-53Z-00000 +0 -0
  52. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-52-31Z-00000 +0 -0
  53. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-54-53Z-00000 +0 -0
  54. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-55-09Z-00000 +0 -0
  55. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-55-38Z-00000 +0 -0
  56. package/test_boot/data/index-1-757073248613337118.wt +0 -0
  57. package/test_boot/data/mongod.lock +0 -0
  58. package/test_boot/data/sizeStorer.wt +0 -0
  59. package/test_boot/data/storage.bson +0 -0
  60. package/test_boot/server_password.pem +51 -0
  61. package/.travis.yml +0 -10
  62. package/t1.js +0 -59
  63. package/wercker.yml +0 -19
package/lib/db.js CHANGED
@@ -16,6 +16,7 @@ var EventEmitter = require('events').EventEmitter
16
16
  , CoreReadPreference = require('mongodb-core').ReadPreference
17
17
  , MongoError = require('mongodb-core').MongoError
18
18
  , ObjectID = require('mongodb-core').ObjectID
19
+ , Define = require('./metadata')
19
20
  , Logger = require('mongodb-core').Logger
20
21
  , Collection = require('./collection')
21
22
  , crypto = require('crypto');
@@ -53,14 +54,15 @@ var debugFields = ['authSource', 'w', 'wtimeout', 'j', 'native_parser', 'forceSe
53
54
  * @param {boolean} [options.native_parser=true] Select C++ bson parser instead of JavaScript parser.
54
55
  * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
55
56
  * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
57
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
56
58
  * @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
57
59
  * @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
58
60
  * @param {number} [options.bufferMaxEntries=-1] Sets a cap on how many operations the driver will buffer up before giving up on getting a working connection, default is -1 which is unlimited.
59
- * @param {number} [options.numberOfRetries=5] Number of retries off connection.
60
- * @param {number} [options.retryMiliSeconds=500] Number of milliseconds between retries.
61
61
  * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
62
62
  * @param {object} [options.pkFactory=null] A primary key factory object for generation of custom _id keys.
63
63
  * @param {object} [options.promiseLibrary=null] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
64
+ * @param {object} [options.readConcern=null] Specify a read concern for the collection. (only MongoDB 3.2 or higher supported)
65
+ * @param {object} [options.readConcern.level='local'] Specify a read concern level for the collection operations, one of [local|majority]. (only MongoDB 3.2 or higher supported)
64
66
  * @property {(Server|ReplSet|Mongos)} serverConfig Get the current db topology.
65
67
  * @property {number} bufferMaxEntries Current bufferMaxEntries value for the database
66
68
  * @property {string} databaseName The name of the database this instance represents.
@@ -99,6 +101,8 @@ var Db = function(databaseName, topology, options) {
99
101
  this.s = {
100
102
  // Database name
101
103
  databaseName: databaseName
104
+ // DbCache
105
+ , dbCache: {}
102
106
  // Children db's
103
107
  , children: []
104
108
  // Topology
@@ -123,6 +127,10 @@ var Db = function(databaseName, topology, options) {
123
127
  , nativeParser: options.nativeParser || options.native_parser
124
128
  // Promise library
125
129
  , promiseLibrary: promiseLibrary
130
+ // No listener
131
+ , noListener: typeof options.noListener == 'boolean' ? options.noListener : false
132
+ // ReadConcern
133
+ , readConcern: options.readConcern
126
134
  }
127
135
 
128
136
  // Ensure we have a valid db name
@@ -180,12 +188,13 @@ var Db = function(databaseName, topology, options) {
180
188
 
181
189
  // This is a child db, do not register any listeners
182
190
  if(options.parentDb) return;
191
+ if(this.s.noListener) return;
183
192
 
184
193
  // Add listeners
185
- topology.once('error', createListener(self, 'error', self));
186
- topology.once('timeout', createListener(self, 'timeout', self));
194
+ topology.on('error', createListener(self, 'error', self));
195
+ topology.on('timeout', createListener(self, 'timeout', self));
187
196
  topology.on('close', createListener(self, 'close', self));
188
- topology.once('parseError', createListener(self, 'parseError', self));
197
+ topology.on('parseError', createListener(self, 'parseError', self));
189
198
  topology.once('open', createListener(self, 'open', self));
190
199
  topology.once('fullsetup', createListener(self, 'fullsetup', self));
191
200
  topology.once('all', createListener(self, 'all', self));
@@ -194,6 +203,8 @@ var Db = function(databaseName, topology, options) {
194
203
 
195
204
  inherits(Db, EventEmitter);
196
205
 
206
+ var define = Db.define = new Define('Db', Db, false);
207
+
197
208
  /**
198
209
  * The callback format for the Db.open method
199
210
  * @callback Db~openCallback
@@ -214,13 +225,13 @@ var open = function(self, callback) {
214
225
  }
215
226
 
216
227
  internalCallback(null, self);
217
- });
228
+ });
218
229
  }
219
230
 
220
231
  /**
221
232
  * Open the database
222
233
  * @method
223
- * @param {Db~openCallback} callback Callback
234
+ * @param {Db~openCallback} [callback] Callback
224
235
  * @return {Promise} returns Promise if no callback passed
225
236
  */
226
237
  Db.prototype.open = function(callback) {
@@ -236,6 +247,8 @@ Db.prototype.open = function(callback) {
236
247
  });
237
248
  }
238
249
 
250
+ define.classMethod('open', {callback: true, promise:true});
251
+
239
252
  /**
240
253
  * The callback format for results
241
254
  * @callback Db~resultCallback
@@ -244,6 +257,9 @@ Db.prototype.open = function(callback) {
244
257
  */
245
258
 
246
259
  var executeCommand = function(self, command, options, callback) {
260
+ // Did the user destroy the topology
261
+ if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
262
+ // Get the db name we are executing against
247
263
  var dbName = options.dbName || options.authdb || self.s.databaseName;
248
264
  // If we have a readPreference set
249
265
  if(options.readPreference == null && self.s.readPreference) {
@@ -265,6 +281,7 @@ var executeCommand = function(self, command, options, callback) {
265
281
  // Execute command
266
282
  self.s.topology.command(f('%s.$cmd', dbName), command, options, function(err, result) {
267
283
  if(err) return handleCallback(callback, err);
284
+ if(options.full) return handleCallback(callback, null, result);
268
285
  handleCallback(callback, null, result.result);
269
286
  });
270
287
  }
@@ -275,8 +292,7 @@ var executeCommand = function(self, command, options, callback) {
275
292
  * @param {object} command The command hash
276
293
  * @param {object} [options=null] Optional settings.
277
294
  * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
278
- * @param {number} [options.maxTimeMS=null] Number of milliseconds to wait before aborting the query.
279
- * @param {Db~resultCallback} callback The command result callback
295
+ * @param {Db~resultCallback} [callback] The command result callback
280
296
  * @return {Promise} returns Promise if no callback passed
281
297
  */
282
298
  Db.prototype.command = function(command, options, callback) {
@@ -285,7 +301,7 @@ Db.prototype.command = function(command, options, callback) {
285
301
  if(typeof options == 'function') callback = options, options = {};
286
302
  // Clone the options
287
303
  options = shallowClone(options);
288
-
304
+
289
305
  // Do we have a callback
290
306
  if(typeof callback == 'function') return executeCommand(self, command, options, callback);
291
307
  // Return a promise
@@ -297,6 +313,8 @@ Db.prototype.command = function(command, options, callback) {
297
313
  });
298
314
  }
299
315
 
316
+ define.classMethod('command', {callback: true, promise:true});
317
+
300
318
  /**
301
319
  * The callback format for results
302
320
  * @callback Db~noResultCallback
@@ -308,7 +326,7 @@ Db.prototype.command = function(command, options, callback) {
308
326
  * Close the db and it's underlying connections
309
327
  * @method
310
328
  * @param {boolean} force Force close, emitting no events
311
- * @param {Db~noResultCallback} callback The result callback
329
+ * @param {Db~noResultCallback} [callback] The result callback
312
330
  * @return {Promise} returns Promise if no callback passed
313
331
  */
314
332
  Db.prototype.close = function(force, callback) {
@@ -325,13 +343,13 @@ Db.prototype.close = function(force, callback) {
325
343
  // Fire close on all children
326
344
  for(var i = 0; i < this.s.children.length; i++) {
327
345
  this.s.children[i].emit('close');
328
- }
346
+ }
329
347
  }
330
348
 
331
349
  // Remove listeners after emit
332
- self.removeAllListeners('close');
350
+ self.removeAllListeners('close');
333
351
  }
334
-
352
+
335
353
  // Close parent db if set
336
354
  if(this.s.parentDb) this.s.parentDb.close();
337
355
  // Callback after next event loop tick
@@ -345,6 +363,8 @@ Db.prototype.close = function(force, callback) {
345
363
  });
346
364
  }
347
365
 
366
+ define.classMethod('close', {callback: true, promise:true});
367
+
348
368
  /**
349
369
  * Return the Admin db instance
350
370
  * @method
@@ -354,6 +374,8 @@ Db.prototype.admin = function() {
354
374
  return new Admin(this, this.s.topology, this.s.promiseLibrary);
355
375
  };
356
376
 
377
+ define.classMethod('admin', {callback: false, promise:false, returns: [Admin]});
378
+
357
379
  /**
358
380
  * The callback format for the collection method, must be used if strict is specified
359
381
  * @callback Db~collectionResultCallback
@@ -376,6 +398,8 @@ Db.prototype.admin = function() {
376
398
  * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
377
399
  * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
378
400
  * @param {boolean} [options.strict=false] Returns an error if the collection does not exist
401
+ * @param {object} [options.readConcern=null] Specify a read concern for the collection. (only MongoDB 3.2 or higher supported)
402
+ * @param {object} [options.readConcern.level='local'] Specify a read concern level for the collection operations, one of [local|majority]. (only MongoDB 3.2 or higher supported)
379
403
  * @param {Db~collectionResultCallback} callback The collection result callback
380
404
  * @return {Collection} return the new Collection instance if not in strict mode
381
405
  */
@@ -387,6 +411,14 @@ Db.prototype.collection = function(name, options, callback) {
387
411
  // Set the promise library
388
412
  options.promiseLibrary = this.s.promiseLibrary;
389
413
 
414
+ // If we have not set a collection level readConcern set the db level one
415
+ options.readConcern = options.readConcern || this.s.readConcern;
416
+
417
+ // Do we have ignoreUndefined set
418
+ if(this.s.options.ignoreUndefined) {
419
+ options.ignoreUndefined = this.s.options.ignoreUndefined;
420
+ }
421
+
390
422
  // Execute
391
423
  if(options == null || !options.strict) {
392
424
  try {
@@ -417,15 +449,19 @@ Db.prototype.collection = function(name, options, callback) {
417
449
  });
418
450
  }
419
451
 
452
+ define.classMethod('collection', {callback: true, promise:false, returns: [Collection]});
453
+
420
454
  var createCollection = function(self, name, options, callback) {
421
455
  // Get the write concern options
422
456
  var finalOptions = writeConcern(shallowClone(options), self, options);
457
+ // Did the user destroy the topology
458
+ if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
423
459
 
424
460
  // Check if we have the name
425
461
  self.listCollections({name: name}).toArray(function(err, collections) {
426
462
  if(err != null) return handleCallback(callback, err, null);
427
463
  if(collections.length > 0 && finalOptions.strict) {
428
- return handleCallback(callback, new MongoError(f("Collection %s already exists. Currently in strict mode.", name)), null);
464
+ return handleCallback(callback, MongoError.create({message: f("Collection %s already exists. Currently in strict mode.", name), driver:true}), null);
429
465
  } else if (collections.length > 0) {
430
466
  try { return handleCallback(callback, null, new Collection(self, self.s.topology, self.s.databaseName, name, self.s.pkFactory, options)); }
431
467
  catch(err) { return handleCallback(callback, err); }
@@ -445,7 +481,7 @@ var createCollection = function(self, name, options, callback) {
445
481
  if(err) return handleCallback(callback, err);
446
482
  handleCallback(callback, null, new Collection(self, self.s.topology, self.s.databaseName, name, self.s.pkFactory, options));
447
483
  });
448
- });
484
+ });
449
485
  }
450
486
 
451
487
  /**
@@ -466,7 +502,7 @@ var createCollection = function(self, name, options, callback) {
466
502
  * @param {number} [options.size=null] The size of the capped collection in bytes.
467
503
  * @param {number} [options.max=null] The maximum number of documents in the capped collection.
468
504
  * @param {boolean} [options.autoIndexId=true] Create an index on the _id field of the document, True by default on MongoDB 2.2 or higher off for version < 2.2.
469
- * @param {Db~collectionResultCallback} callback The results callback
505
+ * @param {Db~collectionResultCallback} [callback] The results callback
470
506
  * @return {Promise} returns Promise if no callback passed
471
507
  */
472
508
  Db.prototype.createCollection = function(name, options, callback) {
@@ -477,6 +513,9 @@ Db.prototype.createCollection = function(name, options, callback) {
477
513
  name = args.length ? args.shift() : null;
478
514
  options = args.length ? args.shift() || {} : {};
479
515
 
516
+ // Do we have a promisesLibrary
517
+ options.promiseLibrary = options.promiseLibrary || this.s.promiseLibrary;
518
+
480
519
  // Check if the callback is in fact a string
481
520
  if(typeof callback == 'string') name = callback;
482
521
 
@@ -490,13 +529,15 @@ Db.prototype.createCollection = function(name, options, callback) {
490
529
  });
491
530
  }
492
531
 
532
+ define.classMethod('createCollection', {callback: true, promise:true});
533
+
493
534
  /**
494
535
  * Get all the db statistics.
495
536
  *
496
537
  * @method
497
538
  * @param {object} [options=null] Optional settings.
498
539
  * @param {number} [options.scale=null] Divide the returned sizes by scale value.
499
- * @param {Db~resultCallback} callback The collection result callback
540
+ * @param {Db~resultCallback} [callback] The collection result callback
500
541
  * @return {Promise} returns Promise if no callback passed
501
542
  */
502
543
  Db.prototype.stats = function(options, callback) {
@@ -510,6 +551,8 @@ Db.prototype.stats = function(options, callback) {
510
551
  return this.command(commandObject, options, callback);
511
552
  }
512
553
 
554
+ define.classMethod('stats', {callback: true, promise:true});
555
+
513
556
  // Transformation methods for cursor results
514
557
  var listCollectionsTranforms = function(databaseName) {
515
558
  var matching = f('%s.', databaseName);
@@ -534,6 +577,7 @@ var listCollectionsTranforms = function(databaseName) {
534
577
  * @param {object} filter Query to filter collections by
535
578
  * @param {object} [options=null] Optional settings.
536
579
  * @param {number} [options.batchSize=null] The batchSize for the returned command cursor or if pre 2.8 the systems batch collection
580
+ * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
537
581
  * @return {CommandCursor}
538
582
  */
539
583
  Db.prototype.listCollections = function(filter, options) {
@@ -544,7 +588,6 @@ Db.prototype.listCollections = function(filter, options) {
544
588
  options = shallowClone(options);
545
589
  // Set the promise library
546
590
  options.promiseLibrary = this.s.promiseLibrary;
547
-
548
591
  // We have a list collections command
549
592
  if(this.serverConfig.capabilities().hasListCollectionsCommand) {
550
593
  // Cursor options
@@ -555,8 +598,12 @@ Db.prototype.listCollections = function(filter, options) {
555
598
  options.cursorFactory = CommandCursor;
556
599
  // Filter out the correct field values
557
600
  options.transforms = listCollectionsTranforms(this.s.databaseName);
558
- // Execute the cursor
559
- return this.s.topology.cursor(f('%s.$cmd', this.s.databaseName), command, options);
601
+ // Create the cursor
602
+ var cursor = this.s.topology.cursor(f('%s.$cmd', this.s.databaseName), command, options);
603
+ // Do we have a readPreference, apply it
604
+ if(options.readPeference) cursor.setReadPreference(options.readPeference);
605
+ // Return the cursor
606
+ return cursor;
560
607
  }
561
608
 
562
609
  // We cannot use the listCollectionsCommand
@@ -581,19 +628,26 @@ Db.prototype.listCollections = function(filter, options) {
581
628
  }
582
629
 
583
630
  // Return options
584
- var options = {transforms: listCollectionsTranforms(this.s.databaseName)}
631
+ var _options = {transforms: listCollectionsTranforms(this.s.databaseName)}
585
632
  // Get the cursor
586
- var cursor = this.collection(Db.SYSTEM_NAMESPACE_COLLECTION).find(filter, options);
633
+ var cursor = this.collection(Db.SYSTEM_NAMESPACE_COLLECTION).find(filter, _options);
634
+ // Do we have a readPreference, apply it
635
+ if(options.readPeference) cursor.setReadPreference(options.readPeference);
587
636
  // Set the passed in batch size if one was provided
588
637
  if(options.batchSize) cursor = cursor.batchSize(options.batchSize);
589
638
  // We have a fallback mode using legacy systems collections
590
639
  return cursor;
591
640
  };
592
641
 
642
+ define.classMethod('listCollections', {callback: false, promise:false, returns: [CommandCursor]});
643
+
593
644
  var evaluate = function(self, code, parameters, options, callback) {
594
645
  var finalCode = code;
595
646
  var finalParameters = [];
596
647
 
648
+ // Did the user destroy the topology
649
+ if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
650
+
597
651
  // If not a code object translate to one
598
652
  if(!(finalCode instanceof Code)) finalCode = new Code(finalCode);
599
653
  // Ensure the parameters are correct
@@ -617,9 +671,9 @@ var evaluate = function(self, code, parameters, options, callback) {
617
671
  self.command(cmd, options, function(err, result) {
618
672
  if(err) return handleCallback(callback, err, null);
619
673
  if(result && result.ok == 1) return handleCallback(callback, null, result.retval);
620
- if(result) return handleCallback(callback, new MongoError(f("eval failed: %s", result.errmsg)), null);
674
+ if(result) return handleCallback(callback, MongoError.create({message: f("eval failed: %s", result.errmsg), driver:true}), null);
621
675
  handleCallback(callback, err, result);
622
- });
676
+ });
623
677
  }
624
678
 
625
679
  /**
@@ -630,7 +684,8 @@ var evaluate = function(self, code, parameters, options, callback) {
630
684
  * @param {(object|array)} parameters The parameters for the call.
631
685
  * @param {object} [options=null] Optional settings.
632
686
  * @param {boolean} [options.nolock=false] Tell MongoDB not to block on the evaulation of the javascript.
633
- * @param {Db~resultCallback} callback The results callback
687
+ * @param {Db~resultCallback} [callback] The results callback
688
+ * @deprecated Eval is deprecated on MongoDB 3.2 and forward
634
689
  * @return {Promise} returns Promise if no callback passed
635
690
  */
636
691
  Db.prototype.eval = function(code, parameters, options, callback) {
@@ -652,6 +707,8 @@ Db.prototype.eval = function(code, parameters, options, callback) {
652
707
  });
653
708
  };
654
709
 
710
+ define.classMethod('eval', {callback: true, promise:true});
711
+
655
712
  /**
656
713
  * Rename a collection.
657
714
  *
@@ -660,7 +717,7 @@ Db.prototype.eval = function(code, parameters, options, callback) {
660
717
  * @param {string} toCollection New name of of the collection.
661
718
  * @param {object} [options=null] Optional settings.
662
719
  * @param {boolean} [options.dropTarget=false] Drop the target name collection if it previously exists.
663
- * @param {Db~collectionResultCallback} callback The results callback
720
+ * @param {Db~collectionResultCallback} [callback] The results callback
664
721
  * @return {Promise} returns Promise if no callback passed
665
722
  */
666
723
  Db.prototype.renameCollection = function(fromCollection, toCollection, options, callback) {
@@ -673,7 +730,7 @@ Db.prototype.renameCollection = function(fromCollection, toCollection, options,
673
730
  // Check if the callback is in fact a string
674
731
  if(typeof callback == 'function') {
675
732
  return this.collection(fromCollection).rename(toCollection, options, callback);
676
- }
733
+ }
677
734
 
678
735
  // Return a promise
679
736
  return new this.s.promiseLibrary(function(resolve, reject) {
@@ -684,12 +741,14 @@ Db.prototype.renameCollection = function(fromCollection, toCollection, options,
684
741
  });
685
742
  };
686
743
 
744
+ define.classMethod('renameCollection', {callback: true, promise:true});
745
+
687
746
  /**
688
747
  * Drop a collection from the database, removing it permanently. New accesses will create a new collection.
689
748
  *
690
749
  * @method
691
750
  * @param {string} name Name of collection to drop
692
- * @param {Db~resultCallback} callback The results callback
751
+ * @param {Db~resultCallback} [callback] The results callback
693
752
  * @return {Promise} returns Promise if no callback passed
694
753
  */
695
754
  Db.prototype.dropCollection = function(name, callback) {
@@ -700,6 +759,8 @@ Db.prototype.dropCollection = function(name, callback) {
700
759
 
701
760
  // Check if the callback is in fact a string
702
761
  if(typeof callback == 'function') return this.command(cmd, this.s.options, function(err, result) {
762
+ // Did the user destroy the topology
763
+ if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
703
764
  if(err) return handleCallback(callback, err);
704
765
  if(result.ok) return handleCallback(callback, null, true);
705
766
  handleCallback(callback, null, false);
@@ -709,13 +770,17 @@ Db.prototype.dropCollection = function(name, callback) {
709
770
  return new this.s.promiseLibrary(function(resolve, reject) {
710
771
  // Execute command
711
772
  self.command(cmd, self.s.options, function(err, result) {
712
- if(err) return reject(err);
773
+ // Did the user destroy the topology
774
+ if(self.serverConfig && self.serverConfig.isDestroyed()) return reject(new MongoError('topology was destroyed'));
775
+ if(err) return reject(err);
713
776
  if(result.ok) return resolve(true);
714
777
  resolve(false);
715
778
  });
716
779
  });
717
780
  };
718
781
 
782
+ define.classMethod('dropCollection', {callback: true, promise:true});
783
+
719
784
  /**
720
785
  * Drop a database.
721
786
  *
@@ -725,12 +790,13 @@ Db.prototype.dropCollection = function(name, callback) {
725
790
  */
726
791
  Db.prototype.dropDatabase = function(callback) {
727
792
  var self = this;
728
- if(typeof options == 'function') callback = options, options = {};
729
793
  // Drop database command
730
794
  var cmd = {'dropDatabase':1};
731
795
 
732
796
  // Check if the callback is in fact a string
733
797
  if(typeof callback == 'function') return this.command(cmd, this.s.options, function(err, result) {
798
+ // Did the user destroy the topology
799
+ if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
734
800
  if(callback == null) return;
735
801
  if(err) return handleCallback(callback, err, null);
736
802
  handleCallback(callback, null, result.ok ? true : false);
@@ -740,20 +806,23 @@ Db.prototype.dropDatabase = function(callback) {
740
806
  return new this.s.promiseLibrary(function(resolve, reject) {
741
807
  // Execute command
742
808
  self.command(cmd, self.s.options, function(err, result) {
743
- if(err) return reject(err);
809
+ // Did the user destroy the topology
810
+ if(self.serverConfig && self.serverConfig.isDestroyed()) return reject(new MongoError('topology was destroyed'));
811
+ if(err) return reject(err);
744
812
  if(result.ok) return resolve(true);
745
813
  resolve(false);
746
814
  });
747
815
  });
748
816
  }
749
817
 
818
+ define.classMethod('dropDatabase', {callback: true, promise:true});
819
+
750
820
  /**
751
821
  * The callback format for the collections method.
752
822
  * @callback Db~collectionsResultCallback
753
823
  * @param {MongoError} error An error instance representing the error during the execution.
754
824
  * @param {Collection[]} collections An array of all the collections objects for the db instance.
755
825
  */
756
-
757
826
  var collections = function(self, callback) {
758
827
  // Let's get the collection names
759
828
  self.listCollections().toArray(function(err, documents) {
@@ -767,7 +836,7 @@ var collections = function(self, callback) {
767
836
  handleCallback(callback, null, documents.map(function(d) {
768
837
  return new Collection(self, self.s.topology, self.s.databaseName, d.name.replace(self.s.databaseName + ".", ''), self.s.pkFactory, self.s.options);
769
838
  }));
770
- });
839
+ });
771
840
  }
772
841
 
773
842
  /**
@@ -791,6 +860,8 @@ Db.prototype.collections = function(callback) {
791
860
  });
792
861
  };
793
862
 
863
+ define.classMethod('collections', {callback: true, promise:true});
864
+
794
865
  /**
795
866
  * Runs a command on the database as admin.
796
867
  * @method
@@ -798,7 +869,7 @@ Db.prototype.collections = function(callback) {
798
869
  * @param {object} [options=null] Optional settings.
799
870
  * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
800
871
  * @param {number} [options.maxTimeMS=null] Number of milliseconds to wait before aborting the query.
801
- * @param {Db~resultCallback} callback The command result callback
872
+ * @param {Db~resultCallback} [callback] The command result callback
802
873
  * @return {Promise} returns Promise if no callback passed
803
874
  */
804
875
  Db.prototype.executeDbAdminCommand = function(selector, options, callback) {
@@ -812,6 +883,8 @@ Db.prototype.executeDbAdminCommand = function(selector, options, callback) {
812
883
 
813
884
  // Return the callback
814
885
  if(typeof callback == 'function') return self.s.topology.command('admin.$cmd', selector, options, function(err, result) {
886
+ // Did the user destroy the topology
887
+ if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
815
888
  if(err) return handleCallback(callback, err);
816
889
  handleCallback(callback, null, result.result);
817
890
  });
@@ -819,37 +892,15 @@ Db.prototype.executeDbAdminCommand = function(selector, options, callback) {
819
892
  // Return promise
820
893
  return new self.s.promiseLibrary(function(resolve, reject) {
821
894
  self.s.topology.command('admin.$cmd', selector, options, function(err, result) {
895
+ // Did the user destroy the topology
896
+ if(self.serverConfig && self.serverConfig.isDestroyed()) return reject(new MongoError('topology was destroyed'));
822
897
  if(err) return reject(err);
823
898
  resolve(result.result);
824
899
  });
825
900
  });
826
901
  };
827
902
 
828
- var createIndex = function(self, name, fieldOrSpec, options, callback) {
829
- // Get the write concern options
830
- var finalOptions = writeConcern({}, self, options);
831
- // Ensure we have a callback
832
- if(finalOptions.writeConcern && typeof callback != 'function') {
833
- throw new MongoError("Cannot use a writeConcern without a provided callback");
834
- }
835
-
836
- // Attempt to run using createIndexes command
837
- createIndexUsingCreateIndexes(self, name, fieldOrSpec, options, function(err, result) {
838
- if(err == null) return handleCallback(callback, err, result);
839
- // Create command
840
- var doc = createCreateIndexCommand(self, name, fieldOrSpec, options);
841
- // Set no key checking
842
- finalOptions.checkKeys = false;
843
- // Insert document
844
- self.s.topology.insert(f("%s.%s", self.s.databaseName, Db.SYSTEM_INDEX_COLLECTION), doc, finalOptions, function(err, result) {
845
- if(callback == null) return;
846
- if(err) return handleCallback(callback, err);
847
- if(result == null) return handleCallback(callback, null, null);
848
- if(result.result.writeErrors) return handleCallback(callback, MongoError.create(result.result.writeErrors[0]), null);
849
- handleCallback(callback, null, doc.name);
850
- });
851
- });
852
- }
903
+ define.classMethod('executeDbAdminCommand', {callback: true, promise:true});
853
904
 
854
905
  /**
855
906
  * Creates an index on the db and collection collection.
@@ -869,7 +920,7 @@ var createIndex = function(self, name, fieldOrSpec, options, callback) {
869
920
  * @param {number} [options.v=null] Specify the format version of the indexes.
870
921
  * @param {number} [options.expireAfterSeconds=null] Allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
871
922
  * @param {number} [options.name=null] Override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
872
- * @param {Db~resultCallback} callback The command result callback
923
+ * @param {Db~resultCallback} [callback] The command result callback
873
924
  * @return {Promise} returns Promise if no callback passed
874
925
  */
875
926
  Db.prototype.createIndex = function(name, fieldOrSpec, options, callback) {
@@ -896,27 +947,37 @@ Db.prototype.createIndex = function(name, fieldOrSpec, options, callback) {
896
947
  });
897
948
  };
898
949
 
899
- var ensureIndex = function(self, name, fieldOrSpec, options, callback) {
950
+ var createIndex = function(self, name, fieldOrSpec, options, callback) {
900
951
  // Get the write concern options
901
952
  var finalOptions = writeConcern({}, self, options);
902
- // Create command
903
- var selector = createCreateIndexCommand(self, name, fieldOrSpec, options);
904
- var index_name = selector.name;
953
+ // Ensure we have a callback
954
+ if(finalOptions.writeConcern && typeof callback != 'function') {
955
+ throw MongoError.create({message: "Cannot use a writeConcern without a provided callback", driver:true});
956
+ }
905
957
 
906
- // Default command options
907
- var commandOptions = {};
908
- // Check if the index allready exists
909
- self.indexInformation(name, finalOptions, function(err, indexInformation) {
910
- if(err != null && err.code != 26) return handleCallback(callback, err, null);
911
- // If the index does not exist, create it
912
- if(indexInformation == null || !indexInformation[index_name]) {
913
- self.createIndex(name, fieldOrSpec, options, callback);
914
- } else {
915
- if(typeof callback === 'function') return handleCallback(callback, null, index_name);
916
- }
917
- });
958
+ // Did the user destroy the topology
959
+ if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
960
+
961
+ // Attempt to run using createIndexes command
962
+ createIndexUsingCreateIndexes(self, name, fieldOrSpec, options, function(err, result) {
963
+ if(err == null) return handleCallback(callback, err, result);
964
+ // Create command
965
+ var doc = createCreateIndexCommand(self, name, fieldOrSpec, options);
966
+ // Set no key checking
967
+ finalOptions.checkKeys = false;
968
+ // Insert document
969
+ self.s.topology.insert(f("%s.%s", self.s.databaseName, Db.SYSTEM_INDEX_COLLECTION), doc, finalOptions, function(err, result) {
970
+ if(callback == null) return;
971
+ if(err) return handleCallback(callback, err);
972
+ if(result == null) return handleCallback(callback, null, null);
973
+ if(result.result.writeErrors) return handleCallback(callback, MongoError.create(result.result.writeErrors[0]), null);
974
+ handleCallback(callback, null, doc.name);
975
+ });
976
+ });
918
977
  }
919
978
 
979
+ define.classMethod('createIndex', {callback: true, promise:true});
980
+
920
981
  /**
921
982
  * Ensures that an index exists, if it does not it creates it
922
983
  * @method
@@ -936,7 +997,7 @@ var ensureIndex = function(self, name, fieldOrSpec, options, callback) {
936
997
  * @param {number} [options.v=null] Specify the format version of the indexes.
937
998
  * @param {number} [options.expireAfterSeconds=null] Allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
938
999
  * @param {number} [options.name=null] Override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
939
- * @param {Db~resultCallback} callback The command result callback
1000
+ * @param {Db~resultCallback} [callback] The command result callback
940
1001
  * @return {Promise} returns Promise if no callback passed
941
1002
  */
942
1003
  Db.prototype.ensureIndex = function(name, fieldOrSpec, options, callback) {
@@ -946,7 +1007,7 @@ Db.prototype.ensureIndex = function(name, fieldOrSpec, options, callback) {
946
1007
 
947
1008
  // If we have a callback fallback
948
1009
  if(typeof callback == 'function') return ensureIndex(self, name, fieldOrSpec, options, callback);
949
-
1010
+
950
1011
  // Return a promise
951
1012
  return new this.s.promiseLibrary(function(resolve, reject) {
952
1013
  ensureIndex(self, name, fieldOrSpec, options, function(err, r) {
@@ -956,38 +1017,86 @@ Db.prototype.ensureIndex = function(name, fieldOrSpec, options, callback) {
956
1017
  });
957
1018
  };
958
1019
 
1020
+ var ensureIndex = function(self, name, fieldOrSpec, options, callback) {
1021
+ // Get the write concern options
1022
+ var finalOptions = writeConcern({}, self, options);
1023
+ // Create command
1024
+ var selector = createCreateIndexCommand(self, name, fieldOrSpec, options);
1025
+ var index_name = selector.name;
1026
+
1027
+ // Did the user destroy the topology
1028
+ if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
1029
+
1030
+ // Default command options
1031
+ var commandOptions = {};
1032
+ // Check if the index allready exists
1033
+ self.indexInformation(name, finalOptions, function(err, indexInformation) {
1034
+ if(err != null && err.code != 26) return handleCallback(callback, err, null);
1035
+ // If the index does not exist, create it
1036
+ if(indexInformation == null || !indexInformation[index_name]) {
1037
+ self.createIndex(name, fieldOrSpec, options, callback);
1038
+ } else {
1039
+ if(typeof callback === 'function') return handleCallback(callback, null, index_name);
1040
+ }
1041
+ });
1042
+ }
1043
+
1044
+ define.classMethod('ensureIndex', {callback: true, promise:true});
1045
+
959
1046
  Db.prototype.addChild = function(db) {
960
1047
  if(this.s.parentDb) return this.s.parentDb.addChild(db);
961
1048
  this.s.children.push(db);
962
1049
  }
963
1050
 
964
1051
  /**
965
- * Create a new Db instance sharing the current socket connections.
1052
+ * Create a new Db instance sharing the current socket connections. Be aware that the new db instances are
1053
+ * related in a parent-child relationship to the original instance so that events are correctly emitted on child
1054
+ * db instances. Child db instances are cached so performing db('db1') twice will return the same instance.
1055
+ * You can control these behaviors with the options noListener and returnNonCachedInstance.
1056
+ *
966
1057
  * @method
967
1058
  * @param {string} name The name of the database we want to use.
1059
+ * @param {object} [options=null] Optional settings.
1060
+ * @param {boolean} [options.noListener=false] Do not make the db an event listener to the original connection.
1061
+ * @param {boolean} [options.returnNonCachedInstance=false] Control if you want to return a cached instance or have a new one created
968
1062
  * @return {Db}
969
1063
  */
970
- Db.prototype.db = function(dbName) {
1064
+ Db.prototype.db = function(dbName, options) {
1065
+ options = options || {};
971
1066
  // Copy the options and add out internal override of the not shared flag
972
- var options = {};
973
1067
  for(var key in this.options) {
974
1068
  options[key] = this.options[key];
975
1069
  }
976
1070
 
1071
+ // Do we have the db in the cache already
1072
+ if(this.s.dbCache[dbName] && options.returnNonCachedInstance !== true) {
1073
+ return this.s.dbCache[dbName];
1074
+ }
1075
+
977
1076
  // Add current db as parentDb
978
- options.parentDb = this;
1077
+ if(options.noListener == null || options.noListener == false) {
1078
+ options.parentDb = this;
1079
+ }
1080
+
979
1081
  // Add promiseLibrary
980
1082
  options.promiseLibrary = this.s.promiseLibrary;
981
1083
 
982
1084
  // Return the db object
983
1085
  var db = new Db(dbName, this.s.topology, options)
1086
+
984
1087
  // Add as child
985
- this.addChild(db);
986
-
1088
+ if(options.noListener == null || options.noListener == false) {
1089
+ this.addChild(db);
1090
+ }
1091
+
1092
+ // Add the db to the cache
1093
+ this.s.dbCache[dbName] = db;
987
1094
  // Return the database
988
1095
  return db;
989
1096
  };
990
1097
 
1098
+ define.classMethod('db', {callback: false, promise:false, returns: [Db]});
1099
+
991
1100
  var _executeAuthCreateUserCommand = function(self, username, password, options, callback) {
992
1101
  // Special case where there is no password ($external users)
993
1102
  if(typeof username == 'string'
@@ -1066,6 +1175,8 @@ var _executeAuthCreateUserCommand = function(self, username, password, options,
1066
1175
  }
1067
1176
 
1068
1177
  var addUser = function(self, username, password, options, callback) {
1178
+ // Did the user destroy the topology
1179
+ if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
1069
1180
  // Attempt to execute auth command
1070
1181
  _executeAuthCreateUserCommand(self, username, password, options, function(err, r) {
1071
1182
  // We need to perform the backward compatible insert operation
@@ -1108,7 +1219,7 @@ var addUser = function(self, username, password, options, callback) {
1108
1219
 
1109
1220
  if(err) return handleCallback(callback, err);
1110
1221
  handleCallback(callback, err, r);
1111
- });
1222
+ });
1112
1223
  }
1113
1224
 
1114
1225
  /**
@@ -1122,7 +1233,7 @@ var addUser = function(self, username, password, options, callback) {
1122
1233
  * @param {boolean} [options.j=false] Specify a journal write concern.
1123
1234
  * @param {object} [options.customData=null] Custom data associated with the user (only Mongodb 2.6 or higher)
1124
1235
  * @param {object[]} [options.roles=null] Roles associated with the created user (only Mongodb 2.6 or higher)
1125
- * @param {Db~resultCallback} callback The command result callback
1236
+ * @param {Db~resultCallback} [callback] The command result callback
1126
1237
  * @return {Promise} returns Promise if no callback passed
1127
1238
  */
1128
1239
  Db.prototype.addUser = function(username, password, options, callback) {
@@ -1135,7 +1246,7 @@ Db.prototype.addUser = function(username, password, options, callback) {
1135
1246
 
1136
1247
  // If we have a callback fallback
1137
1248
  if(typeof callback == 'function') return addUser(self, username, password, options, callback);
1138
-
1249
+
1139
1250
  // Return a promise
1140
1251
  return new this.s.promiseLibrary(function(resolve, reject) {
1141
1252
  addUser(self, username, password, options, function(err, r) {
@@ -1145,8 +1256,12 @@ Db.prototype.addUser = function(username, password, options, callback) {
1145
1256
  });
1146
1257
  };
1147
1258
 
1259
+ define.classMethod('addUser', {callback: true, promise:true});
1260
+
1148
1261
  var _executeAuthRemoveUserCommand = function(self, username, options, callback) {
1149
1262
  if(typeof options == 'function') callback = options, options = {};
1263
+ // Did the user destroy the topology
1264
+ if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
1150
1265
  // Get the error options
1151
1266
  var commandOptions = {writeCommand:true};
1152
1267
  if(options['dbName']) commandOptions.dbName = options['dbName'];
@@ -1200,9 +1315,11 @@ var removeUser = function(self, username, options, callback) {
1200
1315
 
1201
1316
  if(err) return handleCallback(callback, err);
1202
1317
  handleCallback(callback, err, result);
1203
- });
1318
+ });
1204
1319
  }
1205
1320
 
1321
+ define.classMethod('removeUser', {callback: true, promise:true});
1322
+
1206
1323
  /**
1207
1324
  * Remove a user from a database
1208
1325
  * @method
@@ -1211,7 +1328,7 @@ var removeUser = function(self, username, options, callback) {
1211
1328
  * @param {(number|string)} [options.w=null] The write concern.
1212
1329
  * @param {number} [options.wtimeout=null] The write concern timeout.
1213
1330
  * @param {boolean} [options.j=false] Specify a journal write concern.
1214
- * @param {Db~resultCallback} callback The command result callback
1331
+ * @param {Db~resultCallback} [callback] The command result callback
1215
1332
  * @return {Promise} returns Promise if no callback passed
1216
1333
  */
1217
1334
  Db.prototype.removeUser = function(username, options, callback) {
@@ -1235,6 +1352,8 @@ Db.prototype.removeUser = function(username, options, callback) {
1235
1352
  };
1236
1353
 
1237
1354
  var authenticate = function(self, username, password, options, callback) {
1355
+ // Did the user destroy the topology
1356
+ if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
1238
1357
  // the default db to authenticate against is 'self'
1239
1358
  // if authententicate is called from a retry context, it may be another one, like admin
1240
1359
  var authdb = options.authdb ? options.authdb : options.dbName;
@@ -1294,7 +1413,7 @@ var authenticate = function(self, username, password, options, callback) {
1294
1413
  _callback(null, true);
1295
1414
  });
1296
1415
  } else {
1297
- handleCallback(callback, new MongoError(f("authentication mechanism %s not supported", options.authMechanism), false));
1416
+ handleCallback(callback, MongoError.create({message: f("authentication mechanism %s not supported", options.authMechanism), driver:true}));
1298
1417
  }
1299
1418
  }
1300
1419
 
@@ -1305,7 +1424,7 @@ var authenticate = function(self, username, password, options, callback) {
1305
1424
  * @param {string} [password] The password.
1306
1425
  * @param {object} [options=null] Optional settings.
1307
1426
  * @param {string} [options.authMechanism=MONGODB-CR] The authentication mechanism to use, GSSAPI, MONGODB-CR, MONGODB-X509, PLAIN
1308
- * @param {Db~resultCallback} callback The command result callback
1427
+ * @param {Db~resultCallback} [callback] The command result callback
1309
1428
  * @return {Promise} returns Promise if no callback passed
1310
1429
  */
1311
1430
  Db.prototype.authenticate = function(username, password, options, callback) {
@@ -1322,27 +1441,38 @@ Db.prototype.authenticate = function(username, password, options, callback) {
1322
1441
  && options.authMechanism != 'MONGODB-X509'
1323
1442
  && options.authMechanism != 'SCRAM-SHA-1'
1324
1443
  && options.authMechanism != 'PLAIN') {
1325
- return handleCallback(callback, new MongoError("only GSSAPI, PLAIN, MONGODB-X509, SCRAM-SHA-1 or MONGODB-CR is supported by authMechanism"));
1444
+ return handleCallback(callback, MongoError.create({message: "only GSSAPI, PLAIN, MONGODB-X509, SCRAM-SHA-1 or MONGODB-CR is supported by authMechanism", driver:true}));
1326
1445
  }
1327
1446
 
1328
1447
  // If we have a callback fallback
1329
- if(typeof callback == 'function') return authenticate(self, username, password, options, callback);
1330
-
1448
+ if(typeof callback == 'function') return authenticate(self, username, password, options, function(err, r) {
1449
+ // Support failed auth method
1450
+ if(err && err.message && err.message.indexOf('saslStart') != -1) err.code = 59;
1451
+ // Reject error
1452
+ if(err) return callback(err, r);
1453
+ callback(null, r);
1454
+ });
1455
+
1331
1456
  // Return a promise
1332
1457
  return new this.s.promiseLibrary(function(resolve, reject) {
1333
1458
  authenticate(self, username, password, options, function(err, r) {
1459
+ // Support failed auth method
1460
+ if(err && err.message && err.message.indexOf('saslStart') != -1) err.code = 59;
1461
+ // Reject error
1334
1462
  if(err) return reject(err);
1335
1463
  resolve(r);
1336
1464
  });
1337
1465
  });
1338
1466
  };
1339
1467
 
1468
+ define.classMethod('authenticate', {callback: true, promise:true});
1469
+
1340
1470
  /**
1341
1471
  * Logout user from server, fire off on all connections and remove all auth info
1342
1472
  * @method
1343
1473
  * @param {object} [options=null] Optional settings.
1344
1474
  * @param {string} [options.dbName=null] Logout against different database than current.
1345
- * @param {Db~resultCallback} callback The command result callback
1475
+ * @param {Db~resultCallback} [callback] The command result callback
1346
1476
  * @return {Promise} returns Promise if no callback passed
1347
1477
  */
1348
1478
  Db.prototype.logout = function(options, callback) {
@@ -1363,6 +1493,8 @@ Db.prototype.logout = function(options, callback) {
1363
1493
 
1364
1494
  // Execute the command
1365
1495
  if(typeof callback == 'function') return this.command(cmd, options, function(err, result) {
1496
+ // Did the user destroy the topology
1497
+ if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
1366
1498
  if(err) return handleCallback(callback, err, false);
1367
1499
  handleCallback(callback, null, true)
1368
1500
  });
@@ -1370,12 +1502,16 @@ Db.prototype.logout = function(options, callback) {
1370
1502
  // Return promise
1371
1503
  return new this.s.promiseLibrary(function(resolve, reject) {
1372
1504
  self.command(cmd, options, function(err, result) {
1505
+ // Did the user destroy the topology
1506
+ if(self.serverConfig && self.serverConfig.isDestroyed()) return reject(new MongoError('topology was destroyed'));
1373
1507
  if(err) return reject(err);
1374
1508
  resolve(true);
1375
1509
  });
1376
1510
  });
1377
1511
  }
1378
1512
 
1513
+ define.classMethod('logout', {callback: true, promise:true});
1514
+
1379
1515
  // Figure out the read preference
1380
1516
  var getReadPreference = function(options, db) {
1381
1517
  if(options.readPreference) return options;
@@ -1390,7 +1526,7 @@ var getReadPreference = function(options, db) {
1390
1526
  * @param {object} [options=null] Optional settings.
1391
1527
  * @param {boolean} [options.full=false] Returns the full raw index information.
1392
1528
  * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
1393
- * @param {Db~resultCallback} callback The command result callback
1529
+ * @param {Db~resultCallback} [callback] The command result callback
1394
1530
  * @return {Promise} returns Promise if no callback passed
1395
1531
  */
1396
1532
  Db.prototype.indexInformation = function(name, options, callback) {
@@ -1400,7 +1536,7 @@ Db.prototype.indexInformation = function(name, options, callback) {
1400
1536
 
1401
1537
  // If we have a callback fallback
1402
1538
  if(typeof callback == 'function') return indexInformation(self, name, options, callback);
1403
-
1539
+
1404
1540
  // Return a promise
1405
1541
  return new this.s.promiseLibrary(function(resolve, reject) {
1406
1542
  indexInformation(self, name, options, function(err, r) {
@@ -1414,6 +1550,9 @@ var indexInformation = function(self, name, options, callback) {
1414
1550
  // If we specified full information
1415
1551
  var full = options['full'] == null ? false : options['full'];
1416
1552
 
1553
+ // Did the user destroy the topology
1554
+ if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
1555
+
1417
1556
  // Process all the results from the index command and collection
1418
1557
  var processResults = function(indexes) {
1419
1558
  // Contains all the information
@@ -1440,6 +1579,8 @@ var indexInformation = function(self, name, options, callback) {
1440
1579
  });
1441
1580
  }
1442
1581
 
1582
+ define.classMethod('indexInformation', {callback: true, promise:true});
1583
+
1443
1584
  var createCreateIndexCommand = function(db, name, fieldOrSpec, options) {
1444
1585
  var indexParameters = parseIndexOptions(fieldOrSpec);
1445
1586
  var fieldHash = indexParameters.fieldHash;
@@ -1514,13 +1655,13 @@ var createIndexUsingCreateIndexes = function(self, name, fieldOrSpec, options, c
1514
1655
 
1515
1656
  // Validate the database name
1516
1657
  var validateDatabaseName = function(databaseName) {
1517
- if(typeof databaseName !== 'string') throw new MongoError("database name must be a string");
1518
- if(databaseName.length === 0) throw new MongoError("database name cannot be the empty string");
1658
+ if(typeof databaseName !== 'string') throw MongoError.create({message: "database name must be a string", driver:true});
1659
+ if(databaseName.length === 0) throw MongoError.create({message: "database name cannot be the empty string", driver:true});
1519
1660
  if(databaseName == '$external') return;
1520
1661
 
1521
1662
  var invalidChars = [" ", ".", "$", "/", "\\"];
1522
1663
  for(var i = 0; i < invalidChars.length; i++) {
1523
- if(databaseName.indexOf(invalidChars[i]) != -1) throw new MongoError("database names cannot contain the character '" + invalidChars[i] + "'");
1664
+ if(databaseName.indexOf(invalidChars[i]) != -1) throw MongoError.create({message: "database names cannot contain the character '" + invalidChars[i] + "'", driver:true});
1524
1665
  }
1525
1666
  }
1526
1667
 
@@ -1558,13 +1699,17 @@ var createListener = function(self, e, object) {
1558
1699
  /**
1559
1700
  * Db close event
1560
1701
  *
1702
+ * Emitted after a socket closed against a single server or mongos proxy.
1703
+ *
1561
1704
  * @event Db#close
1562
- * @type {object}
1705
+ * @type {MongoError}
1563
1706
  */
1564
1707
 
1565
1708
  /**
1566
1709
  * Db authenticated event
1567
1710
  *
1711
+ * Emitted after all server members in the topology (single server, replicaset or mongos) have successfully authenticated.
1712
+ *
1568
1713
  * @event Db#authenticated
1569
1714
  * @type {object}
1570
1715
  */
@@ -1572,6 +1717,10 @@ var createListener = function(self, e, object) {
1572
1717
  /**
1573
1718
  * Db reconnect event
1574
1719
  *
1720
+ * * Server: Emitted when the driver has reconnected and re-authenticated.
1721
+ * * ReplicaSet: N/A
1722
+ * * Mongos: Emitted when the driver reconnects and re-authenticates successfully against a Mongos.
1723
+ *
1575
1724
  * @event Db#reconnect
1576
1725
  * @type {object}
1577
1726
  */
@@ -1579,6 +1728,8 @@ var createListener = function(self, e, object) {
1579
1728
  /**
1580
1729
  * Db error event
1581
1730
  *
1731
+ * Emitted after an error occurred against a single server or mongos proxy.
1732
+ *
1582
1733
  * @event Db#error
1583
1734
  * @type {MongoError}
1584
1735
  */
@@ -1586,19 +1737,27 @@ var createListener = function(self, e, object) {
1586
1737
  /**
1587
1738
  * Db timeout event
1588
1739
  *
1740
+ * Emitted after a socket timeout occurred against a single server or mongos proxy.
1741
+ *
1589
1742
  * @event Db#timeout
1590
- * @type {object}
1743
+ * @type {MongoError}
1591
1744
  */
1592
1745
 
1593
1746
  /**
1594
1747
  * Db parseError event
1595
1748
  *
1749
+ * The parseError event is emitted if the driver detects illegal or corrupt BSON being received from the server.
1750
+ *
1596
1751
  * @event Db#parseError
1597
- * @type {object}
1752
+ * @type {MongoError}
1598
1753
  */
1599
1754
 
1600
1755
  /**
1601
- * Db fullsetup event, emitted when all servers in the topology have been connected to.
1756
+ * Db fullsetup event, emitted when all servers in the topology have been connected to at start up time.
1757
+ *
1758
+ * * Server: Emitted when the driver has connected to the single server and has authenticated.
1759
+ * * ReplSet: Emitted after the driver has attempted to connect to all replicaset members.
1760
+ * * Mongos: Emitted after the driver has attempted to connect to all mongos proxies.
1602
1761
  *
1603
1762
  * @event Db#fullsetup
1604
1763
  * @type {Db}