mongodb 4.0.0 → 4.1.2

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 (246) hide show
  1. package/README.md +62 -30
  2. package/lib/bson.js +1 -0
  3. package/lib/bson.js.map +1 -1
  4. package/lib/bulk/common.js +53 -30
  5. package/lib/bulk/common.js.map +1 -1
  6. package/lib/bulk/ordered.js +3 -2
  7. package/lib/bulk/ordered.js.map +1 -1
  8. package/lib/bulk/unordered.js +3 -2
  9. package/lib/bulk/unordered.js.map +1 -1
  10. package/lib/change_stream.js +23 -13
  11. package/lib/change_stream.js.map +1 -1
  12. package/lib/cmap/auth/auth_provider.js +2 -1
  13. package/lib/cmap/auth/auth_provider.js.map +1 -1
  14. package/lib/cmap/auth/gssapi.js +5 -4
  15. package/lib/cmap/auth/gssapi.js.map +1 -1
  16. package/lib/cmap/auth/mongo_credentials.js +9 -5
  17. package/lib/cmap/auth/mongo_credentials.js.map +1 -1
  18. package/lib/cmap/auth/mongocr.js +2 -2
  19. package/lib/cmap/auth/mongocr.js.map +1 -1
  20. package/lib/cmap/auth/mongodb_aws.js +32 -32
  21. package/lib/cmap/auth/mongodb_aws.js.map +1 -1
  22. package/lib/cmap/auth/plain.js +1 -1
  23. package/lib/cmap/auth/plain.js.map +1 -1
  24. package/lib/cmap/auth/scram.js +15 -12
  25. package/lib/cmap/auth/scram.js.map +1 -1
  26. package/lib/cmap/auth/x509.js +2 -2
  27. package/lib/cmap/auth/x509.js.map +1 -1
  28. package/lib/cmap/command_monitoring_events.js +26 -10
  29. package/lib/cmap/command_monitoring_events.js.map +1 -1
  30. package/lib/cmap/commands.js +9 -5
  31. package/lib/cmap/commands.js.map +1 -1
  32. package/lib/cmap/connect.js +23 -9
  33. package/lib/cmap/connect.js.map +1 -1
  34. package/lib/cmap/connection.js +43 -46
  35. package/lib/cmap/connection.js.map +1 -1
  36. package/lib/cmap/connection_pool.js +113 -15
  37. package/lib/cmap/connection_pool.js.map +1 -1
  38. package/lib/cmap/connection_pool_events.js +3 -1
  39. package/lib/cmap/connection_pool_events.js.map +1 -1
  40. package/lib/cmap/errors.js +3 -3
  41. package/lib/cmap/errors.js.map +1 -1
  42. package/lib/cmap/message_stream.js +1 -1
  43. package/lib/cmap/message_stream.js.map +1 -1
  44. package/lib/cmap/metrics.js +62 -0
  45. package/lib/cmap/metrics.js.map +1 -0
  46. package/lib/cmap/stream_description.js +3 -1
  47. package/lib/cmap/stream_description.js.map +1 -1
  48. package/lib/cmap/wire_protocol/compression.js +22 -9
  49. package/lib/cmap/wire_protocol/compression.js.map +1 -1
  50. package/lib/cmap/wire_protocol/shared.js +1 -1
  51. package/lib/cmap/wire_protocol/shared.js.map +1 -1
  52. package/lib/collection.js +23 -18
  53. package/lib/collection.js.map +1 -1
  54. package/lib/connection_string.js +76 -30
  55. package/lib/connection_string.js.map +1 -1
  56. package/lib/cursor/abstract_cursor.js +75 -68
  57. package/lib/cursor/abstract_cursor.js.map +1 -1
  58. package/lib/cursor/aggregation_cursor.js +47 -9
  59. package/lib/cursor/aggregation_cursor.js.map +1 -1
  60. package/lib/cursor/find_cursor.js +53 -13
  61. package/lib/cursor/find_cursor.js.map +1 -1
  62. package/lib/db.js +21 -14
  63. package/lib/db.js.map +1 -1
  64. package/lib/deps.js +16 -5
  65. package/lib/deps.js.map +1 -1
  66. package/lib/encrypter.js +5 -8
  67. package/lib/encrypter.js.map +1 -1
  68. package/lib/error.js +230 -34
  69. package/lib/error.js.map +1 -1
  70. package/lib/explain.js +2 -2
  71. package/lib/explain.js.map +1 -1
  72. package/lib/gridfs/download.js +22 -47
  73. package/lib/gridfs/download.js.map +1 -1
  74. package/lib/gridfs/index.js +4 -3
  75. package/lib/gridfs/index.js.map +1 -1
  76. package/lib/gridfs/upload.js +13 -21
  77. package/lib/gridfs/upload.js.map +1 -1
  78. package/lib/index.js +27 -2
  79. package/lib/index.js.map +1 -1
  80. package/lib/logger.js +3 -2
  81. package/lib/logger.js.map +1 -1
  82. package/lib/mongo_client.js +5 -8
  83. package/lib/mongo_client.js.map +1 -1
  84. package/lib/mongo_types.js.map +1 -1
  85. package/lib/operations/add_user.js +2 -3
  86. package/lib/operations/add_user.js.map +1 -1
  87. package/lib/operations/aggregate.js +12 -9
  88. package/lib/operations/aggregate.js.map +1 -1
  89. package/lib/operations/command.js +5 -7
  90. package/lib/operations/command.js.map +1 -1
  91. package/lib/operations/common_functions.js +1 -1
  92. package/lib/operations/common_functions.js.map +1 -1
  93. package/lib/operations/connect.js +3 -2
  94. package/lib/operations/connect.js.map +1 -1
  95. package/lib/operations/count.js +1 -1
  96. package/lib/operations/count.js.map +1 -1
  97. package/lib/operations/count_documents.js +1 -1
  98. package/lib/operations/count_documents.js.map +1 -1
  99. package/lib/operations/delete.js +5 -5
  100. package/lib/operations/delete.js.map +1 -1
  101. package/lib/operations/distinct.js +2 -2
  102. package/lib/operations/distinct.js.map +1 -1
  103. package/lib/operations/estimated_document_count.js +5 -1
  104. package/lib/operations/estimated_document_count.js.map +1 -1
  105. package/lib/operations/eval.js.map +1 -1
  106. package/lib/operations/execute_operation.js +31 -17
  107. package/lib/operations/execute_operation.js.map +1 -1
  108. package/lib/operations/find.js +13 -9
  109. package/lib/operations/find.js.map +1 -1
  110. package/lib/operations/find_and_modify.js +9 -9
  111. package/lib/operations/find_and_modify.js.map +1 -1
  112. package/lib/operations/indexes.js +8 -3
  113. package/lib/operations/indexes.js.map +1 -1
  114. package/lib/operations/insert.js +5 -3
  115. package/lib/operations/insert.js.map +1 -1
  116. package/lib/operations/is_capped.js +2 -1
  117. package/lib/operations/is_capped.js.map +1 -1
  118. package/lib/operations/list_collections.js +6 -3
  119. package/lib/operations/list_collections.js.map +1 -1
  120. package/lib/operations/map_reduce.js +1 -1
  121. package/lib/operations/map_reduce.js.map +1 -1
  122. package/lib/operations/operation.js +3 -1
  123. package/lib/operations/operation.js.map +1 -1
  124. package/lib/operations/options_operation.js +2 -1
  125. package/lib/operations/options_operation.js.map +1 -1
  126. package/lib/operations/profiling_level.js +4 -2
  127. package/lib/operations/profiling_level.js.map +1 -1
  128. package/lib/operations/set_profiling_level.js +4 -2
  129. package/lib/operations/set_profiling_level.js.map +1 -1
  130. package/lib/operations/update.js +12 -12
  131. package/lib/operations/update.js.map +1 -1
  132. package/lib/operations/validate_collection.js +6 -5
  133. package/lib/operations/validate_collection.js.map +1 -1
  134. package/lib/promise_provider.js +1 -1
  135. package/lib/promise_provider.js.map +1 -1
  136. package/lib/read_preference.js +8 -8
  137. package/lib/read_preference.js.map +1 -1
  138. package/lib/sdam/common.js +12 -10
  139. package/lib/sdam/common.js.map +1 -1
  140. package/lib/sdam/server.js +90 -25
  141. package/lib/sdam/server.js.map +1 -1
  142. package/lib/sdam/server_description.js +9 -4
  143. package/lib/sdam/server_description.js.map +1 -1
  144. package/lib/sdam/server_selection.js +10 -4
  145. package/lib/sdam/server_selection.js.map +1 -1
  146. package/lib/sdam/srv_polling.js +1 -1
  147. package/lib/sdam/srv_polling.js.map +1 -1
  148. package/lib/sdam/topology.js +42 -21
  149. package/lib/sdam/topology.js.map +1 -1
  150. package/lib/sdam/topology_description.js +7 -3
  151. package/lib/sdam/topology_description.js.map +1 -1
  152. package/lib/sessions.js +132 -31
  153. package/lib/sessions.js.map +1 -1
  154. package/lib/sort.js +3 -3
  155. package/lib/sort.js.map +1 -1
  156. package/lib/transactions.js +15 -7
  157. package/lib/transactions.js.map +1 -1
  158. package/lib/utils.js +60 -20
  159. package/lib/utils.js.map +1 -1
  160. package/mongodb.d.ts +523 -138
  161. package/mongodb.ts34.d.ts +480 -141
  162. package/package.json +44 -48
  163. package/src/bson.ts +1 -0
  164. package/src/bulk/common.ts +83 -43
  165. package/src/bulk/ordered.ts +4 -3
  166. package/src/bulk/unordered.ts +4 -3
  167. package/src/change_stream.ts +46 -29
  168. package/src/cmap/auth/auth_provider.ts +3 -2
  169. package/src/cmap/auth/gssapi.ts +15 -5
  170. package/src/cmap/auth/mongo_credentials.ts +22 -8
  171. package/src/cmap/auth/mongocr.ts +3 -3
  172. package/src/cmap/auth/mongodb_aws.ts +52 -39
  173. package/src/cmap/auth/plain.ts +2 -2
  174. package/src/cmap/auth/scram.ts +23 -13
  175. package/src/cmap/auth/x509.ts +3 -3
  176. package/src/cmap/command_monitoring_events.ts +36 -14
  177. package/src/cmap/commands.ts +12 -6
  178. package/src/cmap/connect.ts +42 -12
  179. package/src/cmap/connection.ts +54 -62
  180. package/src/cmap/connection_pool.ts +141 -20
  181. package/src/cmap/connection_pool_events.ts +8 -1
  182. package/src/cmap/errors.ts +3 -4
  183. package/src/cmap/message_stream.ts +2 -4
  184. package/src/cmap/metrics.ts +58 -0
  185. package/src/cmap/stream_description.ts +6 -1
  186. package/src/cmap/wire_protocol/compression.ts +26 -13
  187. package/src/cmap/wire_protocol/shared.ts +4 -2
  188. package/src/collection.ts +75 -70
  189. package/src/connection_string.ts +97 -34
  190. package/src/cursor/abstract_cursor.ts +141 -104
  191. package/src/cursor/aggregation_cursor.ts +34 -20
  192. package/src/cursor/find_cursor.ts +41 -21
  193. package/src/db.ts +19 -18
  194. package/src/deps.ts +110 -22
  195. package/src/encrypter.ts +6 -12
  196. package/src/error.ts +264 -48
  197. package/src/explain.ts +3 -3
  198. package/src/gridfs/download.ts +48 -53
  199. package/src/gridfs/index.ts +5 -4
  200. package/src/gridfs/upload.ts +32 -33
  201. package/src/index.ts +42 -4
  202. package/src/logger.ts +6 -3
  203. package/src/mongo_client.ts +20 -23
  204. package/src/mongo_types.ts +19 -20
  205. package/src/operations/add_user.ts +4 -5
  206. package/src/operations/aggregate.ts +18 -17
  207. package/src/operations/command.ts +7 -10
  208. package/src/operations/common_functions.ts +2 -3
  209. package/src/operations/connect.ts +4 -3
  210. package/src/operations/count.ts +2 -2
  211. package/src/operations/count_documents.ts +2 -2
  212. package/src/operations/delete.ts +8 -6
  213. package/src/operations/distinct.ts +5 -3
  214. package/src/operations/estimated_document_count.ts +5 -1
  215. package/src/operations/eval.ts +1 -1
  216. package/src/operations/execute_operation.ts +41 -20
  217. package/src/operations/find.ts +25 -16
  218. package/src/operations/find_and_modify.ts +12 -10
  219. package/src/operations/indexes.ts +39 -8
  220. package/src/operations/insert.ts +7 -4
  221. package/src/operations/is_capped.ts +3 -2
  222. package/src/operations/list_collections.ts +9 -6
  223. package/src/operations/map_reduce.ts +4 -2
  224. package/src/operations/operation.ts +7 -2
  225. package/src/operations/options_operation.ts +3 -2
  226. package/src/operations/profiling_level.ts +5 -3
  227. package/src/operations/set_profiling_level.ts +9 -3
  228. package/src/operations/update.ts +17 -13
  229. package/src/operations/validate_collection.ts +7 -6
  230. package/src/promise_provider.ts +2 -2
  231. package/src/read_preference.ts +11 -9
  232. package/src/sdam/common.ts +11 -9
  233. package/src/sdam/server.ts +168 -69
  234. package/src/sdam/server_description.ts +16 -4
  235. package/src/sdam/server_selection.ts +15 -7
  236. package/src/sdam/srv_polling.ts +2 -2
  237. package/src/sdam/topology.ts +67 -36
  238. package/src/sdam/topology_description.ts +11 -4
  239. package/src/sessions.ts +194 -37
  240. package/src/sort.ts +6 -4
  241. package/src/transactions.ts +18 -9
  242. package/src/utils.ts +73 -20
  243. package/HISTORY.md +0 -2993
  244. package/lib/operations/find_one.js +0 -34
  245. package/lib/operations/find_one.js.map +0 -1
  246. package/src/operations/find_one.ts +0 -43
@@ -1,7 +1,15 @@
1
1
  import { Callback, maybePromise, MongoDBNamespace, ns } from '../utils';
2
2
  import { Long, Document, BSONSerializeOptions, pluckBSONSerializeOptions } from '../bson';
3
- import { ClientSession } from '../sessions';
4
- import { MongoDriverError } from '../error';
3
+ import { ClientSession, maybeClearPinnedConnection } from '../sessions';
4
+ import {
5
+ AnyError,
6
+ MongoRuntimeError,
7
+ MongoNetworkError,
8
+ MongoInvalidArgumentError,
9
+ MongoCursorExhaustedError,
10
+ MongoTailableCursorError,
11
+ MongoCursorInUseError
12
+ } from '../error';
5
13
  import { ReadPreference, ReadPreferenceLike } from '../read_preference';
6
14
  import type { Server } from '../sdam/server';
7
15
  import type { Topology } from '../sdam/topology';
@@ -43,9 +51,11 @@ export const CURSOR_FLAGS = [
43
51
  'partial'
44
52
  ] as const;
45
53
 
46
- /** @public */
54
+ /** @public
55
+ * @deprecated This interface is deprecated */
47
56
  export interface CursorCloseOptions {
48
57
  /** Bypass calling killCursors when closing the cursor. */
58
+ /** @deprecated the skipKillCursors option is deprecated */
49
59
  skipKillCursors?: boolean;
50
60
  }
51
61
 
@@ -150,7 +160,7 @@ export abstract class AbstractCursor<
150
160
  this[kOptions].batchSize = options.batchSize;
151
161
  }
152
162
 
153
- if (typeof options.comment !== 'undefined') {
163
+ if (options.comment != null) {
154
164
  this[kOptions].comment = options.comment;
155
165
  }
156
166
 
@@ -211,6 +221,10 @@ export abstract class AbstractCursor<
211
221
  return this[kKilled];
212
222
  }
213
223
 
224
+ get loadBalanced(): boolean {
225
+ return this[kTopology].loadBalanced;
226
+ }
227
+
214
228
  /** Returns current buffered documents length */
215
229
  bufferedCount(): number {
216
230
  return this[kDocuments].length;
@@ -221,9 +235,12 @@ export abstract class AbstractCursor<
221
235
  return this[kDocuments].splice(0, number ?? this[kDocuments].length);
222
236
  }
223
237
 
224
- [Symbol.asyncIterator](): AsyncIterator<TSchema | null> {
238
+ [Symbol.asyncIterator](): AsyncIterator<TSchema, void> {
225
239
  return {
226
- next: () => this.next<TSchema>().then(value => ({ value, done: value === null }))
240
+ next: () =>
241
+ this.next().then(value =>
242
+ value != null ? { value, done: false } : { value: undefined, done: true }
243
+ )
227
244
  };
228
245
  }
229
246
 
@@ -263,8 +280,7 @@ export abstract class AbstractCursor<
263
280
  return done(undefined, true);
264
281
  }
265
282
 
266
- next<any>(this, true, (err, doc) => {
267
- // FIXME(NODE):
283
+ next<TSchema>(this, true, (err, doc) => {
268
284
  if (err) return done(err);
269
285
 
270
286
  if (doc) {
@@ -279,12 +295,13 @@ export abstract class AbstractCursor<
279
295
  }
280
296
 
281
297
  /** Get the next available document from the cursor, returns null if no more documents are available. */
282
- next<T = TSchema>(): Promise<T | null>;
283
- next<T = TSchema>(callback: Callback<T | null>): void;
284
- next<T = TSchema>(callback?: Callback<T | null>): Promise<T | null> | void {
298
+ next(): Promise<TSchema | null>;
299
+ next(callback: Callback<TSchema | null>): void;
300
+ next(callback?: Callback<TSchema | null>): Promise<TSchema | null> | void;
301
+ next(callback?: Callback<TSchema | null>): Promise<TSchema | null> | void {
285
302
  return maybePromise(callback, done => {
286
303
  if (this[kId] === Long.ZERO) {
287
- return done(new MongoDriverError('Cursor is exhausted'));
304
+ return done(new MongoCursorExhaustedError());
288
305
  }
289
306
 
290
307
  next(this, true, done);
@@ -294,12 +311,12 @@ export abstract class AbstractCursor<
294
311
  /**
295
312
  * Try to get the next available document from the cursor or `null` if an empty batch is returned
296
313
  */
297
- tryNext<T = TSchema>(): Promise<T | null>;
298
- tryNext<T = TSchema>(callback: Callback<T | null>): void;
299
- tryNext<T = TSchema>(callback?: Callback<T | null>): Promise<T | null> | void {
314
+ tryNext(): Promise<TSchema | null>;
315
+ tryNext(callback: Callback<TSchema | null>): void;
316
+ tryNext(callback?: Callback<TSchema | null>): Promise<TSchema | null> | void {
300
317
  return maybePromise(callback, done => {
301
318
  if (this[kId] === Long.ZERO) {
302
- return done(new MongoDriverError('Cursor is exhausted'));
319
+ return done(new MongoCursorExhaustedError());
303
320
  }
304
321
 
305
322
  next(this, false, done);
@@ -312,19 +329,19 @@ export abstract class AbstractCursor<
312
329
  * @param iterator - The iteration callback.
313
330
  * @param callback - The end callback.
314
331
  */
315
- forEach<T = TSchema>(iterator: (doc: T) => boolean | void): Promise<void>;
316
- forEach<T = TSchema>(iterator: (doc: T) => boolean | void, callback: Callback<void>): void;
317
- forEach<T = TSchema>(
318
- iterator: (doc: T) => boolean | void,
332
+ forEach(iterator: (doc: TSchema) => boolean | void): Promise<void>;
333
+ forEach(iterator: (doc: TSchema) => boolean | void, callback: Callback<void>): void;
334
+ forEach(
335
+ iterator: (doc: TSchema) => boolean | void,
319
336
  callback?: Callback<void>
320
337
  ): Promise<void> | void {
321
338
  if (typeof iterator !== 'function') {
322
- throw new MongoDriverError('Missing required parameter `iterator`');
339
+ throw new MongoInvalidArgumentError('Argument "iterator" must be a function');
323
340
  }
324
341
  return maybePromise(callback, done => {
325
342
  const transform = this[kTransform];
326
343
  const fetchDocs = () => {
327
- next<T>(this, true, (err, doc) => {
344
+ next<TSchema>(this, true, (err, doc) => {
328
345
  if (err || doc == null) return done(err);
329
346
  let result;
330
347
  // NOTE: no need to transform because `next` will do this automatically
@@ -341,7 +358,7 @@ export abstract class AbstractCursor<
341
358
  for (let i = 0; i < internalDocs.length; ++i) {
342
359
  try {
343
360
  result = iterator(
344
- (transform ? transform(internalDocs[i]) : internalDocs[i]) as T // TODO(NODE-3283): Improve transform typing
361
+ (transform ? transform(internalDocs[i]) : internalDocs[i]) as TSchema // TODO(NODE-3283): Improve transform typing
345
362
  );
346
363
  } catch (error) {
347
364
  return done(error);
@@ -359,7 +376,13 @@ export abstract class AbstractCursor<
359
376
 
360
377
  close(): void;
361
378
  close(callback: Callback): void;
379
+ /**
380
+ * @deprecated options argument is deprecated
381
+ */
362
382
  close(options: CursorCloseOptions): Promise<void>;
383
+ /**
384
+ * @deprecated options argument is deprecated
385
+ */
363
386
  close(options: CursorCloseOptions, callback: Callback): void;
364
387
  close(options?: CursorCloseOptions | Callback, callback?: Callback): Promise<void> | void {
365
388
  if (typeof options === 'function') (callback = options), (options = {});
@@ -368,49 +391,7 @@ export abstract class AbstractCursor<
368
391
  const needsToEmitClosed = !this[kClosed];
369
392
  this[kClosed] = true;
370
393
 
371
- return maybePromise(callback, done => {
372
- const cursorId = this[kId];
373
- const cursorNs = this[kNamespace];
374
- const server = this[kServer];
375
- const session = this[kSession];
376
-
377
- if (cursorId == null || server == null || cursorId.isZero() || cursorNs == null) {
378
- if (needsToEmitClosed) {
379
- this[kId] = Long.ZERO;
380
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
381
- // @ts-expect-error
382
- this.emit(AbstractCursor.CLOSE);
383
- }
384
-
385
- if (session && session.owner === this) {
386
- return session.endSession(done);
387
- }
388
-
389
- return done();
390
- }
391
-
392
- this[kKilled] = true;
393
- server.killCursors(
394
- cursorNs,
395
- [cursorId],
396
- { ...pluckBSONSerializeOptions(this[kOptions]), session },
397
- () => {
398
- if (session && session.owner === this) {
399
- return session.endSession(() => {
400
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
401
- // @ts-expect-error
402
- this.emit(AbstractCursor.CLOSE);
403
- done();
404
- });
405
- }
406
-
407
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
408
- // @ts-expect-error
409
- this.emit(AbstractCursor.CLOSE);
410
- done();
411
- }
412
- );
413
- });
394
+ return maybePromise(callback, done => cleanupCursor(this, { needsToEmitClosed }, done));
414
395
  }
415
396
 
416
397
  /**
@@ -421,15 +402,15 @@ export abstract class AbstractCursor<
421
402
  *
422
403
  * @param callback - The result callback.
423
404
  */
424
- toArray<T = TSchema>(): Promise<T[]>;
425
- toArray<T = TSchema>(callback: Callback<T[]>): void;
426
- toArray<T = TSchema>(callback?: Callback<T[]>): Promise<T[]> | void {
405
+ toArray(): Promise<TSchema[]>;
406
+ toArray(callback: Callback<TSchema[]>): void;
407
+ toArray(callback?: Callback<TSchema[]>): Promise<TSchema[]> | void {
427
408
  return maybePromise(callback, done => {
428
- const docs: T[] = [];
409
+ const docs: TSchema[] = [];
429
410
  const transform = this[kTransform];
430
411
  const fetchDocs = () => {
431
412
  // NOTE: if we add a `nextBatch` then we should use it here
432
- next<T>(this, true, (err, doc) => {
413
+ next<TSchema>(this, true, (err, doc) => {
433
414
  if (err) return done(err);
434
415
  if (doc == null) return done(undefined, docs);
435
416
 
@@ -437,9 +418,11 @@ export abstract class AbstractCursor<
437
418
  docs.push(doc);
438
419
 
439
420
  // these do need to be transformed since they are copying the rest of the batch
440
- const internalDocs = (transform
441
- ? this[kDocuments].splice(0, this[kDocuments].length).map(transform)
442
- : this[kDocuments].splice(0, this[kDocuments].length)) as T[]; // TODO(NODE-3283): Improve transform typing
421
+ const internalDocs = (
422
+ transform
423
+ ? this[kDocuments].splice(0, this[kDocuments].length).map(transform)
424
+ : this[kDocuments].splice(0, this[kDocuments].length)
425
+ ) as TSchema[]; // TODO(NODE-3283): Improve transform typing
443
426
 
444
427
  if (internalDocs) {
445
428
  docs.push(...internalDocs);
@@ -462,11 +445,11 @@ export abstract class AbstractCursor<
462
445
  addCursorFlag(flag: CursorFlag, value: boolean): this {
463
446
  assertUninitialized(this);
464
447
  if (!CURSOR_FLAGS.includes(flag)) {
465
- throw new MongoDriverError(`flag ${flag} is not one of ${CURSOR_FLAGS}`);
448
+ throw new MongoInvalidArgumentError(`Flag ${flag} is not one of ${CURSOR_FLAGS}`);
466
449
  }
467
450
 
468
451
  if (typeof value !== 'boolean') {
469
- throw new MongoDriverError(`flag ${flag} must be a boolean value`);
452
+ throw new MongoInvalidArgumentError(`Flag ${flag} must be a boolean value`);
470
453
  }
471
454
 
472
455
  this[kOptions][flag] = value;
@@ -477,11 +460,12 @@ export abstract class AbstractCursor<
477
460
  * Map all documents using the provided function
478
461
  * If there is a transform set on the cursor, that will be called first and the result passed to
479
462
  * this function's transform.
480
- * @remarks
481
463
  *
482
- * **NOTE:** adding a transform changes the return type of the iteration of this cursor, it **does not** return
483
- * a new instance of a cursor. This means when calling map, you should always assign the result to a new
484
- * variable. Take note of the following example:
464
+ * @remarks
465
+ * **Note for Typescript Users:** adding a transform changes the return type of the iteration of this cursor,
466
+ * it **does not** return a new instance of a cursor. This means when calling map,
467
+ * you should always assign the result to a new variable in order to get a correctly typed cursor variable.
468
+ * Take note of the following example:
485
469
  *
486
470
  * @example
487
471
  * ```typescript
@@ -502,7 +486,7 @@ export abstract class AbstractCursor<
502
486
  this[kTransform] = transform;
503
487
  }
504
488
 
505
- return (this as unknown) as AbstractCursor<T>;
489
+ return this as unknown as AbstractCursor<T>;
506
490
  }
507
491
 
508
492
  /**
@@ -517,7 +501,7 @@ export abstract class AbstractCursor<
517
501
  } else if (typeof readPreference === 'string') {
518
502
  this[kOptions].readPreference = ReadPreference.fromString(readPreference);
519
503
  } else {
520
- throw new MongoDriverError('Invalid read preference: ' + readPreference);
504
+ throw new MongoInvalidArgumentError(`Invalid read preference: ${readPreference}`);
521
505
  }
522
506
 
523
507
  return this;
@@ -546,7 +530,7 @@ export abstract class AbstractCursor<
546
530
  maxTimeMS(value: number): this {
547
531
  assertUninitialized(this);
548
532
  if (typeof value !== 'number') {
549
- throw new MongoDriverError('maxTimeMS must be a number');
533
+ throw new MongoInvalidArgumentError('Argument for maxTimeMS must be a number');
550
534
  }
551
535
 
552
536
  this[kOptions].maxTimeMS = value;
@@ -561,11 +545,11 @@ export abstract class AbstractCursor<
561
545
  batchSize(value: number): this {
562
546
  assertUninitialized(this);
563
547
  if (this[kOptions].tailable) {
564
- throw new MongoDriverError('Tailable cursors do not support batchSize');
548
+ throw new MongoTailableCursorError('Tailable cursor does not support batchSize');
565
549
  }
566
550
 
567
551
  if (typeof value !== 'number') {
568
- throw new MongoDriverError('batchSize requires an integer');
552
+ throw new MongoInvalidArgumentError('Operation "batchSize" requires an integer');
569
553
  }
570
554
 
571
555
  this[kOptions].batchSize = value;
@@ -617,12 +601,12 @@ export abstract class AbstractCursor<
617
601
  const server = this[kServer];
618
602
 
619
603
  if (cursorId == null) {
620
- callback(new MongoDriverError('Unable to iterate cursor with no id'));
604
+ callback(new MongoRuntimeError('Unable to iterate cursor with no id'));
621
605
  return;
622
606
  }
623
607
 
624
608
  if (server == null) {
625
- callback(new MongoDriverError('Unable to iterate cursor without selected server'));
609
+ callback(new MongoRuntimeError('Unable to iterate cursor without selected server'));
626
610
  return;
627
611
  }
628
612
 
@@ -714,7 +698,7 @@ function next<T>(cursor: AbstractCursor, blocking: boolean, callback: Callback<T
714
698
  cursor[kInitialized] = true;
715
699
 
716
700
  if (err || cursorIsDead(cursor)) {
717
- return cleanupCursor(cursor, () => callback(err, nextDocument(cursor)));
701
+ return cleanupCursor(cursor, { error: err }, () => callback(err, nextDocument(cursor)));
718
702
  }
719
703
 
720
704
  next(cursor, blocking, callback);
@@ -724,7 +708,7 @@ function next<T>(cursor: AbstractCursor, blocking: boolean, callback: Callback<T
724
708
  }
725
709
 
726
710
  if (cursorIsDead(cursor)) {
727
- return cleanupCursor(cursor, () => callback(undefined, null));
711
+ return cleanupCursor(cursor, undefined, () => callback(undefined, null));
728
712
  }
729
713
 
730
714
  // otherwise need to call getMore
@@ -741,7 +725,7 @@ function next<T>(cursor: AbstractCursor, blocking: boolean, callback: Callback<T
741
725
  }
742
726
 
743
727
  if (err || cursorIsDead(cursor)) {
744
- return cleanupCursor(cursor, () => callback(err, nextDocument(cursor)));
728
+ return cleanupCursor(cursor, { error: err }, () => callback(err, nextDocument(cursor)));
745
729
  }
746
730
 
747
731
  if (cursor[kDocuments].length === 0 && blocking === false) {
@@ -757,24 +741,75 @@ function cursorIsDead(cursor: AbstractCursor): boolean {
757
741
  return !!cursorId && cursorId.isZero();
758
742
  }
759
743
 
760
- function cleanupCursor(cursor: AbstractCursor, callback: Callback): void {
761
- if (cursor[kDocuments].length === 0) {
762
- cursor[kClosed] = true;
763
- cursor.emit(AbstractCursor.CLOSE);
744
+ function cleanupCursor(
745
+ cursor: AbstractCursor,
746
+ options: { error?: AnyError | undefined; needsToEmitClosed?: boolean } | undefined,
747
+ callback: Callback
748
+ ): void {
749
+ const cursorId = cursor[kId];
750
+ const cursorNs = cursor[kNamespace];
751
+ const server = cursor[kServer];
752
+ const session = cursor[kSession];
753
+ const error = options?.error;
754
+ const needsToEmitClosed = options?.needsToEmitClosed ?? cursor[kDocuments].length === 0;
755
+
756
+ if (error) {
757
+ if (cursor.loadBalanced && error instanceof MongoNetworkError) {
758
+ return completeCleanup();
759
+ }
764
760
  }
765
761
 
766
- const session = cursor[kSession];
767
- if (session && session.owner === cursor) {
768
- session.endSession(callback);
769
- } else {
770
- callback();
762
+ if (cursorId == null || server == null || cursorId.isZero() || cursorNs == null) {
763
+ if (needsToEmitClosed) {
764
+ cursor[kClosed] = true;
765
+ cursor[kId] = Long.ZERO;
766
+ cursor.emit(AbstractCursor.CLOSE);
767
+ }
768
+
769
+ if (session) {
770
+ if (session.owner === cursor) {
771
+ return session.endSession({ error }, callback);
772
+ }
773
+
774
+ if (!session.inTransaction()) {
775
+ maybeClearPinnedConnection(session, { error });
776
+ }
777
+ }
778
+
779
+ return callback();
771
780
  }
781
+
782
+ function completeCleanup() {
783
+ if (session) {
784
+ if (session.owner === cursor) {
785
+ return session.endSession({ error }, () => {
786
+ cursor.emit(AbstractCursor.CLOSE);
787
+ callback();
788
+ });
789
+ }
790
+
791
+ if (!session.inTransaction()) {
792
+ maybeClearPinnedConnection(session, { error });
793
+ }
794
+ }
795
+
796
+ cursor.emit(AbstractCursor.CLOSE);
797
+ return callback();
798
+ }
799
+
800
+ cursor[kKilled] = true;
801
+ server.killCursors(
802
+ cursorNs,
803
+ [cursorId],
804
+ { ...pluckBSONSerializeOptions(cursor[kOptions]), session },
805
+ () => completeCleanup()
806
+ );
772
807
  }
773
808
 
774
809
  /** @internal */
775
810
  export function assertUninitialized(cursor: AbstractCursor): void {
776
811
  if (cursor[kInitialized]) {
777
- throw new MongoDriverError('Cursor is already initialized');
812
+ throw new MongoCursorInUseError();
778
813
  }
779
814
  }
780
815
 
@@ -812,7 +847,7 @@ function makeCursorStream<TSchema extends Document>(cursor: AbstractCursor<TSche
812
847
  function readNext() {
813
848
  needToClose = false;
814
849
  next(cursor, true, (err, result) => {
815
- needToClose = err ? !cursor.closed : result !== null;
850
+ needToClose = err ? !cursor.closed : result != null;
816
851
 
817
852
  if (err) {
818
853
  // NOTE: This is questionable, but we have a test backing the behavior. It seems the
@@ -826,15 +861,17 @@ function makeCursorStream<TSchema extends Document>(cursor: AbstractCursor<TSche
826
861
 
827
862
  // NOTE: This is also perhaps questionable. The rationale here is that these errors tend
828
863
  // to be "operation interrupted", where a cursor has been closed but there is an
829
- // active getMore in-flight.
830
- if (cursor.killed) {
864
+ // active getMore in-flight. This used to check if the cursor was killed but once
865
+ // that changed to happen in cleanup legitimate errors would not destroy the
866
+ // stream. There are change streams test specifically test these cases.
867
+ if (err.message.match(/interrupted/)) {
831
868
  return readable.push(null);
832
869
  }
833
870
 
834
871
  return readable.destroy(err);
835
872
  }
836
873
 
837
- if (result === null) {
874
+ if (result == null) {
838
875
  readable.push(null);
839
876
  } else if (readable.destroyed) {
840
877
  cursor.close();
@@ -7,16 +7,12 @@ import type { Sort } from '../sort';
7
7
  import type { Topology } from '../sdam/topology';
8
8
  import type { Callback, MongoDBNamespace } from '../utils';
9
9
  import type { ClientSession } from '../sessions';
10
- import type { OperationParent } from '../operations/command';
11
10
  import type { AbstractCursorOptions } from './abstract_cursor';
12
11
  import type { ExplainVerbosityLike } from '../explain';
13
- import type { Projection } from '../mongo_types';
14
12
 
15
13
  /** @public */
16
14
  export interface AggregationCursorOptions extends AbstractCursorOptions, AggregateOptions {}
17
15
 
18
- /** @internal */
19
- const kParent = Symbol('parent');
20
16
  /** @internal */
21
17
  const kPipeline = Symbol('pipeline');
22
18
  /** @internal */
@@ -30,8 +26,6 @@ const kOptions = Symbol('options');
30
26
  * @public
31
27
  */
32
28
  export class AggregationCursor<TSchema = Document> extends AbstractCursor<TSchema> {
33
- /** @internal */
34
- [kParent]: OperationParent; // TODO: NODE-2883
35
29
  /** @internal */
36
30
  [kPipeline]: Document[];
37
31
  /** @internal */
@@ -39,7 +33,6 @@ export class AggregationCursor<TSchema = Document> extends AbstractCursor<TSchem
39
33
 
40
34
  /** @internal */
41
35
  constructor(
42
- parent: OperationParent,
43
36
  topology: Topology,
44
37
  namespace: MongoDBNamespace,
45
38
  pipeline: Document[] = [],
@@ -47,7 +40,6 @@ export class AggregationCursor<TSchema = Document> extends AbstractCursor<TSchem
47
40
  ) {
48
41
  super(topology, namespace, options);
49
42
 
50
- this[kParent] = parent;
51
43
  this[kPipeline] = pipeline;
52
44
  this[kOptions] = options;
53
45
  }
@@ -59,7 +51,7 @@ export class AggregationCursor<TSchema = Document> extends AbstractCursor<TSchem
59
51
  clone(): AggregationCursor<TSchema> {
60
52
  const clonedOptions = mergeOptions({}, this[kOptions]);
61
53
  delete clonedOptions.session;
62
- return new AggregationCursor(this[kParent], this.topology, this.namespace, this[kPipeline], {
54
+ return new AggregationCursor(this.topology, this.namespace, this[kPipeline], {
63
55
  ...clonedOptions
64
56
  });
65
57
  }
@@ -70,7 +62,7 @@ export class AggregationCursor<TSchema = Document> extends AbstractCursor<TSchem
70
62
 
71
63
  /** @internal */
72
64
  _initialize(session: ClientSession | undefined, callback: Callback<ExecutionResult>): void {
73
- const aggregateOperation = new AggregateOperation(this[kParent], this[kPipeline], {
65
+ const aggregateOperation = new AggregateOperation(this.namespace, this[kPipeline], {
74
66
  ...this[kOptions],
75
67
  ...this.cursorOptions,
76
68
  session
@@ -93,11 +85,11 @@ export class AggregationCursor<TSchema = Document> extends AbstractCursor<TSchem
93
85
  callback?: Callback<Document>
94
86
  ): Promise<Document> | void {
95
87
  if (typeof verbosity === 'function') (callback = verbosity), (verbosity = true);
96
- if (verbosity === undefined) verbosity = true;
88
+ if (verbosity == null) verbosity = true;
97
89
 
98
90
  return executeOperation(
99
91
  this.topology,
100
- new AggregateOperation(this[kParent], this[kPipeline], {
92
+ new AggregateOperation(this.namespace, this[kPipeline], {
101
93
  ...this[kOptions], // NOTE: order matters here, we may need to refine this
102
94
  ...this.cursorOptions,
103
95
  explain: verbosity
@@ -128,8 +120,8 @@ export class AggregationCursor<TSchema = Document> extends AbstractCursor<TSchem
128
120
  return this;
129
121
  }
130
122
 
131
- /** Add a out stage to the aggregation pipeline */
132
- out($out: number): this {
123
+ /** Add an out stage to the aggregation pipeline */
124
+ out($out: { db: string; coll: string } | string): this {
133
125
  assertUninitialized(this);
134
126
  this[kPipeline].push({ $out });
135
127
  return this;
@@ -142,22 +134,44 @@ export class AggregationCursor<TSchema = Document> extends AbstractCursor<TSchem
142
134
  * In order to strictly type this function you must provide an interface
143
135
  * that represents the effect of your projection on the result documents.
144
136
  *
145
- * **NOTE:** adding a projection changes the return type of the iteration of this cursor,
137
+ * By default chaining a projection to your cursor changes the returned type to the generic {@link Document} type.
138
+ * You should specify a parameterized type to have assertions on your final results.
139
+ *
140
+ * @example
141
+ * ```typescript
142
+ * // Best way
143
+ * const docs: AggregationCursor<{ a: number }> = cursor.project<{ a: number }>({ _id: 0, a: true });
144
+ * // Flexible way
145
+ * const docs: AggregationCursor<Document> = cursor.project({ _id: 0, a: true });
146
+ * ```
147
+ *
148
+ * @remarks
149
+ * In order to strictly type this function you must provide an interface
150
+ * that represents the effect of your projection on the result documents.
151
+ *
152
+ * **Note for Typescript Users:** adding a transform changes the return type of the iteration of this cursor,
146
153
  * it **does not** return a new instance of a cursor. This means when calling project,
147
- * you should always assign the result to a new variable. Take note of the following example:
154
+ * you should always assign the result to a new variable in order to get a correctly typed cursor variable.
155
+ * Take note of the following example:
148
156
  *
149
157
  * @example
150
158
  * ```typescript
151
159
  * const cursor: AggregationCursor<{ a: number; b: string }> = coll.aggregate([]);
152
- * const projectCursor = cursor.project<{ a: number }>({ a: true });
160
+ * const projectCursor = cursor.project<{ a: number }>({ _id: 0, a: true });
153
161
  * const aPropOnlyArray: {a: number}[] = await projectCursor.toArray();
162
+ *
163
+ * // or always use chaining and save the final cursor
164
+ *
165
+ * const cursor = coll.aggregate().project<{ a: string }>({
166
+ * _id: 0,
167
+ * a: { $convert: { input: '$a', to: 'string' }
168
+ * }});
154
169
  * ```
155
170
  */
156
- project<T = TSchema>($project: Projection<T>): AggregationCursor<T>;
157
- project($project: Document): this {
171
+ project<T extends Document = Document>($project: Document): AggregationCursor<T> {
158
172
  assertUninitialized(this);
159
173
  this[kPipeline].push({ $project });
160
- return this;
174
+ return this as unknown as AggregationCursor<T>;
161
175
  }
162
176
 
163
177
  /** Add a lookup stage to the aggregation pipeline */