indexes.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.ListIndexesOperation = exports.DropIndexOperation = exports.CreateIndexesOperation = void 0;
  4. const responses_1 = require("../cmap/wire_protocol/responses");
  5. const error_1 = require("../error");
  6. const utils_1 = require("../utils");
  7. const command_1 = require("./command");
  8. const operation_1 = require("./operation");
  9. const VALID_INDEX_OPTIONS = new Set([
  10. 'background',
  11. 'unique',
  12. 'name',
  13. 'partialFilterExpression',
  14. 'sparse',
  15. 'hidden',
  16. 'expireAfterSeconds',
  17. 'storageEngine',
  18. 'collation',
  19. 'version',
  20. // text indexes
  21. 'weights',
  22. 'default_language',
  23. 'language_override',
  24. 'textIndexVersion',
  25. // 2d-sphere indexes
  26. '2dsphereIndexVersion',
  27. // 2d indexes
  28. 'bits',
  29. 'min',
  30. 'max',
  31. // geoHaystack Indexes
  32. 'bucketSize',
  33. // wildcard indexes
  34. 'wildcardProjection'
  35. ]);
  36. function isIndexDirection(x) {
  37. return (typeof x === 'number' || x === '2d' || x === '2dsphere' || x === 'text' || x === 'geoHaystack');
  38. }
  39. function isSingleIndexTuple(t) {
  40. return Array.isArray(t) && t.length === 2 && isIndexDirection(t[1]);
  41. }
  42. /**
  43. * Converts an `IndexSpecification`, which can be specified in multiple formats, into a
  44. * valid `key` for the createIndexes command.
  45. */
  46. function constructIndexDescriptionMap(indexSpec) {
  47. const key = new Map();
  48. const indexSpecs = !Array.isArray(indexSpec) || isSingleIndexTuple(indexSpec) ? [indexSpec] : indexSpec;
  49. // Iterate through array and handle different types
  50. for (const spec of indexSpecs) {
  51. if (typeof spec === 'string') {
  52. key.set(spec, 1);
  53. }
  54. else if (Array.isArray(spec)) {
  55. key.set(spec[0], spec[1] ?? 1);
  56. }
  57. else if (spec instanceof Map) {
  58. for (const [property, value] of spec) {
  59. key.set(property, value);
  60. }
  61. }
  62. else if ((0, utils_1.isObject)(spec)) {
  63. for (const [property, value] of Object.entries(spec)) {
  64. key.set(property, value);
  65. }
  66. }
  67. }
  68. return key;
  69. }
  70. /**
  71. * Receives an index description and returns a modified index description which has had invalid options removed
  72. * from the description and has mapped the `version` option to the `v` option.
  73. */
  74. function resolveIndexDescription(description) {
  75. const validProvidedOptions = Object.entries(description).filter(([optionName]) => VALID_INDEX_OPTIONS.has(optionName));
  76. return Object.fromEntries(
  77. // we support the `version` option, but the `createIndexes` command expects it to be the `v`
  78. validProvidedOptions.map(([name, value]) => (name === 'version' ? ['v', value] : [name, value])));
  79. }
  80. /** @internal */
  81. class CreateIndexesOperation extends command_1.CommandOperation {
  82. constructor(parent, collectionName, indexes, options) {
  83. super(parent, options);
  84. this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
  85. this.options = options ?? {};
  86. // collation is set on each index, it should not be defined at the root
  87. this.options.collation = undefined;
  88. this.collectionName = collectionName;
  89. this.indexes = indexes.map((userIndex) => {
  90. // Ensure the key is a Map to preserve index key ordering
  91. const key = userIndex.key instanceof Map ? userIndex.key : new Map(Object.entries(userIndex.key));
  92. const name = userIndex.name ?? Array.from(key).flat().join('_');
  93. const validIndexOptions = resolveIndexDescription(userIndex);
  94. return {
  95. ...validIndexOptions,
  96. name,
  97. key
  98. };
  99. });
  100. this.ns = parent.s.namespace;
  101. }
  102. static fromIndexDescriptionArray(parent, collectionName, indexes, options) {
  103. return new CreateIndexesOperation(parent, collectionName, indexes, options);
  104. }
  105. static fromIndexSpecification(parent, collectionName, indexSpec, options = {}) {
  106. const key = constructIndexDescriptionMap(indexSpec);
  107. const description = { ...options, key };
  108. return new CreateIndexesOperation(parent, collectionName, [description], options);
  109. }
  110. get commandName() {
  111. return 'createIndexes';
  112. }
  113. buildCommandDocument(connection) {
  114. const options = this.options;
  115. const indexes = this.indexes;
  116. const serverWireVersion = (0, utils_1.maxWireVersion)(connection);
  117. const cmd = { createIndexes: this.collectionName, indexes };
  118. if (options.commitQuorum != null) {
  119. if (serverWireVersion < 9) {
  120. throw new error_1.MongoCompatibilityError('Option `commitQuorum` for `createIndexes` not supported on servers < 4.4');
  121. }
  122. cmd.commitQuorum = options.commitQuorum;
  123. }
  124. return cmd;
  125. }
  126. handleOk(_response) {
  127. const indexNames = this.indexes.map(index => index.name || '');
  128. return indexNames;
  129. }
  130. }
  131. exports.CreateIndexesOperation = CreateIndexesOperation;
  132. /** @internal */
  133. class DropIndexOperation extends command_1.CommandOperation {
  134. constructor(collection, indexName, options) {
  135. super(collection, options);
  136. this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
  137. this.options = options ?? {};
  138. this.collection = collection;
  139. this.indexName = indexName;
  140. this.ns = collection.fullNamespace;
  141. }
  142. get commandName() {
  143. return 'dropIndexes';
  144. }
  145. buildCommandDocument(_connection) {
  146. return { dropIndexes: this.collection.collectionName, index: this.indexName };
  147. }
  148. }
  149. exports.DropIndexOperation = DropIndexOperation;
  150. /** @internal */
  151. class ListIndexesOperation extends command_1.CommandOperation {
  152. constructor(collection, options) {
  153. super(collection, options);
  154. this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.CursorResponse;
  155. this.options = { ...options };
  156. delete this.options.writeConcern;
  157. this.collectionNamespace = collection.s.namespace;
  158. }
  159. get commandName() {
  160. return 'listIndexes';
  161. }
  162. buildCommandDocument(connection) {
  163. const serverWireVersion = (0, utils_1.maxWireVersion)(connection);
  164. const cursor = this.options.batchSize ? { batchSize: this.options.batchSize } : {};
  165. const command = { listIndexes: this.collectionNamespace.collection, cursor };
  166. // we check for undefined specifically here to allow falsy values
  167. // eslint-disable-next-line no-restricted-syntax
  168. if (serverWireVersion >= 9 && this.options.comment !== undefined) {
  169. command.comment = this.options.comment;
  170. }
  171. return command;
  172. }
  173. handleOk(response) {
  174. return response;
  175. }
  176. }
  177. exports.ListIndexesOperation = ListIndexesOperation;
  178. (0, operation_1.defineAspects)(ListIndexesOperation, [
  179. operation_1.Aspect.READ_OPERATION,
  180. operation_1.Aspect.RETRYABLE,
  181. operation_1.Aspect.CURSOR_CREATING,
  182. operation_1.Aspect.SUPPORTS_RAW_DATA
  183. ]);
  184. (0, operation_1.defineAspects)(CreateIndexesOperation, [operation_1.Aspect.WRITE_OPERATION, operation_1.Aspect.SUPPORTS_RAW_DATA]);
  185. (0, operation_1.defineAspects)(DropIndexOperation, [operation_1.Aspect.WRITE_OPERATION, operation_1.Aspect.SUPPORTS_RAW_DATA]);
  186. //# sourceMappingURL=indexes.js.map