mongodb 6.16.0 → 6.17.0

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 (95) hide show
  1. package/README.md +2 -0
  2. package/lib/beta.d.ts +132 -33
  3. package/lib/bulk/common.js +4 -4
  4. package/lib/bulk/common.js.map +1 -1
  5. package/lib/client-side-encryption/auto_encrypter.js +5 -2
  6. package/lib/client-side-encryption/auto_encrypter.js.map +1 -1
  7. package/lib/client-side-encryption/client_encryption.js.map +1 -1
  8. package/lib/client-side-encryption/state_machine.js +1 -1
  9. package/lib/client-side-encryption/state_machine.js.map +1 -1
  10. package/lib/cmap/auth/mongodb_oidc/automated_callback_workflow.js +6 -0
  11. package/lib/cmap/auth/mongodb_oidc/automated_callback_workflow.js.map +1 -1
  12. package/lib/cmap/auth/mongodb_oidc/azure_machine_workflow.js +21 -33
  13. package/lib/cmap/auth/mongodb_oidc/azure_machine_workflow.js.map +1 -1
  14. package/lib/cmap/auth/mongodb_oidc/gcp_machine_workflow.js +14 -21
  15. package/lib/cmap/auth/mongodb_oidc/gcp_machine_workflow.js.map +1 -1
  16. package/lib/cmap/auth/mongodb_oidc/k8s_machine_workflow.js +19 -26
  17. package/lib/cmap/auth/mongodb_oidc/k8s_machine_workflow.js.map +1 -1
  18. package/lib/cmap/auth/mongodb_oidc/token_machine_workflow.js +12 -24
  19. package/lib/cmap/auth/mongodb_oidc/token_machine_workflow.js.map +1 -1
  20. package/lib/cmap/auth/mongodb_oidc.js +5 -4
  21. package/lib/cmap/auth/mongodb_oidc.js.map +1 -1
  22. package/lib/cmap/connect.js +4 -3
  23. package/lib/cmap/connect.js.map +1 -1
  24. package/lib/cmap/connection.js +8 -3
  25. package/lib/cmap/connection.js.map +1 -1
  26. package/lib/cmap/connection_pool.js +6 -1
  27. package/lib/cmap/connection_pool.js.map +1 -1
  28. package/lib/cmap/wire_protocol/constants.js +2 -2
  29. package/lib/cmap/wire_protocol/responses.js.map +1 -1
  30. package/lib/collection.js.map +1 -1
  31. package/lib/connection_string.js +2 -0
  32. package/lib/connection_string.js.map +1 -1
  33. package/lib/constants.js +0 -1
  34. package/lib/constants.js.map +1 -1
  35. package/lib/encrypter.js +3 -7
  36. package/lib/encrypter.js.map +1 -1
  37. package/lib/error.js +28 -1
  38. package/lib/error.js.map +1 -1
  39. package/lib/index.js +4 -3
  40. package/lib/index.js.map +1 -1
  41. package/lib/mongo_client.js +66 -20
  42. package/lib/mongo_client.js.map +1 -1
  43. package/lib/operations/aggregate.js +0 -1
  44. package/lib/operations/aggregate.js.map +1 -1
  45. package/lib/operations/client_bulk_write/command_builder.js +20 -13
  46. package/lib/operations/client_bulk_write/command_builder.js.map +1 -1
  47. package/lib/operations/find_and_modify.js +1 -1
  48. package/lib/operations/find_and_modify.js.map +1 -1
  49. package/lib/operations/update.js +6 -2
  50. package/lib/operations/update.js.map +1 -1
  51. package/lib/sdam/server.js +4 -1
  52. package/lib/sdam/server.js.map +1 -1
  53. package/lib/sdam/topology.js +9 -4
  54. package/lib/sdam/topology.js.map +1 -1
  55. package/lib/sort.js +13 -6
  56. package/lib/sort.js.map +1 -1
  57. package/lib/utils.js +15 -1
  58. package/lib/utils.js.map +1 -1
  59. package/mongodb.d.ts +132 -33
  60. package/package.json +19 -19
  61. package/src/bulk/common.ts +11 -6
  62. package/src/client-side-encryption/auto_encrypter.ts +10 -2
  63. package/src/client-side-encryption/client_encryption.ts +5 -0
  64. package/src/client-side-encryption/state_machine.ts +1 -1
  65. package/src/cmap/auth/mongodb_oidc/automated_callback_workflow.ts +6 -0
  66. package/src/cmap/auth/mongodb_oidc/azure_machine_workflow.ts +23 -35
  67. package/src/cmap/auth/mongodb_oidc/gcp_machine_workflow.ts +16 -23
  68. package/src/cmap/auth/mongodb_oidc/k8s_machine_workflow.ts +17 -25
  69. package/src/cmap/auth/mongodb_oidc/token_machine_workflow.ts +11 -24
  70. package/src/cmap/auth/mongodb_oidc.ts +13 -8
  71. package/src/cmap/connect.ts +4 -3
  72. package/src/cmap/connection.ts +11 -4
  73. package/src/cmap/connection_pool.ts +8 -1
  74. package/src/cmap/wire_protocol/constants.ts +2 -2
  75. package/src/cmap/wire_protocol/on_demand/document.ts +1 -1
  76. package/src/cmap/wire_protocol/responses.ts +2 -2
  77. package/src/collection.ts +2 -1
  78. package/src/connection_string.ts +2 -0
  79. package/src/constants.ts +0 -1
  80. package/src/encrypter.ts +3 -10
  81. package/src/error.ts +28 -0
  82. package/src/index.ts +1 -0
  83. package/src/mongo_client.ts +73 -21
  84. package/src/operations/aggregate.ts +0 -1
  85. package/src/operations/client_bulk_write/command_builder.ts +32 -14
  86. package/src/operations/client_bulk_write/common.ts +5 -0
  87. package/src/operations/find_and_modify.ts +1 -1
  88. package/src/operations/update.ts +12 -3
  89. package/src/sdam/server.ts +5 -1
  90. package/src/sdam/topology.ts +10 -4
  91. package/src/sort.ts +32 -23
  92. package/src/utils.ts +21 -1
  93. package/lib/cmap/auth/mongodb_oidc/machine_workflow.js +0 -110
  94. package/lib/cmap/auth/mongodb_oidc/machine_workflow.js.map +0 -1
  95. package/src/cmap/auth/mongodb_oidc/machine_workflow.ts +0 -142
@@ -1,8 +1,9 @@
1
- import { BSON, type Document } from '../../bson';
1
+ import { BSON, type BSONSerializeOptions, type Document } from '../../bson';
2
2
  import { DocumentSequence } from '../../cmap/commands';
3
3
  import { MongoAPIError, MongoInvalidArgumentError } from '../../error';
4
4
  import { type PkFactory } from '../../mongo_client';
5
5
  import type { Filter, OptionalId, UpdateFilter, WithoutId } from '../../mongo_types';
6
+ import { formatSort, type SortForCmd } from '../../sort';
6
7
  import { DEFAULT_PK_FACTORY, hasAtomicOperators } from '../../utils';
7
8
  import { type CollationOptions } from '../command';
8
9
  import { type Hint } from '../operation';
@@ -127,7 +128,7 @@ export class ClientBulkWriteCommandBuilder {
127
128
 
128
129
  if (nsIndex != null) {
129
130
  // Build the operation and serialize it to get the bytes buffer.
130
- const operation = buildOperation(model, nsIndex, this.pkFactory);
131
+ const operation = buildOperation(model, nsIndex, this.pkFactory, this.options);
131
132
  let operationBuffer;
132
133
  try {
133
134
  operationBuffer = BSON.serialize(operation);
@@ -158,7 +159,12 @@ export class ClientBulkWriteCommandBuilder {
158
159
  // construct our nsInfo and ops documents and buffers.
159
160
  namespaces.set(ns, currentNamespaceIndex);
160
161
  const nsInfo = { ns: ns };
161
- const operation = buildOperation(model, currentNamespaceIndex, this.pkFactory);
162
+ const operation = buildOperation(
163
+ model,
164
+ currentNamespaceIndex,
165
+ this.pkFactory,
166
+ this.options
167
+ );
162
168
  let nsInfoBuffer;
163
169
  let operationBuffer;
164
170
  try {
@@ -327,6 +333,7 @@ export interface ClientUpdateOperation {
327
333
  upsert?: boolean;
328
334
  arrayFilters?: Document[];
329
335
  collation?: CollationOptions;
336
+ sort?: SortForCmd;
330
337
  }
331
338
 
332
339
  /**
@@ -337,9 +344,10 @@ export interface ClientUpdateOperation {
337
344
  */
338
345
  export const buildUpdateOneOperation = (
339
346
  model: ClientUpdateOneModel<Document>,
340
- index: number
347
+ index: number,
348
+ options: BSONSerializeOptions
341
349
  ): ClientUpdateOperation => {
342
- return createUpdateOperation(model, index, false);
350
+ return createUpdateOperation(model, index, false, options);
343
351
  };
344
352
 
345
353
  /**
@@ -350,17 +358,18 @@ export const buildUpdateOneOperation = (
350
358
  */
351
359
  export const buildUpdateManyOperation = (
352
360
  model: ClientUpdateManyModel<Document>,
353
- index: number
361
+ index: number,
362
+ options: BSONSerializeOptions
354
363
  ): ClientUpdateOperation => {
355
- return createUpdateOperation(model, index, true);
364
+ return createUpdateOperation(model, index, true, options);
356
365
  };
357
366
 
358
367
  /**
359
368
  * Validate the update document.
360
369
  * @param update - The update document.
361
370
  */
362
- function validateUpdate(update: Document) {
363
- if (!hasAtomicOperators(update)) {
371
+ function validateUpdate(update: Document, options: BSONSerializeOptions) {
372
+ if (!hasAtomicOperators(update, options)) {
364
373
  throw new MongoAPIError(
365
374
  'Client bulk write update models must only contain atomic modifiers (start with $) and must not be empty.'
366
375
  );
@@ -373,13 +382,14 @@ function validateUpdate(update: Document) {
373
382
  function createUpdateOperation(
374
383
  model: ClientUpdateOneModel<Document> | ClientUpdateManyModel<Document>,
375
384
  index: number,
376
- multi: boolean
385
+ multi: boolean,
386
+ options: BSONSerializeOptions
377
387
  ): ClientUpdateOperation {
378
388
  // Update documents provided in UpdateOne and UpdateMany write models are
379
389
  // required only to contain atomic modifiers (i.e. keys that start with "$").
380
390
  // Drivers MUST throw an error if an update document is empty or if the
381
391
  // document's first key does not start with "$".
382
- validateUpdate(model.update);
392
+ validateUpdate(model.update, options);
383
393
  const document: ClientUpdateOperation = {
384
394
  update: index,
385
395
  multi: multi,
@@ -398,6 +408,9 @@ function createUpdateOperation(
398
408
  if (model.collation) {
399
409
  document.collation = model.collation;
400
410
  }
411
+ if (!multi && 'sort' in model && model.sort != null) {
412
+ document.sort = formatSort(model.sort);
413
+ }
401
414
  return document;
402
415
  }
403
416
 
@@ -410,6 +423,7 @@ export interface ClientReplaceOneOperation {
410
423
  hint?: Hint;
411
424
  upsert?: boolean;
412
425
  collation?: CollationOptions;
426
+ sort?: SortForCmd;
413
427
  }
414
428
 
415
429
  /**
@@ -443,6 +457,9 @@ export const buildReplaceOneOperation = (
443
457
  if (model.collation) {
444
458
  document.collation = model.collation;
445
459
  }
460
+ if (model.sort != null) {
461
+ document.sort = formatSort(model.sort);
462
+ }
446
463
  return document;
447
464
  };
448
465
 
@@ -450,7 +467,8 @@ export const buildReplaceOneOperation = (
450
467
  export function buildOperation(
451
468
  model: AnyClientBulkWriteModel<Document>,
452
469
  index: number,
453
- pkFactory: PkFactory
470
+ pkFactory: PkFactory,
471
+ options: BSONSerializeOptions
454
472
  ): Document {
455
473
  switch (model.name) {
456
474
  case 'insertOne':
@@ -460,9 +478,9 @@ export function buildOperation(
460
478
  case 'deleteMany':
461
479
  return buildDeleteManyOperation(model, index);
462
480
  case 'updateOne':
463
- return buildUpdateOneOperation(model, index);
481
+ return buildUpdateOneOperation(model, index, options);
464
482
  case 'updateMany':
465
- return buildUpdateManyOperation(model, index);
483
+ return buildUpdateManyOperation(model, index, options);
466
484
  case 'replaceOne':
467
485
  return buildReplaceOneOperation(model, index);
468
486
  }
@@ -2,6 +2,7 @@ import { type Document } from '../../bson';
2
2
  import type { Filter, OptionalId, UpdateFilter, WithoutId } from '../../mongo_types';
3
3
  import type { CollationOptions, CommandOperationOptions } from '../../operations/command';
4
4
  import type { Hint } from '../../operations/operation';
5
+ import { type Sort } from '../../sort';
5
6
 
6
7
  /** @public */
7
8
  export interface ClientBulkWriteOptions extends CommandOperationOptions {
@@ -89,6 +90,8 @@ export interface ClientReplaceOneModel<TSchema> extends ClientWriteModel {
89
90
  hint?: Hint;
90
91
  /** When true, creates a new document if no document matches the query. */
91
92
  upsert?: boolean;
93
+ /** Specifies the sort order for the documents matched by the filter. */
94
+ sort?: Sort;
92
95
  }
93
96
 
94
97
  /** @public */
@@ -113,6 +116,8 @@ export interface ClientUpdateOneModel<TSchema> extends ClientWriteModel {
113
116
  hint?: Hint;
114
117
  /** When true, creates a new document if no document matches the query. */
115
118
  upsert?: boolean;
119
+ /** Specifies the sort order for the documents matched by the filter. */
120
+ sort?: Sort;
116
121
  }
117
122
 
118
123
  /** @public */
@@ -273,7 +273,7 @@ export class FindOneAndUpdateOperation extends FindAndModifyOperation {
273
273
  throw new MongoInvalidArgumentError('Argument "update" must be an object');
274
274
  }
275
275
 
276
- if (!hasAtomicOperators(update)) {
276
+ if (!hasAtomicOperators(update, options)) {
277
277
  throw new MongoInvalidArgumentError('Update document requires atomic operators');
278
278
  }
279
279
 
@@ -4,6 +4,7 @@ import { MongoCompatibilityError, MongoInvalidArgumentError, MongoServerError }
4
4
  import type { InferIdType, TODO_NODE_3286 } from '../mongo_types';
5
5
  import type { Server } from '../sdam/server';
6
6
  import type { ClientSession } from '../sessions';
7
+ import { formatSort, type Sort, type SortForCmd } from '../sort';
7
8
  import { type TimeoutContext } from '../timeout';
8
9
  import { hasAtomicOperators, type MongoDBNamespace } from '../utils';
9
10
  import { type CollationOptions, CommandOperation, type CommandOperationOptions } from './command';
@@ -58,6 +59,8 @@ export interface UpdateStatement {
58
59
  arrayFilters?: Document[];
59
60
  /** A document or string that specifies the index to use to support the query predicate. */
60
61
  hint?: Hint;
62
+ /** Specifies the sort order for the documents matched by the filter. */
63
+ sort?: SortForCmd;
61
64
  }
62
65
 
63
66
  /**
@@ -141,7 +144,7 @@ export class UpdateOneOperation extends UpdateOperation {
141
144
  options
142
145
  );
143
146
 
144
- if (!hasAtomicOperators(update)) {
147
+ if (!hasAtomicOperators(update, options)) {
145
148
  throw new MongoInvalidArgumentError('Update document requires atomic operators');
146
149
  }
147
150
  }
@@ -176,7 +179,7 @@ export class UpdateManyOperation extends UpdateOperation {
176
179
  options
177
180
  );
178
181
 
179
- if (!hasAtomicOperators(update)) {
182
+ if (!hasAtomicOperators(update, options)) {
180
183
  throw new MongoInvalidArgumentError('Update document requires atomic operators');
181
184
  }
182
185
  }
@@ -214,6 +217,8 @@ export interface ReplaceOptions extends CommandOperationOptions {
214
217
  upsert?: boolean;
215
218
  /** Map of parameter names and values that can be accessed using $$var (requires MongoDB 5.0). */
216
219
  let?: Document;
220
+ /** Specifies the sort order for the documents matched by the filter. */
221
+ sort?: Sort;
217
222
  }
218
223
 
219
224
  /** @internal */
@@ -259,7 +264,7 @@ export class ReplaceOneOperation extends UpdateOperation {
259
264
  export function makeUpdateStatement(
260
265
  filter: Document,
261
266
  update: Document | Document[],
262
- options: UpdateOptions & { multi?: boolean }
267
+ options: UpdateOptions & { multi?: boolean } & { sort?: Sort }
263
268
  ): UpdateStatement {
264
269
  if (filter == null || typeof filter !== 'object') {
265
270
  throw new MongoInvalidArgumentError('Selector must be a valid JavaScript object');
@@ -290,6 +295,10 @@ export function makeUpdateStatement(
290
295
  op.collation = options.collation;
291
296
  }
292
297
 
298
+ if (!options.multi && options.sort != null) {
299
+ op.sort = formatSort(options.sort);
300
+ }
301
+
293
302
  return op;
294
303
  }
295
304
 
@@ -246,8 +246,12 @@ export class Server extends TypedEventEmitter<ServerEvents> {
246
246
  }
247
247
  }
248
248
 
249
+ closeCheckedOutConnections() {
250
+ return this.pool.closeCheckedOutConnections();
251
+ }
252
+
249
253
  /** Destroy the server connection */
250
- destroy(): void {
254
+ close(): void {
251
255
  if (this.s.state === STATE_CLOSED) {
252
256
  return;
253
257
  }
@@ -490,6 +490,12 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
490
490
  }
491
491
  }
492
492
 
493
+ closeCheckedOutConnections() {
494
+ for (const server of this.s.servers.values()) {
495
+ return server.closeCheckedOutConnections();
496
+ }
497
+ }
498
+
493
499
  /** Close this topology */
494
500
  close(): void {
495
501
  if (this.s.state === STATE_CLOSED || this.s.state === STATE_CLOSING) {
@@ -497,7 +503,7 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
497
503
  }
498
504
 
499
505
  for (const server of this.s.servers.values()) {
500
- destroyServer(server, this);
506
+ closeServer(server, this);
501
507
  }
502
508
 
503
509
  this.s.servers.clear();
@@ -791,12 +797,12 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
791
797
  }
792
798
 
793
799
  /** Destroys a server, and removes all event listeners from the instance */
794
- function destroyServer(server: Server, topology: Topology) {
800
+ function closeServer(server: Server, topology: Topology) {
795
801
  for (const event of LOCAL_SERVER_EVENTS) {
796
802
  server.removeAllListeners(event);
797
803
  }
798
804
 
799
- server.destroy();
805
+ server.close();
800
806
  topology.emitAndLog(
801
807
  Topology.SERVER_CLOSED,
802
808
  new ServerClosedEvent(topology.s.id, server.description.address)
@@ -903,7 +909,7 @@ function updateServers(topology: Topology, incomingServerDescription?: ServerDes
903
909
 
904
910
  // prepare server for garbage collection
905
911
  if (server) {
906
- destroyServer(server, topology);
912
+ closeServer(server, topology);
907
913
  }
908
914
  }
909
915
  }
package/src/sort.ts CHANGED
@@ -8,24 +8,24 @@ export type SortDirection =
8
8
  | 'desc'
9
9
  | 'ascending'
10
10
  | 'descending'
11
- | { $meta: string };
11
+ | { readonly $meta: string };
12
12
 
13
13
  /** @public */
14
14
  export type Sort =
15
15
  | string
16
- | Exclude<SortDirection, { $meta: string }>
17
- | string[]
18
- | { [key: string]: SortDirection }
19
- | Map<string, SortDirection>
20
- | [string, SortDirection][]
21
- | [string, SortDirection];
16
+ | Exclude<SortDirection, { readonly $meta: string }>
17
+ | ReadonlyArray<string>
18
+ | { readonly [key: string]: SortDirection }
19
+ | ReadonlyMap<string, SortDirection>
20
+ | ReadonlyArray<readonly [string, SortDirection]>
21
+ | readonly [string, SortDirection];
22
22
 
23
23
  /** Below stricter types were created for sort that correspond with type that the cmd takes */
24
24
 
25
- /** @internal */
25
+ /** @public */
26
26
  export type SortDirectionForCmd = 1 | -1 | { $meta: string };
27
27
 
28
- /** @internal */
28
+ /** @public */
29
29
  export type SortForCmd = Map<string, SortDirectionForCmd>;
30
30
 
31
31
  /** @internal */
@@ -55,7 +55,7 @@ function isMeta(t: SortDirection): t is { $meta: string } {
55
55
  }
56
56
 
57
57
  /** @internal */
58
- function isPair(t: Sort): t is [string, SortDirection] {
58
+ function isPair(t: Sort): t is readonly [string, SortDirection] {
59
59
  if (Array.isArray(t) && t.length === 2) {
60
60
  try {
61
61
  prepareDirection(t[1]);
@@ -67,33 +67,37 @@ function isPair(t: Sort): t is [string, SortDirection] {
67
67
  return false;
68
68
  }
69
69
 
70
- function isDeep(t: Sort): t is [string, SortDirection][] {
70
+ function isDeep(t: Sort): t is ReadonlyArray<readonly [string, SortDirection]> {
71
71
  return Array.isArray(t) && Array.isArray(t[0]);
72
72
  }
73
73
 
74
- function isMap(t: Sort): t is Map<string, SortDirection> {
74
+ function isMap(t: Sort): t is ReadonlyMap<string, SortDirection> {
75
75
  return t instanceof Map && t.size > 0;
76
76
  }
77
77
 
78
+ function isReadonlyArray<T>(value: any): value is readonly T[] {
79
+ return Array.isArray(value);
80
+ }
81
+
78
82
  /** @internal */
79
- function pairToMap(v: [string, SortDirection]): SortForCmd {
83
+ function pairToMap(v: readonly [string, SortDirection]): SortForCmd {
80
84
  return new Map([[`${v[0]}`, prepareDirection([v[1]])]]);
81
85
  }
82
86
 
83
87
  /** @internal */
84
- function deepToMap(t: [string, SortDirection][]): SortForCmd {
88
+ function deepToMap(t: ReadonlyArray<readonly [string, SortDirection]>): SortForCmd {
85
89
  const sortEntries: SortPairForCmd[] = t.map(([k, v]) => [`${k}`, prepareDirection(v)]);
86
90
  return new Map(sortEntries);
87
91
  }
88
92
 
89
93
  /** @internal */
90
- function stringsToMap(t: string[]): SortForCmd {
94
+ function stringsToMap(t: ReadonlyArray<string>): SortForCmd {
91
95
  const sortEntries: SortPairForCmd[] = t.map(key => [`${key}`, 1]);
92
96
  return new Map(sortEntries);
93
97
  }
94
98
 
95
99
  /** @internal */
96
- function objectToMap(t: { [key: string]: SortDirection }): SortForCmd {
100
+ function objectToMap(t: { readonly [key: string]: SortDirection }): SortForCmd {
97
101
  const sortEntries: SortPairForCmd[] = Object.entries(t).map(([k, v]) => [
98
102
  `${k}`,
99
103
  prepareDirection(v)
@@ -102,7 +106,7 @@ function objectToMap(t: { [key: string]: SortDirection }): SortForCmd {
102
106
  }
103
107
 
104
108
  /** @internal */
105
- function mapToMap(t: Map<string, SortDirection>): SortForCmd {
109
+ function mapToMap(t: ReadonlyMap<string, SortDirection>): SortForCmd {
106
110
  const sortEntries: SortPairForCmd[] = Array.from(t).map(([k, v]) => [
107
111
  `${k}`,
108
112
  prepareDirection(v)
@@ -116,17 +120,22 @@ export function formatSort(
116
120
  direction?: SortDirection
117
121
  ): SortForCmd | undefined {
118
122
  if (sort == null) return undefined;
119
- if (typeof sort === 'string') return new Map([[sort, prepareDirection(direction)]]);
123
+
124
+ if (typeof sort === 'string') return new Map([[sort, prepareDirection(direction)]]); // 'fieldName'
125
+
120
126
  if (typeof sort !== 'object') {
121
127
  throw new MongoInvalidArgumentError(
122
128
  `Invalid sort format: ${JSON.stringify(sort)} Sort must be a valid object`
123
129
  );
124
130
  }
125
- if (!Array.isArray(sort)) {
126
- return isMap(sort) ? mapToMap(sort) : Object.keys(sort).length ? objectToMap(sort) : undefined;
131
+
132
+ if (!isReadonlyArray(sort)) {
133
+ if (isMap(sort)) return mapToMap(sort); // Map<fieldName, SortDirection>
134
+ if (Object.keys(sort).length) return objectToMap(sort); // { [fieldName: string]: SortDirection }
135
+ return undefined;
127
136
  }
128
137
  if (!sort.length) return undefined;
129
- if (isDeep(sort)) return deepToMap(sort);
130
- if (isPair(sort)) return pairToMap(sort);
131
- return stringsToMap(sort);
138
+ if (isDeep(sort)) return deepToMap(sort); // [ [fieldName, sortDir], [fieldName, sortDir] ... ]
139
+ if (isPair(sort)) return pairToMap(sort); // [ fieldName, sortDir ]
140
+ return stringsToMap(sort); // [ fieldName, fieldName ]
132
141
  }
package/src/utils.ts CHANGED
@@ -476,7 +476,10 @@ export function calculateDurationInMs(started: number | undefined): number {
476
476
  }
477
477
 
478
478
  /** @internal */
479
- export function hasAtomicOperators(doc: Document | Document[]): boolean {
479
+ export function hasAtomicOperators(
480
+ doc: Document | Document[],
481
+ options?: CommandOperationOptions
482
+ ): boolean {
480
483
  if (Array.isArray(doc)) {
481
484
  for (const document of doc) {
482
485
  if (hasAtomicOperators(document)) {
@@ -487,6 +490,23 @@ export function hasAtomicOperators(doc: Document | Document[]): boolean {
487
490
  }
488
491
 
489
492
  const keys = Object.keys(doc);
493
+ // In this case we need to throw if all the atomic operators are undefined.
494
+ if (options?.ignoreUndefined) {
495
+ let allUndefined = true;
496
+ for (const key of keys) {
497
+ // eslint-disable-next-line no-restricted-syntax
498
+ if (doc[key] !== undefined) {
499
+ allUndefined = false;
500
+ break;
501
+ }
502
+ }
503
+ if (allUndefined) {
504
+ throw new MongoInvalidArgumentError(
505
+ 'Update operations require that all atomic operators have defined values, but none were provided.'
506
+ );
507
+ }
508
+ }
509
+
490
510
  return keys.length > 0 && keys[0][0] === '$';
491
511
  }
492
512
 
@@ -1,110 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MachineWorkflow = void 0;
4
- const promises_1 = require("timers/promises");
5
- const utils_1 = require("../../../utils");
6
- const command_builders_1 = require("./command_builders");
7
- /** The time to throttle callback calls. */
8
- const THROTTLE_MS = 100;
9
- /**
10
- * Common behaviour for OIDC machine workflows.
11
- * @internal
12
- */
13
- class MachineWorkflow {
14
- /**
15
- * Instantiate the machine workflow.
16
- */
17
- constructor(cache) {
18
- this.cache = cache;
19
- this.callback = this.withLock(this.getToken.bind(this));
20
- this.lastExecutionTime = Date.now() - THROTTLE_MS;
21
- }
22
- /**
23
- * Execute the workflow. Gets the token from the subclass implementation.
24
- */
25
- async execute(connection, credentials) {
26
- const token = await this.getTokenFromCacheOrEnv(connection, credentials);
27
- const command = (0, command_builders_1.finishCommandDocument)(token);
28
- await connection.command((0, utils_1.ns)(credentials.source), command, undefined);
29
- }
30
- /**
31
- * Reauthenticate on a machine workflow just grabs the token again since the server
32
- * has said the current access token is invalid or expired.
33
- */
34
- async reauthenticate(connection, credentials) {
35
- if (this.cache.hasAccessToken) {
36
- // Reauthentication implies the token has expired.
37
- if (connection.accessToken === this.cache.getAccessToken()) {
38
- // If connection's access token is the same as the cache's, remove
39
- // the token from the cache and connection.
40
- this.cache.removeAccessToken();
41
- delete connection.accessToken;
42
- }
43
- else {
44
- // If the connection's access token is different from the cache's, set
45
- // the cache's token on the connection and do not remove from the
46
- // cache.
47
- connection.accessToken = this.cache.getAccessToken();
48
- }
49
- }
50
- await this.execute(connection, credentials);
51
- }
52
- /**
53
- * Get the document to add for speculative authentication.
54
- */
55
- async speculativeAuth(connection, credentials) {
56
- // The spec states only cached access tokens can use speculative auth.
57
- if (!this.cache.hasAccessToken) {
58
- return {};
59
- }
60
- const token = await this.getTokenFromCacheOrEnv(connection, credentials);
61
- const document = (0, command_builders_1.finishCommandDocument)(token);
62
- document.db = credentials.source;
63
- return { speculativeAuthenticate: document };
64
- }
65
- /**
66
- * Get the token from the cache or environment.
67
- */
68
- async getTokenFromCacheOrEnv(connection, credentials) {
69
- if (this.cache.hasAccessToken) {
70
- const token = this.cache.getAccessToken();
71
- // New connections won't have an access token so ensure we set here.
72
- if (!connection.accessToken) {
73
- connection.accessToken = token;
74
- }
75
- return token;
76
- }
77
- else {
78
- const token = await this.callback(credentials);
79
- this.cache.put({ accessToken: token.access_token, expiresInSeconds: token.expires_in });
80
- // Put the access token on the connection as well.
81
- connection.accessToken = token.access_token;
82
- return token.access_token;
83
- }
84
- }
85
- /**
86
- * Ensure the callback is only executed one at a time, and throttled to
87
- * only once per 100ms.
88
- */
89
- withLock(callback) {
90
- let lock = Promise.resolve();
91
- return async (credentials) => {
92
- // We do this to ensure that we would never return the result of the
93
- // previous lock, only the current callback's value would get returned.
94
- await lock;
95
- lock = lock
96
- .catch(() => null)
97
- .then(async () => {
98
- const difference = Date.now() - this.lastExecutionTime;
99
- if (difference <= THROTTLE_MS) {
100
- await (0, promises_1.setTimeout)(THROTTLE_MS - difference);
101
- }
102
- this.lastExecutionTime = Date.now();
103
- return await callback(credentials);
104
- });
105
- return await lock;
106
- };
107
- }
108
- }
109
- exports.MachineWorkflow = MachineWorkflow;
110
- //# sourceMappingURL=machine_workflow.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"machine_workflow.js","sourceRoot":"","sources":["../../../../src/cmap/auth/mongodb_oidc/machine_workflow.ts"],"names":[],"mappings":"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"}