read_preference.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. 'use strict';
  2. /**
  3. * The **ReadPreference** class is a class that represents a MongoDB ReadPreference and is
  4. * used to construct connections.
  5. * @class
  6. * @param {string} mode A string describing the read preference mode (primary|primaryPreferred|secondary|secondaryPreferred|nearest)
  7. * @param {array} tags The tags object
  8. * @param {object} [options] Additional read preference options
  9. * @param {number} [options.maxStalenessSeconds] Max secondary read staleness in seconds, Minimum value is 90 seconds.
  10. * @return {ReadPreference}
  11. * @example
  12. * const ReplSet = require('mongodb-core').ReplSet,
  13. * ReadPreference = require('mongodb-core').ReadPreference,
  14. * assert = require('assert');
  15. *
  16. * const server = new ReplSet([{host: 'localhost', port: 30000}], {setName: 'rs'});
  17. * // Wait for the connection event
  18. * server.on('connect', function(server) {
  19. * const cursor = server.cursor(
  20. * 'db.test',
  21. * { find: 'db.test', query: {} },
  22. * { readPreference: new ReadPreference('secondary') }
  23. * );
  24. *
  25. * cursor.next(function(err, doc) {
  26. * server.destroy();
  27. * });
  28. * });
  29. *
  30. * // Start connecting
  31. * server.connect();
  32. * @see https://docs.mongodb.com/manual/core/read-preference/
  33. */
  34. const ReadPreference = function(mode, tags, options) {
  35. // TODO(major): tags MUST be an array of tagsets
  36. if (tags && !Array.isArray(tags)) {
  37. console.warn(
  38. 'ReadPreference tags must be an array, this will change in the next major version'
  39. );
  40. if (typeof tags.maxStalenessSeconds !== 'undefined') {
  41. // this is likely an options object
  42. options = tags;
  43. tags = undefined;
  44. } else {
  45. tags = [tags];
  46. }
  47. }
  48. this.mode = mode;
  49. this.tags = tags;
  50. options = options || {};
  51. if (options.maxStalenessSeconds != null) {
  52. if (options.maxStalenessSeconds <= 0) {
  53. throw new TypeError('maxStalenessSeconds must be a positive integer');
  54. }
  55. this.maxStalenessSeconds = options.maxStalenessSeconds;
  56. // NOTE: The minimum required wire version is 5 for this read preference. If the existing
  57. // topology has a lower value then a MongoError will be thrown during server selection.
  58. this.minWireVersion = 5;
  59. }
  60. if (this.mode === ReadPreference.PRIMARY || this.mode === true) {
  61. if (this.tags && Array.isArray(this.tags) && this.tags.length > 0) {
  62. throw new TypeError('Primary read preference cannot be combined with tags');
  63. }
  64. if (this.maxStalenessSeconds) {
  65. throw new TypeError('Primary read preference cannot be combined with maxStalenessSeconds');
  66. }
  67. }
  68. };
  69. // Support the deprecated `preference` property introduced in the porcelain layer
  70. Object.defineProperty(ReadPreference.prototype, 'preference', {
  71. enumerable: true,
  72. get: function() {
  73. return this.mode;
  74. }
  75. });
  76. /*
  77. * Read preference mode constants
  78. */
  79. ReadPreference.PRIMARY = 'primary';
  80. ReadPreference.PRIMARY_PREFERRED = 'primaryPreferred';
  81. ReadPreference.SECONDARY = 'secondary';
  82. ReadPreference.SECONDARY_PREFERRED = 'secondaryPreferred';
  83. ReadPreference.NEAREST = 'nearest';
  84. const VALID_MODES = [
  85. ReadPreference.PRIMARY,
  86. ReadPreference.PRIMARY_PREFERRED,
  87. ReadPreference.SECONDARY,
  88. ReadPreference.SECONDARY_PREFERRED,
  89. ReadPreference.NEAREST,
  90. true,
  91. false,
  92. null
  93. ];
  94. /**
  95. * Validate if a mode is legal
  96. *
  97. * @method
  98. * @param {string} mode The string representing the read preference mode.
  99. * @return {boolean} True if a mode is valid
  100. */
  101. ReadPreference.isValid = function(mode) {
  102. return VALID_MODES.indexOf(mode) !== -1;
  103. };
  104. /**
  105. * Validate if a mode is legal
  106. *
  107. * @method
  108. * @param {string} mode The string representing the read preference mode.
  109. * @return {boolean} True if a mode is valid
  110. */
  111. ReadPreference.prototype.isValid = function(mode) {
  112. return ReadPreference.isValid(typeof mode === 'string' ? mode : this.mode);
  113. };
  114. const needSlaveOk = ['primaryPreferred', 'secondary', 'secondaryPreferred', 'nearest'];
  115. /**
  116. * Indicates that this readPreference needs the "slaveOk" bit when sent over the wire
  117. * @method
  118. * @return {boolean}
  119. * @see https://docs.mongodb.com/manual/reference/mongodb-wire-protocol/#op-query
  120. */
  121. ReadPreference.prototype.slaveOk = function() {
  122. return needSlaveOk.indexOf(this.mode) !== -1;
  123. };
  124. /**
  125. * Are the two read preference equal
  126. * @method
  127. * @param {ReadPreference} readPreference The read preference with which to check equality
  128. * @return {boolean} True if the two ReadPreferences are equivalent
  129. */
  130. ReadPreference.prototype.equals = function(readPreference) {
  131. return readPreference.mode === this.mode;
  132. };
  133. /**
  134. * Return JSON representation
  135. * @method
  136. * @return {Object} A JSON representation of the ReadPreference
  137. */
  138. ReadPreference.prototype.toJSON = function() {
  139. const readPreference = { mode: this.mode };
  140. if (Array.isArray(this.tags)) readPreference.tags = this.tags;
  141. if (this.maxStalenessSeconds) readPreference.maxStalenessSeconds = this.maxStalenessSeconds;
  142. return readPreference;
  143. };
  144. /**
  145. * Primary read preference
  146. * @member
  147. * @type {ReadPreference}
  148. */
  149. ReadPreference.primary = new ReadPreference('primary');
  150. /**
  151. * Primary Preferred read preference
  152. * @member
  153. * @type {ReadPreference}
  154. */
  155. ReadPreference.primaryPreferred = new ReadPreference('primaryPreferred');
  156. /**
  157. * Secondary read preference
  158. * @member
  159. * @type {ReadPreference}
  160. */
  161. ReadPreference.secondary = new ReadPreference('secondary');
  162. /**
  163. * Secondary Preferred read preference
  164. * @member
  165. * @type {ReadPreference}
  166. */
  167. ReadPreference.secondaryPreferred = new ReadPreference('secondaryPreferred');
  168. /**
  169. * Nearest read preference
  170. * @member
  171. * @type {ReadPreference}
  172. */
  173. ReadPreference.nearest = new ReadPreference('nearest');
  174. module.exports = ReadPreference;