connection.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854
  1. /*!
  2. * Module dependencies.
  3. */
  4. var utils = require('./utils');
  5. var EventEmitter = require('events').EventEmitter;
  6. var driver = global.MONGOOSE_DRIVER_PATH || './drivers/node-mongodb-native';
  7. var Schema = require('./schema');
  8. var Collection = require(driver + '/collection');
  9. var STATES = require('./connectionstate');
  10. var MongooseError = require('./error');
  11. var muri = require('muri');
  12. var PromiseProvider = require('./promise_provider');
  13. /*!
  14. * Protocol prefix regexp.
  15. *
  16. * @api private
  17. */
  18. var rgxProtocol = /^(?:.)+:\/\//;
  19. /*!
  20. * A list of authentication mechanisms that don't require a password for authentication.
  21. * This is used by the authMechanismDoesNotRequirePassword method.
  22. *
  23. * @api private
  24. */
  25. var authMechanismsWhichDontRequirePassword = [
  26. 'MONGODB-X509'
  27. ];
  28. /**
  29. * Connection constructor
  30. *
  31. * For practical reasons, a Connection equals a Db.
  32. *
  33. * @param {Mongoose} base a mongoose instance
  34. * @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
  35. * @event `connecting`: Emitted when `connection.{open,openSet}()` is executed on this connection.
  36. * @event `connected`: Emitted when this connection successfully connects to the db. May be emitted _multiple_ times in `reconnected` scenarios.
  37. * @event `open`: Emitted after we `connected` and `onOpen` is executed on all of this connections models.
  38. * @event `disconnecting`: Emitted when `connection.close()` was executed.
  39. * @event `disconnected`: Emitted after getting disconnected from the db.
  40. * @event `close`: Emitted after we `disconnected` and `onClose` executed on all of this connections models.
  41. * @event `reconnected`: Emitted after we `connected` and subsequently `disconnected`, followed by successfully another successfull connection.
  42. * @event `error`: Emitted when an error occurs on this connection.
  43. * @event `fullsetup`: Emitted in a replica-set scenario, when primary and at least one seconaries specified in the connection string are connected.
  44. * @event `all`: Emitted in a replica-set scenario, when all nodes specified in the connection string are connected.
  45. * @api public
  46. */
  47. function Connection(base) {
  48. this.base = base;
  49. this.collections = {};
  50. this.models = {};
  51. this.config = {autoIndex: true};
  52. this.replica = false;
  53. this.hosts = null;
  54. this.host = null;
  55. this.port = null;
  56. this.user = null;
  57. this.pass = null;
  58. this.name = null;
  59. this.options = null;
  60. this.otherDbs = [];
  61. this._readyState = STATES.disconnected;
  62. this._closeCalled = false;
  63. this._hasOpened = false;
  64. }
  65. /*!
  66. * Inherit from EventEmitter
  67. */
  68. Connection.prototype.__proto__ = EventEmitter.prototype;
  69. /**
  70. * Connection ready state
  71. *
  72. * - 0 = disconnected
  73. * - 1 = connected
  74. * - 2 = connecting
  75. * - 3 = disconnecting
  76. *
  77. * Each state change emits its associated event name.
  78. *
  79. * ####Example
  80. *
  81. * conn.on('connected', callback);
  82. * conn.on('disconnected', callback);
  83. *
  84. * @property readyState
  85. * @api public
  86. */
  87. Object.defineProperty(Connection.prototype, 'readyState', {
  88. get: function() {
  89. return this._readyState;
  90. },
  91. set: function(val) {
  92. if (!(val in STATES)) {
  93. throw new Error('Invalid connection state: ' + val);
  94. }
  95. if (this._readyState !== val) {
  96. this._readyState = val;
  97. // loop over the otherDbs on this connection and change their state
  98. for (var i = 0; i < this.otherDbs.length; i++) {
  99. this.otherDbs[i].readyState = val;
  100. }
  101. if (STATES.connected === val) {
  102. this._hasOpened = true;
  103. }
  104. this.emit(STATES[val]);
  105. }
  106. }
  107. });
  108. /**
  109. * A hash of the collections associated with this connection
  110. *
  111. * @property collections
  112. */
  113. Connection.prototype.collections;
  114. /**
  115. * The mongodb.Db instance, set when the connection is opened
  116. *
  117. * @property db
  118. */
  119. Connection.prototype.db;
  120. /**
  121. * A hash of the global options that are associated with this connection
  122. *
  123. * @property config
  124. */
  125. Connection.prototype.config;
  126. /**
  127. * Opens the connection to MongoDB.
  128. *
  129. * `options` is a hash with the following possible properties:
  130. *
  131. * config - passed to the connection config instance
  132. * db - passed to the connection db instance
  133. * server - passed to the connection server instance(s)
  134. * replset - passed to the connection ReplSet instance
  135. * user - username for authentication
  136. * pass - password for authentication
  137. * auth - options for authentication (see http://mongodb.github.com/node-mongodb-native/api-generated/db.html#authenticate)
  138. *
  139. * ####Notes:
  140. *
  141. * Mongoose forces the db option `forceServerObjectId` false and cannot be overridden.
  142. * Mongoose defaults the server `auto_reconnect` options to true which can be overridden.
  143. * See the node-mongodb-native driver instance for options that it understands.
  144. *
  145. * _Options passed take precedence over options included in connection strings._
  146. *
  147. * @param {String} connection_string mongodb://uri or the host to which you are connecting
  148. * @param {String} [database] database name
  149. * @param {Number} [port] database port
  150. * @param {Object} [options] options
  151. * @param {Function} [callback]
  152. * @see node-mongodb-native https://github.com/mongodb/node-mongodb-native
  153. * @see http://mongodb.github.com/node-mongodb-native/api-generated/db.html#authenticate
  154. * @api public
  155. */
  156. Connection.prototype.open = function(host, database, port, options, callback) {
  157. var parsed;
  158. var Promise = PromiseProvider.get();
  159. if (typeof database === 'string') {
  160. switch (arguments.length) {
  161. case 2:
  162. port = 27017;
  163. break;
  164. case 3:
  165. switch (typeof port) {
  166. case 'function':
  167. callback = port;
  168. port = 27017;
  169. break;
  170. case 'object':
  171. options = port;
  172. port = 27017;
  173. break;
  174. }
  175. break;
  176. case 4:
  177. if (typeof options === 'function') {
  178. callback = options;
  179. options = {};
  180. }
  181. }
  182. } else {
  183. switch (typeof database) {
  184. case 'function':
  185. callback = database;
  186. database = undefined;
  187. break;
  188. case 'object':
  189. options = database;
  190. database = undefined;
  191. callback = port;
  192. break;
  193. }
  194. if (!rgxProtocol.test(host)) {
  195. host = 'mongodb://' + host;
  196. }
  197. try {
  198. parsed = muri(host);
  199. } catch (err) {
  200. this.error(err, callback);
  201. return this;
  202. }
  203. database = parsed.db;
  204. host = parsed.hosts[0].host || parsed.hosts[0].ipc;
  205. port = parsed.hosts[0].port || 27017;
  206. }
  207. this.options = this.parseOptions(options, parsed && parsed.options);
  208. // make sure we can open
  209. if (STATES.disconnected !== this.readyState) {
  210. var err = new Error('Trying to open unclosed connection.');
  211. err.state = this.readyState;
  212. this.error(err, callback);
  213. return new Promise.ES6(function(resolve, reject) {
  214. reject(err);
  215. });
  216. }
  217. if (!host) {
  218. this.error(new Error('Missing hostname.'), callback);
  219. return new Promise.ES6(function(resolve, reject) {
  220. reject(err);
  221. });
  222. }
  223. if (!database) {
  224. this.error(new Error('Missing database name.'), callback);
  225. return new Promise.ES6(function(resolve, reject) {
  226. reject(err);
  227. });
  228. }
  229. // authentication
  230. if (this.optionsProvideAuthenticationData(options)) {
  231. this.user = options.user;
  232. this.pass = options.pass;
  233. } else if (parsed && parsed.auth) {
  234. this.user = parsed.auth.user;
  235. this.pass = parsed.auth.pass;
  236. // Check hostname for user/pass
  237. } else if (/@/.test(host) && /:/.test(host.split('@')[0])) {
  238. host = host.split('@');
  239. var auth = host.shift().split(':');
  240. host = host.pop();
  241. this.user = auth[0];
  242. this.pass = auth[1];
  243. } else {
  244. this.user = this.pass = undefined;
  245. }
  246. // global configuration options
  247. if (options && options.config) {
  248. this.config.autoIndex = options.config.autoIndex !== false;
  249. }
  250. this.name = database;
  251. this.host = host;
  252. this.port = port;
  253. var _this = this;
  254. var promise = new Promise.ES6(function(resolve, reject) {
  255. _this._open(true, function(error) {
  256. callback && callback(error);
  257. if (error) {
  258. reject(error);
  259. if (!callback && !promise.$hasHandler) {
  260. _this.emit('error', error);
  261. }
  262. return;
  263. }
  264. resolve();
  265. });
  266. });
  267. return promise;
  268. };
  269. /**
  270. * Helper for `dropDatabase()`.
  271. *
  272. * @param {Function} callback
  273. * @return {Promise}
  274. * @api public
  275. */
  276. Connection.prototype.dropDatabase = function(callback) {
  277. var Promise = PromiseProvider.get();
  278. var _this = this;
  279. var promise = new Promise.ES6(function(resolve, reject) {
  280. if (_this.readyState !== STATES.connected) {
  281. _this.on('open', function() {
  282. _this.db.dropDatabase(function(error) {
  283. if (error) {
  284. reject(error);
  285. } else {
  286. resolve();
  287. }
  288. });
  289. });
  290. } else {
  291. _this.db.dropDatabase(function(error) {
  292. if (error) {
  293. reject(error);
  294. } else {
  295. resolve();
  296. }
  297. });
  298. }
  299. });
  300. if (callback) {
  301. promise.then(function() { callback(); }, callback);
  302. }
  303. return promise;
  304. };
  305. /**
  306. * Opens the connection to a replica set.
  307. *
  308. * ####Example:
  309. *
  310. * var db = mongoose.createConnection();
  311. * db.openSet("mongodb://user:pwd@localhost:27020,localhost:27021,localhost:27012/mydb");
  312. *
  313. * The database name and/or auth need only be included in one URI.
  314. * The `options` is a hash which is passed to the internal driver connection object.
  315. *
  316. * Valid `options`
  317. *
  318. * db - passed to the connection db instance
  319. * server - passed to the connection server instance(s)
  320. * replset - passed to the connection ReplSetServer instance
  321. * user - username for authentication
  322. * pass - password for authentication
  323. * auth - options for authentication (see http://mongodb.github.com/node-mongodb-native/api-generated/db.html#authenticate)
  324. * mongos - Boolean - if true, enables High Availability support for mongos
  325. *
  326. * _Options passed take precedence over options included in connection strings._
  327. *
  328. * ####Notes:
  329. *
  330. * _If connecting to multiple mongos servers, set the `mongos` option to true._
  331. *
  332. * conn.open('mongodb://mongosA:27501,mongosB:27501', { mongos: true }, cb);
  333. *
  334. * Mongoose forces the db option `forceServerObjectId` false and cannot be overridden.
  335. * Mongoose defaults the server `auto_reconnect` options to true which can be overridden.
  336. * See the node-mongodb-native driver instance for options that it understands.
  337. *
  338. * _Options passed take precedence over options included in connection strings._
  339. *
  340. * @param {String} uris MongoDB connection string
  341. * @param {String} [database] database name if not included in `uris`
  342. * @param {Object} [options] passed to the internal driver
  343. * @param {Function} [callback]
  344. * @see node-mongodb-native https://github.com/mongodb/node-mongodb-native
  345. * @see http://mongodb.github.com/node-mongodb-native/api-generated/db.html#authenticate
  346. * @api public
  347. */
  348. Connection.prototype.openSet = function(uris, database, options, callback) {
  349. if (!rgxProtocol.test(uris)) {
  350. uris = 'mongodb://' + uris;
  351. }
  352. var Promise = PromiseProvider.get();
  353. switch (arguments.length) {
  354. case 3:
  355. switch (typeof database) {
  356. case 'string':
  357. this.name = database;
  358. break;
  359. case 'object':
  360. callback = options;
  361. options = database;
  362. database = null;
  363. break;
  364. }
  365. if (typeof options === 'function') {
  366. callback = options;
  367. options = {};
  368. }
  369. break;
  370. case 2:
  371. switch (typeof database) {
  372. case 'string':
  373. this.name = database;
  374. break;
  375. case 'function':
  376. callback = database;
  377. database = null;
  378. break;
  379. case 'object':
  380. options = database;
  381. database = null;
  382. break;
  383. }
  384. }
  385. if (typeof database === 'string') {
  386. this.name = database;
  387. }
  388. var parsed;
  389. try {
  390. parsed = muri(uris);
  391. } catch (err) {
  392. this.error(err, callback);
  393. return new Promise.ES6(function(resolve, reject) {
  394. reject(err);
  395. });
  396. }
  397. if (!this.name) {
  398. this.name = parsed.db;
  399. }
  400. this.hosts = parsed.hosts;
  401. this.options = this.parseOptions(options, parsed && parsed.options);
  402. this.replica = true;
  403. if (!this.name) {
  404. var err = new Error('No database name provided for replica set');
  405. this.error(err, callback);
  406. return new Promise.ES6(function(resolve, reject) {
  407. reject(err);
  408. });
  409. }
  410. // authentication
  411. if (this.optionsProvideAuthenticationData(options)) {
  412. this.user = options.user;
  413. this.pass = options.pass;
  414. } else if (parsed && parsed.auth) {
  415. this.user = parsed.auth.user;
  416. this.pass = parsed.auth.pass;
  417. } else {
  418. this.user = this.pass = undefined;
  419. }
  420. // global configuration options
  421. if (options && options.config) {
  422. this.config.autoIndex = options.config.autoIndex !== false;
  423. }
  424. var _this = this;
  425. var emitted = false;
  426. var promise = new Promise.ES6(function(resolve, reject) {
  427. _this._open(true, function(error) {
  428. callback && callback(error);
  429. if (error) {
  430. reject(error);
  431. if (!callback && !promise.$hasHandler && !emitted) {
  432. emitted = true;
  433. _this.emit('error', error);
  434. }
  435. return;
  436. }
  437. resolve();
  438. });
  439. });
  440. return promise;
  441. };
  442. /**
  443. * error
  444. *
  445. * Graceful error handling, passes error to callback
  446. * if available, else emits error on the connection.
  447. *
  448. * @param {Error} err
  449. * @param {Function} callback optional
  450. * @api private
  451. */
  452. Connection.prototype.error = function(err, callback) {
  453. if (callback) {
  454. return callback(err);
  455. }
  456. this.emit('error', err);
  457. };
  458. /**
  459. * Handles opening the connection with the appropriate method based on connection type.
  460. *
  461. * @param {Function} callback
  462. * @api private
  463. */
  464. Connection.prototype._open = function(emit, callback) {
  465. this.readyState = STATES.connecting;
  466. this._closeCalled = false;
  467. var _this = this;
  468. var method = this.replica
  469. ? 'doOpenSet'
  470. : 'doOpen';
  471. // open connection
  472. this[method](function(err) {
  473. if (err) {
  474. _this.readyState = STATES.disconnected;
  475. if (_this._hasOpened) {
  476. if (callback) {
  477. callback(err);
  478. }
  479. } else {
  480. _this.error(err, emit && callback);
  481. }
  482. return;
  483. }
  484. _this.onOpen(callback);
  485. });
  486. };
  487. /**
  488. * Called when the connection is opened
  489. *
  490. * @api private
  491. */
  492. Connection.prototype.onOpen = function(callback) {
  493. var _this = this;
  494. function open(err, isAuth) {
  495. if (err) {
  496. _this.readyState = isAuth ? STATES.unauthorized : STATES.disconnected;
  497. _this.error(err, callback);
  498. return;
  499. }
  500. _this.readyState = STATES.connected;
  501. // avoid having the collection subscribe to our event emitter
  502. // to prevent 0.3 warning
  503. for (var i in _this.collections) {
  504. if (utils.object.hasOwnProperty(_this.collections, i)) {
  505. _this.collections[i].onOpen();
  506. }
  507. }
  508. callback && callback();
  509. _this.emit('open');
  510. }
  511. // re-authenticate if we're not already connected #3871
  512. if (this._readyState !== STATES.connected && this.shouldAuthenticate()) {
  513. _this.db.authenticate(_this.user, _this.pass, _this.options.auth, function(err) {
  514. open(err, true);
  515. });
  516. } else {
  517. open();
  518. }
  519. };
  520. /**
  521. * Closes the connection
  522. *
  523. * @param {Function} [callback] optional
  524. * @return {Connection} self
  525. * @api public
  526. */
  527. Connection.prototype.close = function(callback) {
  528. var _this = this;
  529. var Promise = PromiseProvider.get();
  530. return new Promise.ES6(function(resolve, reject) {
  531. _this._close(function(error) {
  532. callback && callback(error);
  533. if (error) {
  534. reject(error);
  535. return;
  536. }
  537. resolve();
  538. });
  539. });
  540. };
  541. /**
  542. * Handles closing the connection
  543. *
  544. * @param {Function} callback
  545. * @api private
  546. */
  547. Connection.prototype._close = function(callback) {
  548. var _this = this;
  549. this._closeCalled = true;
  550. switch (this.readyState) {
  551. case 0: // disconnected
  552. callback && callback();
  553. break;
  554. case 1: // connected
  555. case 4: // unauthorized
  556. this.readyState = STATES.disconnecting;
  557. this.doClose(function(err) {
  558. if (err) {
  559. _this.error(err, callback);
  560. } else {
  561. _this.onClose();
  562. callback && callback();
  563. }
  564. });
  565. break;
  566. case 2: // connecting
  567. this.once('open', function() {
  568. _this.close(callback);
  569. });
  570. break;
  571. case 3: // disconnecting
  572. if (!callback) {
  573. break;
  574. }
  575. this.once('close', function() {
  576. callback();
  577. });
  578. break;
  579. }
  580. return this;
  581. };
  582. /**
  583. * Called when the connection closes
  584. *
  585. * @api private
  586. */
  587. Connection.prototype.onClose = function() {
  588. this.readyState = STATES.disconnected;
  589. // avoid having the collection subscribe to our event emitter
  590. // to prevent 0.3 warning
  591. for (var i in this.collections) {
  592. if (utils.object.hasOwnProperty(this.collections, i)) {
  593. this.collections[i].onClose();
  594. }
  595. }
  596. this.emit('close');
  597. };
  598. /**
  599. * Retrieves a collection, creating it if not cached.
  600. *
  601. * Not typically needed by applications. Just talk to your collection through your model.
  602. *
  603. * @param {String} name of the collection
  604. * @param {Object} [options] optional collection options
  605. * @return {Collection} collection instance
  606. * @api public
  607. */
  608. Connection.prototype.collection = function(name, options) {
  609. if (!(name in this.collections)) {
  610. this.collections[name] = new Collection(name, this, options);
  611. }
  612. return this.collections[name];
  613. };
  614. /**
  615. * Defines or retrieves a model.
  616. *
  617. * var mongoose = require('mongoose');
  618. * var db = mongoose.createConnection(..);
  619. * db.model('Venue', new Schema(..));
  620. * var Ticket = db.model('Ticket', new Schema(..));
  621. * var Venue = db.model('Venue');
  622. *
  623. * _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._
  624. *
  625. * ####Example:
  626. *
  627. * var schema = new Schema({ name: String }, { collection: 'actor' });
  628. *
  629. * // or
  630. *
  631. * schema.set('collection', 'actor');
  632. *
  633. * // or
  634. *
  635. * var collectionName = 'actor'
  636. * var M = conn.model('Actor', schema, collectionName)
  637. *
  638. * @param {String} name the model name
  639. * @param {Schema} [schema] a schema. necessary when defining a model
  640. * @param {String} [collection] name of mongodb collection (optional) if not given it will be induced from model name
  641. * @see Mongoose#model #index_Mongoose-model
  642. * @return {Model} The compiled model
  643. * @api public
  644. */
  645. Connection.prototype.model = function(name, schema, collection) {
  646. // collection name discovery
  647. if (typeof schema === 'string') {
  648. collection = schema;
  649. schema = false;
  650. }
  651. if (utils.isObject(schema) && !schema.instanceOfSchema) {
  652. schema = new Schema(schema);
  653. }
  654. if (schema && !schema.instanceOfSchema) {
  655. throw new Error('The 2nd parameter to `mongoose.model()` should be a ' +
  656. 'schema or a POJO');
  657. }
  658. if (this.models[name] && !collection) {
  659. // model exists but we are not subclassing with custom collection
  660. if (schema && schema.instanceOfSchema && schema !== this.models[name].schema) {
  661. throw new MongooseError.OverwriteModelError(name);
  662. }
  663. return this.models[name];
  664. }
  665. var opts = {cache: false, connection: this};
  666. var model;
  667. if (schema && schema.instanceOfSchema) {
  668. // compile a model
  669. model = this.base.model(name, schema, collection, opts);
  670. // only the first model with this name is cached to allow
  671. // for one-offs with custom collection names etc.
  672. if (!this.models[name]) {
  673. this.models[name] = model;
  674. }
  675. model.init();
  676. return model;
  677. }
  678. if (this.models[name] && collection) {
  679. // subclassing current model with alternate collection
  680. model = this.models[name];
  681. schema = model.prototype.schema;
  682. var sub = model.__subclass(this, schema, collection);
  683. // do not cache the sub model
  684. return sub;
  685. }
  686. // lookup model in mongoose module
  687. model = this.base.models[name];
  688. if (!model) {
  689. throw new MongooseError.MissingSchemaError(name);
  690. }
  691. if (this === model.prototype.db
  692. && (!collection || collection === model.collection.name)) {
  693. // model already uses this connection.
  694. // only the first model with this name is cached to allow
  695. // for one-offs with custom collection names etc.
  696. if (!this.models[name]) {
  697. this.models[name] = model;
  698. }
  699. return model;
  700. }
  701. this.models[name] = model.__subclass(this, schema, collection);
  702. return this.models[name];
  703. };
  704. /**
  705. * Returns an array of model names created on this connection.
  706. * @api public
  707. * @return {Array}
  708. */
  709. Connection.prototype.modelNames = function() {
  710. return Object.keys(this.models);
  711. };
  712. /**
  713. * @brief Returns if the connection requires authentication after it is opened. Generally if a
  714. * username and password are both provided than authentication is needed, but in some cases a
  715. * password is not required.
  716. * @api private
  717. * @return {Boolean} true if the connection should be authenticated after it is opened, otherwise false.
  718. */
  719. Connection.prototype.shouldAuthenticate = function() {
  720. return (this.user !== null && this.user !== void 0) &&
  721. ((this.pass !== null || this.pass !== void 0) || this.authMechanismDoesNotRequirePassword());
  722. };
  723. /**
  724. * @brief Returns a boolean value that specifies if the current authentication mechanism needs a
  725. * password to authenticate according to the auth objects passed into the open/openSet methods.
  726. * @api private
  727. * @return {Boolean} true if the authentication mechanism specified in the options object requires
  728. * a password, otherwise false.
  729. */
  730. Connection.prototype.authMechanismDoesNotRequirePassword = function() {
  731. if (this.options && this.options.auth) {
  732. return authMechanismsWhichDontRequirePassword.indexOf(this.options.auth.authMechanism) >= 0;
  733. }
  734. return true;
  735. };
  736. /**
  737. * @brief Returns a boolean value that specifies if the provided objects object provides enough
  738. * data to authenticate with. Generally this is true if the username and password are both specified
  739. * but in some authentication methods, a password is not required for authentication so only a username
  740. * is required.
  741. * @param {Object} [options] the options object passed into the open/openSet methods.
  742. * @api private
  743. * @return {Boolean} true if the provided options object provides enough data to authenticate with,
  744. * otherwise false.
  745. */
  746. Connection.prototype.optionsProvideAuthenticationData = function(options) {
  747. return (options) &&
  748. (options.user) &&
  749. ((options.pass) || this.authMechanismDoesNotRequirePassword());
  750. };
  751. /*!
  752. * Module exports.
  753. */
  754. Connection.STATES = STATES;
  755. module.exports = Connection;