mongodb 6.18.0 → 6.19.0-dev.20250828.sha.41034f16

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 (158) hide show
  1. package/lib/admin.js +2 -1
  2. package/lib/admin.js.map +1 -1
  3. package/lib/beta.d.ts +59 -7
  4. package/lib/bulk/common.js +19 -32
  5. package/lib/bulk/common.js.map +1 -1
  6. package/lib/client-side-encryption/client_encryption.js +4 -1
  7. package/lib/client-side-encryption/client_encryption.js.map +1 -1
  8. package/lib/client-side-encryption/state_machine.js +4 -0
  9. package/lib/client-side-encryption/state_machine.js.map +1 -1
  10. package/lib/cmap/connection.js.map +1 -1
  11. package/lib/collection.js +62 -19
  12. package/lib/collection.js.map +1 -1
  13. package/lib/cursor/aggregation_cursor.js +2 -1
  14. package/lib/cursor/aggregation_cursor.js.map +1 -1
  15. package/lib/cursor/explainable_cursor.js +36 -0
  16. package/lib/cursor/explainable_cursor.js.map +1 -0
  17. package/lib/cursor/find_cursor.js +2 -1
  18. package/lib/cursor/find_cursor.js.map +1 -1
  19. package/lib/cursor/run_command_cursor.js +2 -4
  20. package/lib/cursor/run_command_cursor.js.map +1 -1
  21. package/lib/db.js +12 -5
  22. package/lib/db.js.map +1 -1
  23. package/lib/explain.js +1 -33
  24. package/lib/explain.js.map +1 -1
  25. package/lib/index.js +6 -6
  26. package/lib/index.js.map +1 -1
  27. package/lib/mongo_client.js +25 -2
  28. package/lib/mongo_client.js.map +1 -1
  29. package/lib/operations/aggregate.js +9 -7
  30. package/lib/operations/aggregate.js.map +1 -1
  31. package/lib/operations/client_bulk_write/client_bulk_write.js +8 -41
  32. package/lib/operations/client_bulk_write/client_bulk_write.js.map +1 -1
  33. package/lib/operations/command.js +16 -19
  34. package/lib/operations/command.js.map +1 -1
  35. package/lib/operations/count.js +7 -3
  36. package/lib/operations/count.js.map +1 -1
  37. package/lib/operations/create_collection.js +56 -49
  38. package/lib/operations/create_collection.js.map +1 -1
  39. package/lib/operations/delete.js +15 -12
  40. package/lib/operations/delete.js.map +1 -1
  41. package/lib/operations/distinct.js +18 -26
  42. package/lib/operations/distinct.js.map +1 -1
  43. package/lib/operations/drop.js +57 -39
  44. package/lib/operations/drop.js.map +1 -1
  45. package/lib/operations/estimated_document_count.js +7 -3
  46. package/lib/operations/estimated_document_count.js.map +1 -1
  47. package/lib/operations/execute_operation.js +14 -3
  48. package/lib/operations/execute_operation.js.map +1 -1
  49. package/lib/operations/find.js +21 -30
  50. package/lib/operations/find.js.map +1 -1
  51. package/lib/operations/find_and_modify.js +52 -41
  52. package/lib/operations/find_and_modify.js.map +1 -1
  53. package/lib/operations/get_more.js +10 -11
  54. package/lib/operations/get_more.js.map +1 -1
  55. package/lib/operations/indexes.js +21 -12
  56. package/lib/operations/indexes.js.map +1 -1
  57. package/lib/operations/insert.js +8 -47
  58. package/lib/operations/insert.js.map +1 -1
  59. package/lib/operations/kill_cursors.js +13 -15
  60. package/lib/operations/kill_cursors.js.map +1 -1
  61. package/lib/operations/list_collections.js +7 -6
  62. package/lib/operations/list_collections.js.map +1 -1
  63. package/lib/operations/list_databases.js +5 -3
  64. package/lib/operations/list_databases.js.map +1 -1
  65. package/lib/operations/operation.js +30 -1
  66. package/lib/operations/operation.js.map +1 -1
  67. package/lib/operations/profiling_level.js +14 -4
  68. package/lib/operations/profiling_level.js.map +1 -1
  69. package/lib/operations/remove_user.js +6 -2
  70. package/lib/operations/remove_user.js.map +1 -1
  71. package/lib/operations/rename.js +10 -8
  72. package/lib/operations/rename.js.map +1 -1
  73. package/lib/operations/run_command.js +28 -32
  74. package/lib/operations/run_command.js.map +1 -1
  75. package/lib/operations/search_indexes/create.js +11 -8
  76. package/lib/operations/search_indexes/create.js.map +1 -1
  77. package/lib/operations/search_indexes/drop.js +16 -9
  78. package/lib/operations/search_indexes/drop.js.map +1 -1
  79. package/lib/operations/search_indexes/update.js +11 -4
  80. package/lib/operations/search_indexes/update.js.map +1 -1
  81. package/lib/operations/set_profiling_level.js +8 -4
  82. package/lib/operations/set_profiling_level.js.map +1 -1
  83. package/lib/operations/stats.js +4 -2
  84. package/lib/operations/stats.js.map +1 -1
  85. package/lib/operations/update.js +22 -19
  86. package/lib/operations/update.js.map +1 -1
  87. package/lib/operations/validate_collection.js +17 -18
  88. package/lib/operations/validate_collection.js.map +1 -1
  89. package/lib/sdam/server.js +46 -35
  90. package/lib/sdam/server.js.map +1 -1
  91. package/lib/sdam/topology.js +4 -3
  92. package/lib/sdam/topology.js.map +1 -1
  93. package/lib/sessions.js +3 -3
  94. package/lib/sessions.js.map +1 -1
  95. package/lib/utils.js +8 -13
  96. package/lib/utils.js.map +1 -1
  97. package/mongodb.d.ts +59 -7
  98. package/package.json +19 -19
  99. package/src/admin.ts +3 -2
  100. package/src/bulk/common.ts +21 -41
  101. package/src/client-side-encryption/client_encryption.ts +52 -3
  102. package/src/client-side-encryption/state_machine.ts +5 -1
  103. package/src/cmap/connection.ts +0 -1
  104. package/src/collection.ts +94 -65
  105. package/src/cursor/aggregation_cursor.ts +1 -1
  106. package/src/cursor/explainable_cursor.ts +51 -0
  107. package/src/cursor/find_cursor.ts +1 -1
  108. package/src/cursor/run_command_cursor.ts +4 -5
  109. package/src/db.ts +16 -19
  110. package/src/explain.ts +0 -49
  111. package/src/index.ts +4 -4
  112. package/src/mongo_client.ts +24 -9
  113. package/src/operations/aggregate.ts +15 -20
  114. package/src/operations/client_bulk_write/client_bulk_write.ts +21 -65
  115. package/src/operations/command.ts +22 -45
  116. package/src/operations/count.ts +9 -9
  117. package/src/operations/create_collection.ts +83 -75
  118. package/src/operations/delete.ts +27 -35
  119. package/src/operations/distinct.ts +23 -40
  120. package/src/operations/drop.ts +76 -60
  121. package/src/operations/estimated_document_count.ts +8 -9
  122. package/src/operations/execute_operation.ts +21 -11
  123. package/src/operations/find.ts +40 -57
  124. package/src/operations/find_and_modify.ts +78 -54
  125. package/src/operations/get_more.ts +17 -19
  126. package/src/operations/indexes.ts +26 -30
  127. package/src/operations/insert.ts +11 -77
  128. package/src/operations/kill_cursors.ts +21 -22
  129. package/src/operations/list_collections.ts +13 -21
  130. package/src/operations/list_databases.ts +6 -15
  131. package/src/operations/operation.ts +47 -10
  132. package/src/operations/profiling_level.ts +17 -11
  133. package/src/operations/remove_user.ts +9 -9
  134. package/src/operations/rename.ts +11 -14
  135. package/src/operations/run_command.ts +40 -68
  136. package/src/operations/search_indexes/create.ts +15 -15
  137. package/src/operations/search_indexes/drop.ts +23 -14
  138. package/src/operations/search_indexes/update.ts +14 -9
  139. package/src/operations/set_profiling_level.ts +13 -11
  140. package/src/operations/stats.ts +5 -10
  141. package/src/operations/update.ts +49 -52
  142. package/src/operations/validate_collection.ts +19 -27
  143. package/src/sdam/server.ts +56 -59
  144. package/src/sdam/topology.ts +5 -4
  145. package/src/sessions.ts +5 -4
  146. package/src/utils.ts +10 -25
  147. package/lib/operations/bulk_write.js +0 -39
  148. package/lib/operations/bulk_write.js.map +0 -1
  149. package/lib/operations/collections.js +0 -33
  150. package/lib/operations/collections.js.map +0 -1
  151. package/lib/operations/is_capped.js +0 -28
  152. package/lib/operations/is_capped.js.map +0 -1
  153. package/lib/operations/options_operation.js +0 -28
  154. package/lib/operations/options_operation.js.map +0 -1
  155. package/src/operations/bulk_write.ts +0 -64
  156. package/src/operations/collections.ts +0 -47
  157. package/src/operations/is_capped.ts +0 -35
  158. package/src/operations/options_operation.ts +0 -35
@@ -749,7 +749,8 @@ export class ClientEncryption {
749
749
  expressionMode: boolean,
750
750
  options: ClientEncryptionEncryptOptions
751
751
  ): Promise<Binary> {
752
- const { algorithm, keyId, keyAltName, contentionFactor, queryType, rangeOptions } = options;
752
+ const { algorithm, keyId, keyAltName, contentionFactor, queryType, rangeOptions, textOptions } =
753
+ options;
753
754
  const contextOptions: ExplicitEncryptionContextOptions = {
754
755
  expressionMode,
755
756
  algorithm
@@ -782,6 +783,10 @@ export class ClientEncryption {
782
783
  contextOptions.rangeOptions = serialize(rangeOptions);
783
784
  }
784
785
 
786
+ if (typeof textOptions === 'object') {
787
+ contextOptions.textOptions = serialize(textOptions);
788
+ }
789
+
785
790
  const valueBuffer = serialize({ v: value });
786
791
  const stateMachine = new StateMachine({
787
792
  proxyOptions: this._proxyOptions,
@@ -812,7 +817,8 @@ export interface ClientEncryptionEncryptOptions {
812
817
  | 'AEAD_AES_256_CBC_HMAC_SHA_512-Random'
813
818
  | 'Indexed'
814
819
  | 'Unindexed'
815
- | 'Range';
820
+ | 'Range'
821
+ | 'TextPreview';
816
822
 
817
823
  /**
818
824
  * The id of the Binary dataKey to use for encryption
@@ -830,10 +836,53 @@ export interface ClientEncryptionEncryptOptions {
830
836
  /**
831
837
  * The query type.
832
838
  */
833
- queryType?: 'equality' | 'range';
839
+ queryType?: 'equality' | 'range' | 'prefixPreview' | 'suffixPreview' | 'substringPreview';
834
840
 
835
841
  /** The index options for a Queryable Encryption field supporting "range" queries.*/
836
842
  rangeOptions?: RangeOptions;
843
+
844
+ /**
845
+ * Options for a Queryable Encryption field supporting text queries. Only valid when `algorithm` is `TextPreview`.
846
+ *
847
+ * @experimental Public Technical Preview: `textPreview` is an experimental feature and may break at any time.
848
+ */
849
+ textOptions?: TextQueryOptions;
850
+ }
851
+
852
+ /**
853
+ * Options for a Queryable Encryption field supporting text queries.
854
+ *
855
+ * @public
856
+ * @experimental Public Technical Preview: `textPreview` is an experimental feature and may break at any time.
857
+ */
858
+ export interface TextQueryOptions {
859
+ /** Indicates that text indexes for this field are case sensitive */
860
+ caseSensitive: boolean;
861
+ /** Indicates that text indexes for this field are diacritic sensitive. */
862
+ diacriticSensitive: boolean;
863
+
864
+ prefix?: {
865
+ /** The maximum allowed query length. */
866
+ strMaxQueryLength: Int32 | number;
867
+ /** The minimum allowed query length. */
868
+ strMinQueryLength: Int32 | number;
869
+ };
870
+
871
+ suffix?: {
872
+ /** The maximum allowed query length. */
873
+ strMaxQueryLength: Int32 | number;
874
+ /** The minimum allowed query length. */
875
+ strMinQueryLength: Int32 | number;
876
+ };
877
+
878
+ substring?: {
879
+ /** The maximum allowed length to insert. */
880
+ strMaxLength: Int32 | number;
881
+ /** The maximum allowed query length. */
882
+ strMaxQueryLength: Int32 | number;
883
+ /** The minimum allowed query length. */
884
+ strMinQueryLength: Int32 | number;
885
+ };
837
886
  }
838
887
 
839
888
  /**
@@ -106,7 +106,7 @@ declare module 'mongodb-client-encryption' {
106
106
  */
107
107
  export type ClientEncryptionTlsOptions = Pick<
108
108
  MongoClientOptions,
109
- 'tlsCAFile' | 'tlsCertificateKeyFile' | 'tlsCertificateKeyFilePassword'
109
+ 'tlsCAFile' | 'tlsCertificateKeyFile' | 'tlsCertificateKeyFilePassword' | 'secureContext'
110
110
  >;
111
111
 
112
112
  /** @public */
@@ -521,6 +521,10 @@ export class StateMachine {
521
521
  tlsOptions: ClientEncryptionTlsOptions,
522
522
  options: tls.ConnectionOptions
523
523
  ): Promise<void> {
524
+ // If a secureContext is provided, ensure it is set.
525
+ if (tlsOptions.secureContext) {
526
+ options.secureContext = tlsOptions.secureContext;
527
+ }
524
528
  if (tlsOptions.tlsCertificateKeyFile) {
525
529
  const cert = await fs.readFile(tlsOptions.tlsCertificateKeyFile);
526
530
  options.cert = options.key = cert;
@@ -92,7 +92,6 @@ export interface CommandOptions extends BSONSerializeOptions {
92
92
  session?: ClientSession;
93
93
  documentsReturnedIn?: string;
94
94
  noResponse?: boolean;
95
- omitReadPreference?: boolean;
96
95
  omitMaxTimeMS?: boolean;
97
96
 
98
97
  // TODO(NODE-2802): Currently the CommandOptions take a property willRetryWrite which is a hint
package/src/collection.ts CHANGED
@@ -1,5 +1,10 @@
1
1
  import { type BSONSerializeOptions, type Document, resolveBSONOptions } from './bson';
2
- import type { AnyBulkWriteOperation, BulkWriteOptions, BulkWriteResult } from './bulk/common';
2
+ import type {
3
+ AnyBulkWriteOperation,
4
+ BulkOperationBase,
5
+ BulkWriteOptions,
6
+ BulkWriteResult
7
+ } from './bulk/common';
3
8
  import { OrderedBulkOperation } from './bulk/ordered';
4
9
  import { UnorderedBulkOperation } from './bulk/unordered';
5
10
  import { ChangeStream, type ChangeStreamDocument, type ChangeStreamOptions } from './change_stream';
@@ -11,7 +16,8 @@ import {
11
16
  type ListSearchIndexesOptions
12
17
  } from './cursor/list_search_indexes_cursor';
13
18
  import type { Db } from './db';
14
- import { MongoInvalidArgumentError, MongoOperationTimeoutError } from './error';
19
+ import { MongoAPIError, MongoInvalidArgumentError, MongoOperationTimeoutError } from './error';
20
+ import { type ExplainCommandOptions, type ExplainVerbosityLike } from './explain';
15
21
  import type { MongoClient, PkFactory } from './mongo_client';
16
22
  import type {
17
23
  Abortable,
@@ -24,7 +30,6 @@ import type {
24
30
  WithoutId
25
31
  } from './mongo_types';
26
32
  import type { AggregateOptions } from './operations/aggregate';
27
- import { BulkWriteOperation } from './operations/bulk_write';
28
33
  import { CountOperation, type CountOptions } from './operations/count';
29
34
  import {
30
35
  DeleteManyOperation,
@@ -33,13 +38,13 @@ import {
33
38
  type DeleteResult
34
39
  } from './operations/delete';
35
40
  import { DistinctOperation, type DistinctOptions } from './operations/distinct';
36
- import { DropCollectionOperation, type DropCollectionOptions } from './operations/drop';
41
+ import { type DropCollectionOptions } from './operations/drop';
37
42
  import {
38
43
  EstimatedDocumentCountOperation,
39
44
  type EstimatedDocumentCountOptions
40
45
  } from './operations/estimated_document_count';
41
- import { executeOperation } from './operations/execute_operation';
42
- import type { FindOptions } from './operations/find';
46
+ import { autoConnect, executeOperation } from './operations/execute_operation';
47
+ import { type FindOneOptions, type FindOptions } from './operations/find';
43
48
  import {
44
49
  FindOneAndDeleteOperation,
45
50
  type FindOneAndDeleteOptions,
@@ -61,15 +66,12 @@ import {
61
66
  type ListIndexesOptions
62
67
  } from './operations/indexes';
63
68
  import {
64
- InsertManyOperation,
65
69
  type InsertManyResult,
66
70
  InsertOneOperation,
67
71
  type InsertOneOptions,
68
72
  type InsertOneResult
69
73
  } from './operations/insert';
70
- import { IsCappedOperation } from './operations/is_capped';
71
74
  import type { Hint, OperationOptions } from './operations/operation';
72
- import { OptionsOperation } from './operations/options_operation';
73
75
  import { RenameOperation, type RenameOptions } from './operations/rename';
74
76
  import {
75
77
  CreateSearchIndexesOperation,
@@ -305,14 +307,31 @@ export class Collection<TSchema extends Document = Document> {
305
307
  docs: ReadonlyArray<OptionalUnlessRequiredId<TSchema>>,
306
308
  options?: BulkWriteOptions
307
309
  ): Promise<InsertManyResult<TSchema>> {
308
- return await executeOperation(
309
- this.client,
310
- new InsertManyOperation(
311
- this as TODO_NODE_3286,
312
- docs,
313
- resolveOptions(this, options ?? { ordered: true })
314
- ) as TODO_NODE_3286
315
- );
310
+ if (!Array.isArray(docs)) {
311
+ throw new MongoInvalidArgumentError('Argument "docs" must be an array of documents');
312
+ }
313
+ options = resolveOptions(this, options ?? {});
314
+
315
+ const acknowledged = WriteConcern.fromOptions(options)?.w !== 0;
316
+
317
+ try {
318
+ const res = await this.bulkWrite(
319
+ docs.map(doc => ({ insertOne: { document: doc } })),
320
+ options
321
+ );
322
+ return {
323
+ acknowledged,
324
+ insertedCount: res.insertedCount,
325
+ insertedIds: res.insertedIds
326
+ };
327
+ } catch (err) {
328
+ if (err && err.message === 'Operation must be an object with an operation key') {
329
+ throw new MongoInvalidArgumentError(
330
+ 'Collection.insertMany() cannot be called with an array that has null/undefined values'
331
+ );
332
+ }
333
+ throw err;
334
+ }
316
335
  }
317
336
 
318
337
  /**
@@ -342,14 +361,28 @@ export class Collection<TSchema extends Document = Document> {
342
361
  throw new MongoInvalidArgumentError('Argument "operations" must be an array of documents');
343
362
  }
344
363
 
345
- return await executeOperation(
346
- this.client,
347
- new BulkWriteOperation(
348
- this as TODO_NODE_3286,
349
- operations,
350
- resolveOptions(this, options ?? { ordered: true })
351
- )
352
- );
364
+ options = resolveOptions(this, options ?? {});
365
+
366
+ // TODO(NODE-7071): remove once the client doesn't need to be connected to construct
367
+ // bulk operations
368
+ const isConnected = this.client.topology != null;
369
+ if (!isConnected) {
370
+ await autoConnect(this.client);
371
+ }
372
+
373
+ // Create the bulk operation
374
+ const bulk: BulkOperationBase =
375
+ options.ordered === false
376
+ ? this.initializeUnorderedBulkOp(options)
377
+ : this.initializeOrderedBulkOp(options);
378
+
379
+ // for each op go through and add to the bulk
380
+ for (const operation of operations) {
381
+ bulk.raw(operation);
382
+ }
383
+
384
+ // Execute the bulk
385
+ return await bulk.execute({ ...options });
353
386
  }
354
387
 
355
388
  /**
@@ -370,12 +403,7 @@ export class Collection<TSchema extends Document = Document> {
370
403
  ): Promise<UpdateResult<TSchema>> {
371
404
  return await executeOperation(
372
405
  this.client,
373
- new UpdateOneOperation(
374
- this as TODO_NODE_3286,
375
- filter,
376
- update,
377
- resolveOptions(this, options)
378
- ) as TODO_NODE_3286
406
+ new UpdateOneOperation(this.s.namespace, filter, update, resolveOptions(this, options))
379
407
  );
380
408
  }
381
409
 
@@ -393,12 +421,7 @@ export class Collection<TSchema extends Document = Document> {
393
421
  ): Promise<UpdateResult<TSchema>> {
394
422
  return await executeOperation(
395
423
  this.client,
396
- new ReplaceOneOperation(
397
- this as TODO_NODE_3286,
398
- filter,
399
- replacement,
400
- resolveOptions(this, options)
401
- )
424
+ new ReplaceOneOperation(this.s.namespace, filter, replacement, resolveOptions(this, options))
402
425
  );
403
426
  }
404
427
 
@@ -420,12 +443,7 @@ export class Collection<TSchema extends Document = Document> {
420
443
  ): Promise<UpdateResult<TSchema>> {
421
444
  return await executeOperation(
422
445
  this.client,
423
- new UpdateManyOperation(
424
- this as TODO_NODE_3286,
425
- filter,
426
- update,
427
- resolveOptions(this, options)
428
- ) as TODO_NODE_3286
446
+ new UpdateManyOperation(this.s.namespace, filter, update, resolveOptions(this, options))
429
447
  );
430
448
  }
431
449
 
@@ -441,7 +459,7 @@ export class Collection<TSchema extends Document = Document> {
441
459
  ): Promise<DeleteResult> {
442
460
  return await executeOperation(
443
461
  this.client,
444
- new DeleteOneOperation(this as TODO_NODE_3286, filter, resolveOptions(this, options))
462
+ new DeleteOneOperation(this.s.namespace, filter, resolveOptions(this, options))
445
463
  );
446
464
  }
447
465
 
@@ -457,7 +475,7 @@ export class Collection<TSchema extends Document = Document> {
457
475
  ): Promise<DeleteResult> {
458
476
  return await executeOperation(
459
477
  this.client,
460
- new DeleteManyOperation(this as TODO_NODE_3286, filter, resolveOptions(this, options))
478
+ new DeleteManyOperation(this.s.namespace, filter, resolveOptions(this, options))
461
479
  );
462
480
  }
463
481
 
@@ -481,7 +499,7 @@ export class Collection<TSchema extends Document = Document> {
481
499
  ...options,
482
500
  readPreference: ReadPreference.PRIMARY
483
501
  })
484
- ) as TODO_NODE_3286
502
+ )
485
503
  );
486
504
  }
487
505
 
@@ -491,10 +509,7 @@ export class Collection<TSchema extends Document = Document> {
491
509
  * @param options - Optional settings for the command
492
510
  */
493
511
  async drop(options?: DropCollectionOptions): Promise<boolean> {
494
- return await executeOperation(
495
- this.client,
496
- new DropCollectionOperation(this.s.db, this.collectionName, options)
497
- );
512
+ return await this.s.db.dropCollection(this.collectionName, options);
498
513
  }
499
514
 
500
515
  /**
@@ -507,7 +522,7 @@ export class Collection<TSchema extends Document = Document> {
507
522
  async findOne(filter: Filter<TSchema>): Promise<WithId<TSchema> | null>;
508
523
  async findOne(
509
524
  filter: Filter<TSchema>,
510
- options: Omit<FindOptions, 'timeoutMode'> & Abortable
525
+ options: Omit<FindOneOptions, 'timeoutMode'> & Abortable
511
526
  ): Promise<WithId<TSchema> | null>;
512
527
 
513
528
  // allow an override of the schema.
@@ -515,17 +530,22 @@ export class Collection<TSchema extends Document = Document> {
515
530
  async findOne<T = TSchema>(filter: Filter<TSchema>): Promise<T | null>;
516
531
  async findOne<T = TSchema>(
517
532
  filter: Filter<TSchema>,
518
- options?: Omit<FindOptions, 'timeoutMode'> & Abortable
533
+ options?: Omit<FindOneOptions, 'timeoutMode'> & Abortable
519
534
  ): Promise<T | null>;
520
535
 
521
536
  async findOne(
522
537
  filter: Filter<TSchema> = {},
523
- options: FindOptions & Abortable = {}
538
+ options: Omit<FindOneOptions, 'timeoutMode'> & Abortable = {}
524
539
  ): Promise<WithId<TSchema> | null> {
525
- const cursor = this.find(filter, options).limit(-1).batchSize(1);
526
- const res = await cursor.next();
540
+ // Explicitly set the limit to 1 and singleBatch to true for all commands, per the spec.
541
+ // noCursorTimeout must be unset as well as batchSize.
542
+ // See: https://github.com/mongodb/specifications/blob/master/source/crud/crud.md#findone-api-details
543
+ const { batchSize: _batchSize, noCursorTimeout: _noCursorTimeout, ...opts } = options;
544
+ opts.singleBatch = true;
545
+ const cursor = this.find(filter, opts).limit(1);
546
+ const result = await cursor.next();
527
547
  await cursor.close();
528
- return res;
548
+ return result;
529
549
  }
530
550
 
531
551
  /**
@@ -547,7 +567,7 @@ export class Collection<TSchema extends Document = Document> {
547
567
  this.client,
548
568
  this.s.namespace,
549
569
  filter,
550
- resolveOptions(this as TODO_NODE_3286, options)
570
+ resolveOptions(this, options)
551
571
  );
552
572
  }
553
573
 
@@ -557,10 +577,16 @@ export class Collection<TSchema extends Document = Document> {
557
577
  * @param options - Optional settings for the command
558
578
  */
559
579
  async options(options?: OperationOptions): Promise<Document> {
560
- return await executeOperation(
561
- this.client,
562
- new OptionsOperation(this as TODO_NODE_3286, resolveOptions(this, options))
563
- );
580
+ options = resolveOptions(this, options);
581
+ const [collection] = await this.s.db
582
+ .listCollections({ name: this.collectionName }, { ...options, nameOnly: false })
583
+ .toArray();
584
+
585
+ if (collection == null || collection.options == null) {
586
+ throw new MongoAPIError(`collection ${this.namespace} not found`);
587
+ }
588
+
589
+ return collection.options;
564
590
  }
565
591
 
566
592
  /**
@@ -569,10 +595,8 @@ export class Collection<TSchema extends Document = Document> {
569
595
  * @param options - Optional settings for the command
570
596
  */
571
597
  async isCapped(options?: OperationOptions): Promise<boolean> {
572
- return await executeOperation(
573
- this.client,
574
- new IsCappedOperation(this as TODO_NODE_3286, resolveOptions(this, options))
575
- );
598
+ const { capped } = await this.options(options);
599
+ return Boolean(capped);
576
600
  }
577
601
 
578
602
  /**
@@ -840,6 +864,11 @@ export class Collection<TSchema extends Document = Document> {
840
864
  filter: Filter<TSchema>,
841
865
  options: DistinctOptions
842
866
  ): Promise<Array<Flatten<WithId<TSchema>[Key]>>>;
867
+ distinct<Key extends keyof WithId<TSchema>>(
868
+ key: Key,
869
+ filter: Filter<TSchema>,
870
+ options: DistinctOptions & { explain: ExplainVerbosityLike | ExplainCommandOptions }
871
+ ): Promise<Document>;
843
872
 
844
873
  // Embedded documents overload
845
874
  distinct(key: string): Promise<any[]>;
@@ -2,7 +2,6 @@ import type { Document } from '../bson';
2
2
  import { MongoAPIError } from '../error';
3
3
  import {
4
4
  Explain,
5
- ExplainableCursor,
6
5
  type ExplainCommandOptions,
7
6
  type ExplainVerbosityLike,
8
7
  validateExplainTimeoutOptions
@@ -19,6 +18,7 @@ import {
19
18
  CursorTimeoutMode,
20
19
  type InitialCursorResponse
21
20
  } from './abstract_cursor';
21
+ import { ExplainableCursor } from './explainable_cursor';
22
22
 
23
23
  /** @public */
24
24
  export interface AggregationCursorOptions extends AbstractCursorOptions, AggregateOptions {}
@@ -0,0 +1,51 @@
1
+ import { type Document } from '../bson';
2
+ import { type ExplainCommandOptions, type ExplainVerbosityLike } from '../explain';
3
+ import { AbstractCursor } from './abstract_cursor';
4
+
5
+ /**
6
+ * @public
7
+ *
8
+ * A base class for any cursors that have `explain()` methods.
9
+ */
10
+ export abstract class ExplainableCursor<TSchema> extends AbstractCursor<TSchema> {
11
+ /** Execute the explain for the cursor */
12
+ abstract explain(): Promise<Document>;
13
+ abstract explain(verbosity: ExplainVerbosityLike | ExplainCommandOptions): Promise<Document>;
14
+ abstract explain(options: { timeoutMS?: number }): Promise<Document>;
15
+ abstract explain(
16
+ verbosity: ExplainVerbosityLike | ExplainCommandOptions,
17
+ options: { timeoutMS?: number }
18
+ ): Promise<Document>;
19
+ abstract explain(
20
+ verbosity?: ExplainVerbosityLike | ExplainCommandOptions | { timeoutMS?: number },
21
+ options?: { timeoutMS?: number }
22
+ ): Promise<Document>;
23
+
24
+ protected resolveExplainTimeoutOptions(
25
+ verbosity?: ExplainVerbosityLike | ExplainCommandOptions | { timeoutMS?: number },
26
+ options?: { timeoutMS?: number }
27
+ ): { timeout?: { timeoutMS?: number }; explain?: ExplainVerbosityLike | ExplainCommandOptions } {
28
+ let explain: ExplainVerbosityLike | ExplainCommandOptions | undefined;
29
+ let timeout: { timeoutMS?: number } | undefined;
30
+
31
+ if (verbosity == null && options == null) {
32
+ explain = undefined;
33
+ timeout = undefined;
34
+ } else if (verbosity != null && options == null) {
35
+ explain =
36
+ typeof verbosity !== 'object'
37
+ ? verbosity
38
+ : 'verbosity' in verbosity
39
+ ? verbosity
40
+ : undefined;
41
+
42
+ timeout = typeof verbosity === 'object' && 'timeoutMS' in verbosity ? verbosity : undefined;
43
+ } else {
44
+ // @ts-expect-error TS isn't smart enough to determine that if both options are provided, the first is explain options
45
+ explain = verbosity;
46
+ timeout = options;
47
+ }
48
+
49
+ return { timeout, explain };
50
+ }
51
+ }
@@ -3,7 +3,6 @@ import { CursorResponse } from '../cmap/wire_protocol/responses';
3
3
  import { MongoAPIError, MongoInvalidArgumentError, MongoTailableCursorError } from '../error';
4
4
  import {
5
5
  Explain,
6
- ExplainableCursor,
7
6
  type ExplainCommandOptions,
8
7
  type ExplainVerbosityLike,
9
8
  validateExplainTimeoutOptions
@@ -19,6 +18,7 @@ import type { ClientSession } from '../sessions';
19
18
  import { formatSort, type Sort, type SortDirection } from '../sort';
20
19
  import { emitWarningOnce, mergeOptions, type MongoDBNamespace, squashError } from '../utils';
21
20
  import { type InitialCursorResponse } from './abstract_cursor';
21
+ import { ExplainableCursor } from './explainable_cursor';
22
22
 
23
23
  /** @public Flags allowed for cursor */
24
24
  export const FLAGS = [
@@ -1,10 +1,10 @@
1
1
  import type { BSONSerializeOptions, Document } from '../bson';
2
- import { CursorResponse } from '../cmap/wire_protocol/responses';
2
+ import { type CursorResponse } from '../cmap/wire_protocol/responses';
3
3
  import type { Db } from '../db';
4
4
  import { MongoAPIError, MongoRuntimeError } from '../error';
5
5
  import { executeOperation } from '../operations/execute_operation';
6
6
  import { GetMoreOperation } from '../operations/get_more';
7
- import { RunCommandOperation } from '../operations/run_command';
7
+ import { RunCursorCommandOperation } from '../operations/run_command';
8
8
  import type { ReadConcernLike } from '../read_concern';
9
9
  import type { ReadPreferenceLike } from '../read_preference';
10
10
  import type { ClientSession } from '../sessions';
@@ -143,11 +143,10 @@ export class RunCommandCursor extends AbstractCursor {
143
143
 
144
144
  /** @internal */
145
145
  protected async _initialize(session: ClientSession): Promise<InitialCursorResponse> {
146
- const operation = new RunCommandOperation<CursorResponse>(this.db, this.command, {
146
+ const operation = new RunCursorCommandOperation(this.db.s.namespace, this.command, {
147
147
  ...this.cursorOptions,
148
148
  session: session,
149
- readPreference: this.cursorOptions.readPreference,
150
- responseType: CursorResponse
149
+ readPreference: this.cursorOptions.readPreference
151
150
  });
152
151
 
153
152
  const response = await executeOperation(this.client, operation, this.timeoutContext);
package/src/db.ts CHANGED
@@ -10,14 +10,10 @@ import { MongoInvalidArgumentError } from './error';
10
10
  import type { MongoClient, PkFactory } from './mongo_client';
11
11
  import type { Abortable, TODO_NODE_3286 } from './mongo_types';
12
12
  import type { AggregateOptions } from './operations/aggregate';
13
- import { CollectionsOperation } from './operations/collections';
13
+ import { type CreateCollectionOptions, createCollections } from './operations/create_collection';
14
14
  import {
15
- CreateCollectionOperation,
16
- type CreateCollectionOptions
17
- } from './operations/create_collection';
18
- import {
19
- DropCollectionOperation,
20
15
  type DropCollectionOptions,
16
+ dropCollections,
21
17
  DropDatabaseOperation,
22
18
  type DropDatabaseOptions
23
19
  } from './operations/drop';
@@ -242,10 +238,8 @@ export class Db {
242
238
  name: string,
243
239
  options?: CreateCollectionOptions
244
240
  ): Promise<Collection<TSchema>> {
245
- return await executeOperation(
246
- this.client,
247
- new CreateCollectionOperation(this, name, resolveOptions(this, options)) as TODO_NODE_3286
248
- );
241
+ options = resolveOptions(this, options);
242
+ return await createCollections<TSchema>(this, name, options);
249
243
  }
250
244
 
251
245
  /**
@@ -278,7 +272,7 @@ export class Db {
278
272
  return await executeOperation(
279
273
  this.client,
280
274
  new RunCommandOperation(
281
- this,
275
+ this.s.namespace,
282
276
  command,
283
277
  resolveOptions(undefined, {
284
278
  ...resolveBSONOptions(options),
@@ -411,10 +405,8 @@ export class Db {
411
405
  * @param options - Optional settings for the command
412
406
  */
413
407
  async dropCollection(name: string, options?: DropCollectionOptions): Promise<boolean> {
414
- return await executeOperation(
415
- this.client,
416
- new DropCollectionOperation(this, name, resolveOptions(this, options))
417
- );
408
+ options = resolveOptions(this, options);
409
+ return await dropCollections(this, name, options);
418
410
  }
419
411
 
420
412
  /**
@@ -435,10 +427,15 @@ export class Db {
435
427
  * @param options - Optional settings for the command
436
428
  */
437
429
  async collections(options?: ListCollectionsOptions): Promise<Collection[]> {
438
- return await executeOperation(
439
- this.client,
440
- new CollectionsOperation(this, resolveOptions(this, options))
441
- );
430
+ options = resolveOptions(this, options);
431
+ const collections = await this.listCollections({}, { ...options, nameOnly: true }).toArray();
432
+
433
+ return collections
434
+ .filter(
435
+ // Filter collections removing any illegal ones
436
+ ({ name }) => !name.includes('$')
437
+ )
438
+ .map(({ name }) => new Collection(this, name, this.s.options));
442
439
  }
443
440
 
444
441
  /**
package/src/explain.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { type Document } from './bson';
2
- import { AbstractCursor } from './cursor/abstract_cursor';
3
2
  import { MongoAPIError } from './error';
4
3
 
5
4
  /** @public */
@@ -123,51 +122,3 @@ export function decorateWithExplain(
123
122
 
124
123
  return baseCommand;
125
124
  }
126
-
127
- /**
128
- * @public
129
- *
130
- * A base class for any cursors that have `explain()` methods.
131
- */
132
- export abstract class ExplainableCursor<TSchema> extends AbstractCursor<TSchema> {
133
- /** Execute the explain for the cursor */
134
- abstract explain(): Promise<Document>;
135
- abstract explain(verbosity: ExplainVerbosityLike | ExplainCommandOptions): Promise<Document>;
136
- abstract explain(options: { timeoutMS?: number }): Promise<Document>;
137
- abstract explain(
138
- verbosity: ExplainVerbosityLike | ExplainCommandOptions,
139
- options: { timeoutMS?: number }
140
- ): Promise<Document>;
141
- abstract explain(
142
- verbosity?: ExplainVerbosityLike | ExplainCommandOptions | { timeoutMS?: number },
143
- options?: { timeoutMS?: number }
144
- ): Promise<Document>;
145
-
146
- protected resolveExplainTimeoutOptions(
147
- verbosity?: ExplainVerbosityLike | ExplainCommandOptions | { timeoutMS?: number },
148
- options?: { timeoutMS?: number }
149
- ): { timeout?: { timeoutMS?: number }; explain?: ExplainVerbosityLike | ExplainCommandOptions } {
150
- let explain: ExplainVerbosityLike | ExplainCommandOptions | undefined;
151
- let timeout: { timeoutMS?: number } | undefined;
152
-
153
- if (verbosity == null && options == null) {
154
- explain = undefined;
155
- timeout = undefined;
156
- } else if (verbosity != null && options == null) {
157
- explain =
158
- typeof verbosity !== 'object'
159
- ? verbosity
160
- : 'verbosity' in verbosity
161
- ? verbosity
162
- : undefined;
163
-
164
- timeout = typeof verbosity === 'object' && 'timeoutMS' in verbosity ? verbosity : undefined;
165
- } else {
166
- // @ts-expect-error TS isn't smart enough to determine that if both options are provided, the first is explain options
167
- explain = verbosity;
168
- timeout = options;
169
- }
170
-
171
- return { timeout, explain };
172
- }
173
- }