index.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818
  1. 'use strict';
  2. /*!
  3. * Module dependencies.
  4. */
  5. var Schema = require('./schema'),
  6. SchemaType = require('./schematype'),
  7. VirtualType = require('./virtualtype'),
  8. STATES = require('./connectionstate'),
  9. Types = require('./types'),
  10. Query = require('./query'),
  11. Model = require('./model'),
  12. Document = require('./document'),
  13. utils = require('./utils'),
  14. format = utils.toCollectionName,
  15. pkg = require('../package.json');
  16. var querystring = require('querystring');
  17. var Aggregate = require('./aggregate');
  18. var PromiseProvider = require('./promise_provider');
  19. /**
  20. * Mongoose constructor.
  21. *
  22. * The exports object of the `mongoose` module is an instance of this class.
  23. * Most apps will only use this one instance.
  24. *
  25. * @api public
  26. */
  27. function Mongoose() {
  28. this.connections = [];
  29. this.plugins = [];
  30. this.models = {};
  31. this.modelSchemas = {};
  32. // default global options
  33. this.options = {
  34. pluralization: true
  35. };
  36. var conn = this.createConnection(); // default connection
  37. conn.models = this.models;
  38. }
  39. /**
  40. * Expose connection states for user-land
  41. *
  42. */
  43. Mongoose.prototype.STATES = STATES;
  44. /**
  45. * Sets mongoose options
  46. *
  47. * ####Example:
  48. *
  49. * mongoose.set('test', value) // sets the 'test' option to `value`
  50. *
  51. * mongoose.set('debug', true) // enable logging collection methods + arguments to the console
  52. *
  53. * mongoose.set('debug', function(collectionName, methodName, arg1, arg2...) {}); // use custom function to log collection methods + arguments
  54. *
  55. * @param {String} key
  56. * @param {String|Function} value
  57. * @api public
  58. */
  59. Mongoose.prototype.set = function(key, value) {
  60. if (arguments.length === 1) {
  61. return this.options[key];
  62. }
  63. this.options[key] = value;
  64. return this;
  65. };
  66. Mongoose.prototype.set.$hasSideEffects = true;
  67. /**
  68. * Gets mongoose options
  69. *
  70. * ####Example:
  71. *
  72. * mongoose.get('test') // returns the 'test' value
  73. *
  74. * @param {String} key
  75. * @method get
  76. * @api public
  77. */
  78. Mongoose.prototype.get = Mongoose.prototype.set;
  79. /*!
  80. * ReplSet connection string check.
  81. */
  82. var rgxReplSet = /^.+,.+$/;
  83. /**
  84. * Checks if ?replicaSet query parameter is specified in URI
  85. *
  86. * ####Example:
  87. *
  88. * checkReplicaSetInUri('localhost:27000?replicaSet=rs0'); // true
  89. *
  90. * @param {String} uri
  91. * @return {boolean}
  92. * @api private
  93. */
  94. var checkReplicaSetInUri = function(uri) {
  95. if (!uri) {
  96. return false;
  97. }
  98. var queryStringStart = uri.indexOf('?');
  99. var isReplicaSet = false;
  100. if (queryStringStart !== -1) {
  101. try {
  102. var obj = querystring.parse(uri.substr(queryStringStart + 1));
  103. if (obj && obj.replicaSet) {
  104. isReplicaSet = true;
  105. }
  106. } catch (e) {
  107. return false;
  108. }
  109. }
  110. return isReplicaSet;
  111. };
  112. /**
  113. * Creates a Connection instance.
  114. *
  115. * Each `connection` instance maps to a single database. This method is helpful when mangaging multiple db connections.
  116. *
  117. * If arguments are passed, they are proxied to either [Connection#open](#connection_Connection-open) or [Connection#openSet](#connection_Connection-openSet) appropriately. This means we can pass `db`, `server`, and `replset` options to the driver. _Note that the `safe` option specified in your schema will overwrite the `safe` db option specified here unless you set your schemas `safe` option to `undefined`. See [this](/docs/guide.html#safe) for more information._
  118. *
  119. * _Options passed take precedence over options included in connection strings._
  120. *
  121. * ####Example:
  122. *
  123. * // with mongodb:// URI
  124. * db = mongoose.createConnection('mongodb://user:pass@localhost:port/database');
  125. *
  126. * // and options
  127. * var opts = { db: { native_parser: true }}
  128. * db = mongoose.createConnection('mongodb://user:pass@localhost:port/database', opts);
  129. *
  130. * // replica sets
  131. * db = mongoose.createConnection('mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/database');
  132. *
  133. * // and options
  134. * var opts = { replset: { strategy: 'ping', rs_name: 'testSet' }}
  135. * db = mongoose.createConnection('mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/database', opts);
  136. *
  137. * // with [host, database_name[, port] signature
  138. * db = mongoose.createConnection('localhost', 'database', port)
  139. *
  140. * // and options
  141. * var opts = { server: { auto_reconnect: false }, user: 'username', pass: 'mypassword' }
  142. * db = mongoose.createConnection('localhost', 'database', port, opts)
  143. *
  144. * // initialize now, connect later
  145. * db = mongoose.createConnection();
  146. * db.open('localhost', 'database', port, [opts]);
  147. *
  148. * @param {String} [uri] a mongodb:// URI
  149. * @param {Object} [options] options to pass to the driver
  150. * @param {Object} [options.config] mongoose-specific options
  151. * @param {Boolean} [options.config.autoIndex] set to false to disable automatic index creation for all models associated with this connection.
  152. * @see Connection#open #connection_Connection-open
  153. * @see Connection#openSet #connection_Connection-openSet
  154. * @return {Connection} the created Connection object
  155. * @api public
  156. */
  157. Mongoose.prototype.createConnection = function(uri, options) {
  158. var conn = new Connection(this);
  159. this.connections.push(conn);
  160. var rsOption = options && (options.replset || options.replSet);
  161. if (arguments.length) {
  162. if (rgxReplSet.test(arguments[0]) || checkReplicaSetInUri(arguments[0])) {
  163. conn.openSet.apply(conn, arguments).catch(function() {});
  164. } else if (rsOption &&
  165. (rsOption.replicaSet || rsOption.rs_name)) {
  166. conn.openSet.apply(conn, arguments).catch(function() {});
  167. } else {
  168. conn.open.apply(conn, arguments).catch(function() {});
  169. }
  170. }
  171. return conn;
  172. };
  173. Mongoose.prototype.createConnection.$hasSideEffects = true;
  174. /**
  175. * Opens the default mongoose connection.
  176. *
  177. * If arguments are passed, they are proxied to either
  178. * [Connection#open](#connection_Connection-open) or
  179. * [Connection#openSet](#connection_Connection-openSet) appropriately.
  180. *
  181. * _Options passed take precedence over options included in connection strings._
  182. *
  183. * ####Example:
  184. *
  185. * mongoose.connect('mongodb://user:pass@localhost:port/database');
  186. *
  187. * // replica sets
  188. * var uri = 'mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/mydatabase';
  189. * mongoose.connect(uri);
  190. *
  191. * // with options
  192. * mongoose.connect(uri, options);
  193. *
  194. * // connecting to multiple mongos
  195. * var uri = 'mongodb://hostA:27501,hostB:27501';
  196. * var opts = { mongos: true };
  197. * mongoose.connect(uri, opts);
  198. *
  199. * // optional callback that gets fired when initial connection completed
  200. * var uri = 'mongodb://nonexistent.domain:27000';
  201. * mongoose.connect(uri, function(error) {
  202. * // if error is truthy, the initial connection failed.
  203. * })
  204. *
  205. * @param {String} uri(s)
  206. * @param {Object} [options]
  207. * @param {Function} [callback]
  208. * @see Mongoose#createConnection #index_Mongoose-createConnection
  209. * @api public
  210. * @return {MongooseThenable} pseudo-promise wrapper around this
  211. */
  212. Mongoose.prototype.connect = function() {
  213. var conn = this.connection;
  214. if (rgxReplSet.test(arguments[0]) || checkReplicaSetInUri(arguments[0])) {
  215. return new MongooseThenable(this, conn.openSet.apply(conn, arguments));
  216. }
  217. return new MongooseThenable(this, conn.open.apply(conn, arguments));
  218. };
  219. Mongoose.prototype.connect.$hasSideEffects = true;
  220. /**
  221. * Disconnects all connections.
  222. *
  223. * @param {Function} [fn] called after all connection close.
  224. * @return {MongooseThenable} pseudo-promise wrapper around this
  225. * @api public
  226. */
  227. Mongoose.prototype.disconnect = function(fn) {
  228. var error;
  229. this.connections.forEach(function(conn) {
  230. conn.close(function(err) {
  231. if (error) {
  232. return;
  233. }
  234. if (err) {
  235. error = err;
  236. }
  237. });
  238. });
  239. var Promise = PromiseProvider.get();
  240. return new MongooseThenable(this, new Promise.ES6(function(resolve, reject) {
  241. fn && fn(error);
  242. if (error) {
  243. reject(error);
  244. return;
  245. }
  246. resolve();
  247. }));
  248. };
  249. Mongoose.prototype.disconnect.$hasSideEffects = true;
  250. /**
  251. * Defines a model or retrieves it.
  252. *
  253. * Models defined on the `mongoose` instance are available to all connection created by the same `mongoose` instance.
  254. *
  255. * ####Example:
  256. *
  257. * var mongoose = require('mongoose');
  258. *
  259. * // define an Actor model with this mongoose instance
  260. * mongoose.model('Actor', new Schema({ name: String }));
  261. *
  262. * // create a new connection
  263. * var conn = mongoose.createConnection(..);
  264. *
  265. * // retrieve the Actor model
  266. * var Actor = conn.model('Actor');
  267. *
  268. * _When no `collection` argument is passed, Mongoose produces a collection name by passing the model `name` to the [utils.toCollectionName](#utils_exports.toCollectionName) method. This method pluralizes the name. If you don't like this behavior, either pass a collection name or set your schemas collection name option._
  269. *
  270. * ####Example:
  271. *
  272. * var schema = new Schema({ name: String }, { collection: 'actor' });
  273. *
  274. * // or
  275. *
  276. * schema.set('collection', 'actor');
  277. *
  278. * // or
  279. *
  280. * var collectionName = 'actor'
  281. * var M = mongoose.model('Actor', schema, collectionName)
  282. *
  283. * @param {String|Function} name model name or class extending Model
  284. * @param {Schema} [schema]
  285. * @param {String} [collection] name (optional, inferred from model name)
  286. * @param {Boolean} [skipInit] whether to skip initialization (defaults to false)
  287. * @api public
  288. */
  289. Mongoose.prototype.model = function(name, schema, collection, skipInit) {
  290. var model;
  291. if (typeof name === 'function') {
  292. model = name;
  293. name = model.name;
  294. if (!(model.prototype instanceof Model)) {
  295. throw new mongoose.Error('The provided class ' + name + ' must extend Model');
  296. }
  297. }
  298. if (typeof schema === 'string') {
  299. collection = schema;
  300. schema = false;
  301. }
  302. if (utils.isObject(schema) && !(schema.instanceOfSchema)) {
  303. schema = new Schema(schema);
  304. }
  305. if (schema && !schema.instanceOfSchema) {
  306. throw new Error('The 2nd parameter to `mongoose.model()` should be a ' +
  307. 'schema or a POJO');
  308. }
  309. if (typeof collection === 'boolean') {
  310. skipInit = collection;
  311. collection = null;
  312. }
  313. // handle internal options from connection.model()
  314. var options;
  315. if (skipInit && utils.isObject(skipInit)) {
  316. options = skipInit;
  317. skipInit = true;
  318. } else {
  319. options = {};
  320. }
  321. // look up schema for the collection.
  322. if (!this.modelSchemas[name]) {
  323. if (schema) {
  324. // cache it so we only apply plugins once
  325. this.modelSchemas[name] = schema;
  326. } else {
  327. throw new mongoose.Error.MissingSchemaError(name);
  328. }
  329. }
  330. if (schema) {
  331. this._applyPlugins(schema);
  332. }
  333. var sub;
  334. // connection.model() may be passing a different schema for
  335. // an existing model name. in this case don't read from cache.
  336. if (this.models[name] && options.cache !== false) {
  337. if (schema && schema.instanceOfSchema && schema !== this.models[name].schema) {
  338. throw new mongoose.Error.OverwriteModelError(name);
  339. }
  340. if (collection) {
  341. // subclass current model with alternate collection
  342. model = this.models[name];
  343. schema = model.prototype.schema;
  344. sub = model.__subclass(this.connection, schema, collection);
  345. // do not cache the sub model
  346. return sub;
  347. }
  348. return this.models[name];
  349. }
  350. // ensure a schema exists
  351. if (!schema) {
  352. schema = this.modelSchemas[name];
  353. if (!schema) {
  354. throw new mongoose.Error.MissingSchemaError(name);
  355. }
  356. }
  357. // Apply relevant "global" options to the schema
  358. if (!('pluralization' in schema.options)) schema.options.pluralization = this.options.pluralization;
  359. if (!collection) {
  360. collection = schema.get('collection') || format(name, schema.options);
  361. }
  362. var connection = options.connection || this.connection;
  363. model = this.Model.compile(model || name, schema, collection, connection, this);
  364. if (!skipInit) {
  365. model.init();
  366. }
  367. if (options.cache === false) {
  368. return model;
  369. }
  370. this.models[name] = model;
  371. return this.models[name];
  372. };
  373. Mongoose.prototype.model.$hasSideEffects = true;
  374. /**
  375. * Returns an array of model names created on this instance of Mongoose.
  376. *
  377. * ####Note:
  378. *
  379. * _Does not include names of models created using `connection.model()`._
  380. *
  381. * @api public
  382. * @return {Array}
  383. */
  384. Mongoose.prototype.modelNames = function() {
  385. var names = Object.keys(this.models);
  386. return names;
  387. };
  388. Mongoose.prototype.modelNames.$hasSideEffects = true;
  389. /**
  390. * Applies global plugins to `schema`.
  391. *
  392. * @param {Schema} schema
  393. * @api private
  394. */
  395. Mongoose.prototype._applyPlugins = function(schema) {
  396. if (schema.$globalPluginsApplied) {
  397. return;
  398. }
  399. var i;
  400. var len;
  401. for (i = 0, len = this.plugins.length; i < len; ++i) {
  402. schema.plugin(this.plugins[i][0], this.plugins[i][1]);
  403. }
  404. schema.$globalPluginsApplied = true;
  405. for (i = 0, len = schema.childSchemas.length; i < len; ++i) {
  406. this._applyPlugins(schema.childSchemas[i]);
  407. }
  408. };
  409. Mongoose.prototype._applyPlugins.$hasSideEffects = true;
  410. /**
  411. * Declares a global plugin executed on all Schemas.
  412. *
  413. * Equivalent to calling `.plugin(fn)` on each Schema you create.
  414. *
  415. * @param {Function} fn plugin callback
  416. * @param {Object} [opts] optional options
  417. * @return {Mongoose} this
  418. * @see plugins ./plugins.html
  419. * @api public
  420. */
  421. Mongoose.prototype.plugin = function(fn, opts) {
  422. this.plugins.push([fn, opts]);
  423. return this;
  424. };
  425. Mongoose.prototype.plugin.$hasSideEffects = true;
  426. /**
  427. * The default connection of the mongoose module.
  428. *
  429. * ####Example:
  430. *
  431. * var mongoose = require('mongoose');
  432. * mongoose.connect(...);
  433. * mongoose.connection.on('error', cb);
  434. *
  435. * This is the connection used by default for every model created using [mongoose.model](#index_Mongoose-model).
  436. *
  437. * @property connection
  438. * @return {Connection}
  439. * @api public
  440. */
  441. Mongoose.prototype.__defineGetter__('connection', function() {
  442. return this.connections[0];
  443. });
  444. Mongoose.prototype.__defineSetter__('connection', function(v) {
  445. this.connections[0] = v;
  446. });
  447. /*!
  448. * Driver depentend APIs
  449. */
  450. var driver = global.MONGOOSE_DRIVER_PATH || './drivers/node-mongodb-native';
  451. /*!
  452. * Connection
  453. */
  454. var Connection = require(driver + '/connection');
  455. /*!
  456. * Collection
  457. */
  458. var Collection = require(driver + '/collection');
  459. /**
  460. * The Mongoose Aggregate constructor
  461. *
  462. * @method Aggregate
  463. * @api public
  464. */
  465. Mongoose.prototype.Aggregate = Aggregate;
  466. /**
  467. * The Mongoose Collection constructor
  468. *
  469. * @method Collection
  470. * @api public
  471. */
  472. Mongoose.prototype.Collection = Collection;
  473. /**
  474. * The Mongoose [Connection](#connection_Connection) constructor
  475. *
  476. * @method Connection
  477. * @api public
  478. */
  479. Mongoose.prototype.Connection = Connection;
  480. /**
  481. * The Mongoose version
  482. *
  483. * @property version
  484. * @api public
  485. */
  486. Mongoose.prototype.version = pkg.version;
  487. /**
  488. * The Mongoose constructor
  489. *
  490. * The exports of the mongoose module is an instance of this class.
  491. *
  492. * ####Example:
  493. *
  494. * var mongoose = require('mongoose');
  495. * var mongoose2 = new mongoose.Mongoose();
  496. *
  497. * @method Mongoose
  498. * @api public
  499. */
  500. Mongoose.prototype.Mongoose = Mongoose;
  501. /**
  502. * The Mongoose [Schema](#schema_Schema) constructor
  503. *
  504. * ####Example:
  505. *
  506. * var mongoose = require('mongoose');
  507. * var Schema = mongoose.Schema;
  508. * var CatSchema = new Schema(..);
  509. *
  510. * @method Schema
  511. * @api public
  512. */
  513. Mongoose.prototype.Schema = Schema;
  514. /**
  515. * The Mongoose [SchemaType](#schematype_SchemaType) constructor
  516. *
  517. * @method SchemaType
  518. * @api public
  519. */
  520. Mongoose.prototype.SchemaType = SchemaType;
  521. /**
  522. * The various Mongoose SchemaTypes.
  523. *
  524. * ####Note:
  525. *
  526. * _Alias of mongoose.Schema.Types for backwards compatibility._
  527. *
  528. * @property SchemaTypes
  529. * @see Schema.SchemaTypes #schema_Schema.Types
  530. * @api public
  531. */
  532. Mongoose.prototype.SchemaTypes = Schema.Types;
  533. /**
  534. * The Mongoose [VirtualType](#virtualtype_VirtualType) constructor
  535. *
  536. * @method VirtualType
  537. * @api public
  538. */
  539. Mongoose.prototype.VirtualType = VirtualType;
  540. /**
  541. * The various Mongoose Types.
  542. *
  543. * ####Example:
  544. *
  545. * var mongoose = require('mongoose');
  546. * var array = mongoose.Types.Array;
  547. *
  548. * ####Types:
  549. *
  550. * - [ObjectId](#types-objectid-js)
  551. * - [Buffer](#types-buffer-js)
  552. * - [SubDocument](#types-embedded-js)
  553. * - [Array](#types-array-js)
  554. * - [DocumentArray](#types-documentarray-js)
  555. *
  556. * Using this exposed access to the `ObjectId` type, we can construct ids on demand.
  557. *
  558. * var ObjectId = mongoose.Types.ObjectId;
  559. * var id1 = new ObjectId;
  560. *
  561. * @property Types
  562. * @api public
  563. */
  564. Mongoose.prototype.Types = Types;
  565. /**
  566. * The Mongoose [Query](#query_Query) constructor.
  567. *
  568. * @method Query
  569. * @api public
  570. */
  571. Mongoose.prototype.Query = Query;
  572. /**
  573. * The Mongoose [Promise](#promise_Promise) constructor.
  574. *
  575. * @method Promise
  576. * @api public
  577. */
  578. Object.defineProperty(Mongoose.prototype, 'Promise', {
  579. get: function() {
  580. return PromiseProvider.get();
  581. },
  582. set: function(lib) {
  583. PromiseProvider.set(lib);
  584. }
  585. });
  586. /**
  587. * Storage layer for mongoose promises
  588. *
  589. * @method PromiseProvider
  590. * @api public
  591. */
  592. Mongoose.prototype.PromiseProvider = PromiseProvider;
  593. /**
  594. * The Mongoose [Model](#model_Model) constructor.
  595. *
  596. * @method Model
  597. * @api public
  598. */
  599. Mongoose.prototype.Model = Model;
  600. /**
  601. * The Mongoose [Document](#document-js) constructor.
  602. *
  603. * @method Document
  604. * @api public
  605. */
  606. Mongoose.prototype.Document = Document;
  607. /**
  608. * The Mongoose DocumentProvider constructor.
  609. *
  610. * @method DocumentProvider
  611. * @api public
  612. */
  613. Mongoose.prototype.DocumentProvider = require('./document_provider');
  614. /**
  615. * The [MongooseError](#error_MongooseError) constructor.
  616. *
  617. * @method Error
  618. * @api public
  619. */
  620. Mongoose.prototype.Error = require('./error');
  621. /**
  622. * The Mongoose CastError constructor
  623. *
  624. * @method CastError
  625. * @param {String} type The name of the type
  626. * @param {Any} value The value that failed to cast
  627. * @param {String} path The path `a.b.c` in the doc where this cast error occurred
  628. * @param {Error} [reason] The original error that was thrown
  629. * @api public
  630. */
  631. Mongoose.prototype.CastError = require('./error/cast');
  632. /**
  633. * The [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) driver Mongoose uses.
  634. *
  635. * @property mongo
  636. * @api public
  637. */
  638. Mongoose.prototype.mongo = require('mongodb');
  639. /**
  640. * The [mquery](https://github.com/aheckmann/mquery) query builder Mongoose uses.
  641. *
  642. * @property mquery
  643. * @api public
  644. */
  645. Mongoose.prototype.mquery = require('mquery');
  646. /**
  647. * Wraps the given Mongoose instance into a thenable (pseudo-promise). This
  648. * is so `connect()` and `disconnect()` can return a thenable while maintaining
  649. * backwards compatibility.
  650. *
  651. * @api private
  652. */
  653. function MongooseThenable(mongoose, promise) {
  654. var _this = this;
  655. for (var key in mongoose) {
  656. if (typeof mongoose[key] === 'function' && mongoose[key].$hasSideEffects) {
  657. (function(key) {
  658. _this[key] = function() {
  659. return mongoose[key].apply(mongoose, arguments);
  660. };
  661. })(key);
  662. } else if (['connection', 'connections'].indexOf(key) !== -1) {
  663. _this[key] = mongoose[key];
  664. }
  665. }
  666. this.$opPromise = promise;
  667. }
  668. MongooseThenable.prototype = new Mongoose;
  669. /**
  670. * Ability to use mongoose object as a pseudo-promise so `.connect().then()`
  671. * and `.disconnect().then()` are viable.
  672. *
  673. * @param {Function} onFulfilled
  674. * @param {Function} onRejected
  675. * @return {Promise}
  676. * @api private
  677. */
  678. MongooseThenable.prototype.then = function(onFulfilled, onRejected) {
  679. var Promise = PromiseProvider.get();
  680. if (!this.$opPromise) {
  681. return new Promise.ES6(function(resolve, reject) {
  682. reject(new Error('Can only call `.then()` if connect() or disconnect() ' +
  683. 'has been called'));
  684. }).then(onFulfilled, onRejected);
  685. }
  686. this.$opPromise.$hasHandler = true;
  687. return this.$opPromise.then(onFulfilled, onRejected);
  688. };
  689. /**
  690. * Ability to use mongoose object as a pseudo-promise so `.connect().then()`
  691. * and `.disconnect().then()` are viable.
  692. *
  693. * @param {Function} onFulfilled
  694. * @param {Function} onRejected
  695. * @return {Promise}
  696. * @api private
  697. */
  698. MongooseThenable.prototype.catch = function(onRejected) {
  699. return this.then(null, onRejected);
  700. };
  701. /*!
  702. * The exports object is an instance of Mongoose.
  703. *
  704. * @api public
  705. */
  706. var mongoose = module.exports = exports = new Mongoose;