@mongosh/service-provider-node-driver 2.3.3
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.
- package/.depcheckrc +20 -0
- package/.eslintignore +2 -0
- package/.eslintrc.js +10 -0
- package/.prettierignore +6 -0
- package/.prettierrc.json +1 -0
- package/AUTHORS +3 -0
- package/LICENSE +201 -0
- package/lib/compass/compass-service-provider.d.ts +11 -0
- package/lib/compass/compass-service-provider.js +12 -0
- package/lib/compass/compass-service-provider.js.map +1 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +8 -0
- package/lib/index.js.map +1 -0
- package/lib/mongodb-patches.d.ts +4 -0
- package/lib/mongodb-patches.js +18 -0
- package/lib/mongodb-patches.js.map +1 -0
- package/lib/node-driver-service-provider.d.ts +107 -0
- package/lib/node-driver-service-provider.js +622 -0
- package/lib/node-driver-service-provider.js.map +1 -0
- package/package.json +76 -0
- package/src/compass/compass-service-provider.ts +30 -0
- package/src/index.ts +4 -0
- package/src/mongodb-patches.spec.ts +67 -0
- package/src/mongodb-patches.ts +25 -0
- package/src/node-driver-provider.integration.spec.ts +841 -0
- package/src/node-driver-service-provider.spec.ts +1302 -0
- package/src/node-driver-service-provider.ts +1536 -0
- package/tsconfig-lint.json +5 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,1536 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Auth,
|
|
3
|
+
AuthMechanism,
|
|
4
|
+
ClientMetadata,
|
|
5
|
+
ReadPreferenceFromOptions,
|
|
6
|
+
ReadPreferenceLike,
|
|
7
|
+
OperationOptions,
|
|
8
|
+
RunCommandCursor,
|
|
9
|
+
RunCursorCommandOptions,
|
|
10
|
+
ClientEncryptionOptions,
|
|
11
|
+
MongoClient,
|
|
12
|
+
MongoMissingDependencyError,
|
|
13
|
+
SearchIndexDescription,
|
|
14
|
+
TopologyDescription,
|
|
15
|
+
TopologyDescriptionChangedEvent,
|
|
16
|
+
} from 'mongodb';
|
|
17
|
+
|
|
18
|
+
import type {
|
|
19
|
+
ServiceProvider,
|
|
20
|
+
ReplPlatform,
|
|
21
|
+
ShellAuthOptions,
|
|
22
|
+
// Driver types:
|
|
23
|
+
AggregateOptions,
|
|
24
|
+
AggregationCursor,
|
|
25
|
+
AnyBulkWriteOperation,
|
|
26
|
+
BulkWriteOptions,
|
|
27
|
+
BulkWriteResult,
|
|
28
|
+
ClientSessionOptions,
|
|
29
|
+
Collection,
|
|
30
|
+
CountDocumentsOptions,
|
|
31
|
+
CountOptions,
|
|
32
|
+
CreateCollectionOptions,
|
|
33
|
+
CreateIndexesOptions,
|
|
34
|
+
FindCursor,
|
|
35
|
+
Db,
|
|
36
|
+
DbOptions,
|
|
37
|
+
DeleteOptions,
|
|
38
|
+
DeleteResult,
|
|
39
|
+
DistinctOptions,
|
|
40
|
+
Document,
|
|
41
|
+
DropCollectionOptions,
|
|
42
|
+
DropDatabaseOptions,
|
|
43
|
+
EstimatedDocumentCountOptions,
|
|
44
|
+
FindOneAndDeleteOptions,
|
|
45
|
+
FindOneAndReplaceOptions,
|
|
46
|
+
FindOneAndUpdateOptions,
|
|
47
|
+
FindOptions,
|
|
48
|
+
IndexDescription,
|
|
49
|
+
InsertManyResult,
|
|
50
|
+
InsertOneOptions,
|
|
51
|
+
InsertOneResult,
|
|
52
|
+
ListCollectionsOptions,
|
|
53
|
+
ListDatabasesOptions,
|
|
54
|
+
ListIndexesOptions,
|
|
55
|
+
MongoClientOptions,
|
|
56
|
+
ReadConcern,
|
|
57
|
+
RenameOptions,
|
|
58
|
+
ReplaceOptions,
|
|
59
|
+
RunCommandOptions,
|
|
60
|
+
ClientSession,
|
|
61
|
+
UpdateOptions,
|
|
62
|
+
UpdateResult,
|
|
63
|
+
WriteConcern,
|
|
64
|
+
ChangeStreamOptions,
|
|
65
|
+
ChangeStream,
|
|
66
|
+
AutoEncryptionOptions,
|
|
67
|
+
ClientEncryption as MongoCryptClientEncryption,
|
|
68
|
+
ConnectionInfo,
|
|
69
|
+
} from '@mongosh/service-provider-core';
|
|
70
|
+
import {
|
|
71
|
+
getConnectExtraInfo,
|
|
72
|
+
DEFAULT_DB,
|
|
73
|
+
ServiceProviderCore,
|
|
74
|
+
} from '@mongosh/service-provider-core';
|
|
75
|
+
|
|
76
|
+
import type { DevtoolsConnectOptions } from '@mongodb-js/devtools-connect';
|
|
77
|
+
import { MongoshCommandFailed, MongoshInternalError } from '@mongosh/errors';
|
|
78
|
+
import type { MongoshBus } from '@mongosh/types';
|
|
79
|
+
import { forceCloseMongoClient } from './mongodb-patches';
|
|
80
|
+
import {
|
|
81
|
+
ConnectionString,
|
|
82
|
+
CommaAndColonSeparatedRecord,
|
|
83
|
+
} from 'mongodb-connection-string-url';
|
|
84
|
+
import { EventEmitter } from 'events';
|
|
85
|
+
import type { CreateEncryptedCollectionOptions } from '@mongosh/service-provider-core';
|
|
86
|
+
import type { DevtoolsConnectionState } from '@mongodb-js/devtools-connect';
|
|
87
|
+
import { isDeepStrictEqual } from 'util';
|
|
88
|
+
import * as driver from 'mongodb';
|
|
89
|
+
import {
|
|
90
|
+
MongoClient as MongoClientCtor,
|
|
91
|
+
ReadPreference,
|
|
92
|
+
ClientEncryption,
|
|
93
|
+
} from 'mongodb';
|
|
94
|
+
import { connectMongoClient } from '@mongodb-js/devtools-connect';
|
|
95
|
+
|
|
96
|
+
const bsonlib = () => {
|
|
97
|
+
const {
|
|
98
|
+
Binary,
|
|
99
|
+
Code,
|
|
100
|
+
DBRef,
|
|
101
|
+
Double,
|
|
102
|
+
Int32,
|
|
103
|
+
Long,
|
|
104
|
+
MinKey,
|
|
105
|
+
MaxKey,
|
|
106
|
+
ObjectId,
|
|
107
|
+
Timestamp,
|
|
108
|
+
Decimal128,
|
|
109
|
+
BSONSymbol,
|
|
110
|
+
BSONRegExp,
|
|
111
|
+
BSON,
|
|
112
|
+
} = driver;
|
|
113
|
+
return {
|
|
114
|
+
Binary,
|
|
115
|
+
Code,
|
|
116
|
+
DBRef,
|
|
117
|
+
Double,
|
|
118
|
+
Int32,
|
|
119
|
+
Long,
|
|
120
|
+
MinKey,
|
|
121
|
+
MaxKey,
|
|
122
|
+
ObjectId,
|
|
123
|
+
Timestamp,
|
|
124
|
+
Decimal128,
|
|
125
|
+
BSONSymbol,
|
|
126
|
+
calculateObjectSize: BSON.calculateObjectSize,
|
|
127
|
+
EJSON: BSON.EJSON,
|
|
128
|
+
BSONRegExp,
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export type DropDatabaseResult = {
|
|
133
|
+
ok: 0 | 1;
|
|
134
|
+
dropped?: string;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Default driver options we always use.
|
|
139
|
+
*/
|
|
140
|
+
const DEFAULT_DRIVER_OPTIONS: MongoClientOptions = Object.freeze({});
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Default driver method options we always use.
|
|
144
|
+
*/
|
|
145
|
+
const DEFAULT_BASE_OPTIONS: OperationOptions = Object.freeze({
|
|
146
|
+
serializeFunctions: true,
|
|
147
|
+
promoteLongs: false,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Pick properties of `uri` and `opts` that as a tuple that can be matched
|
|
152
|
+
* against the corresponding tuple for another `uri` and `opts` configuration,
|
|
153
|
+
* and when they do, it is meaningful to share connection state between them.
|
|
154
|
+
*
|
|
155
|
+
* Currently, this is only used for OIDC. We don't need to make sure that the
|
|
156
|
+
* configuration matches; what we *need* to avoid, however, is a case in which
|
|
157
|
+
* the same OIDC plugin instance gets passed to different connections whose
|
|
158
|
+
* endpoints don't have a trust relationship (i.e. different hosts) or where
|
|
159
|
+
* the usernames don't match, so that access tokens for one user on a given host
|
|
160
|
+
* do not end up being sent to a different host or for a different user.
|
|
161
|
+
*/
|
|
162
|
+
function normalizeEndpointAndAuthConfiguration(
|
|
163
|
+
uri: ConnectionString,
|
|
164
|
+
opts: DevtoolsConnectOptions
|
|
165
|
+
) {
|
|
166
|
+
const search = uri.typedSearchParams<DevtoolsConnectOptions>();
|
|
167
|
+
const authMechProps = new CommaAndColonSeparatedRecord(
|
|
168
|
+
search.get('authMechanismProperties')
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
return [
|
|
172
|
+
uri.protocol,
|
|
173
|
+
uri.hosts,
|
|
174
|
+
opts.auth?.username ?? uri.username,
|
|
175
|
+
opts.auth?.password ?? uri.password,
|
|
176
|
+
opts.authMechanism ?? search.get('authMechanism'),
|
|
177
|
+
opts.authSource ?? search.get('authSource'),
|
|
178
|
+
{ ...Object.fromEntries(authMechProps), ...opts.authMechanismProperties },
|
|
179
|
+
];
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
interface DependencyVersionInfo {
|
|
183
|
+
nodeDriverVersion?: string;
|
|
184
|
+
libmongocryptVersion?: string;
|
|
185
|
+
libmongocryptNodeBindingsVersion?: string;
|
|
186
|
+
kerberosVersion?: string;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Encapsulates logic for the service provider for the mongosh CLI.
|
|
191
|
+
*/
|
|
192
|
+
export class NodeDriverServiceProvider
|
|
193
|
+
extends ServiceProviderCore
|
|
194
|
+
implements ServiceProvider
|
|
195
|
+
{
|
|
196
|
+
/**
|
|
197
|
+
* Create a new CLI service provider from the provided URI.
|
|
198
|
+
*
|
|
199
|
+
* @param {String} uri - The URI.
|
|
200
|
+
* @param {DevtoolsConnectOptions} driverOptions - The options.
|
|
201
|
+
* @param {Object} cliOptions - Options passed through CLI. Right now only being used for nodb.
|
|
202
|
+
*
|
|
203
|
+
* @returns {Promise} The promise with cli service provider.
|
|
204
|
+
*/
|
|
205
|
+
static async connect(
|
|
206
|
+
this: typeof NodeDriverServiceProvider,
|
|
207
|
+
uri: string,
|
|
208
|
+
driverOptions: DevtoolsConnectOptions,
|
|
209
|
+
cliOptions: { nodb?: boolean } = {},
|
|
210
|
+
bus: MongoshBus = new EventEmitter() // TODO: Change VSCode to pass all arguments, then remove defaults
|
|
211
|
+
): Promise<NodeDriverServiceProvider> {
|
|
212
|
+
const connectionString = new ConnectionString(uri || 'mongodb://nodb/');
|
|
213
|
+
const clientOptions = this.processDriverOptions(
|
|
214
|
+
null,
|
|
215
|
+
connectionString,
|
|
216
|
+
driverOptions
|
|
217
|
+
);
|
|
218
|
+
if (process.env.MONGOSH_TEST_FORCE_API_STRICT) {
|
|
219
|
+
clientOptions.serverApi = {
|
|
220
|
+
version:
|
|
221
|
+
typeof clientOptions.serverApi === 'string'
|
|
222
|
+
? clientOptions.serverApi
|
|
223
|
+
: clientOptions.serverApi?.version ?? '1',
|
|
224
|
+
strict: true,
|
|
225
|
+
deprecationErrors: true,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
let client: MongoClient;
|
|
230
|
+
let state: DevtoolsConnectionState | undefined;
|
|
231
|
+
let lastSeenTopology: TopologyDescription | undefined;
|
|
232
|
+
|
|
233
|
+
class MongoshMongoClient extends MongoClientCtor {
|
|
234
|
+
constructor(url: string, options?: MongoClientOptions) {
|
|
235
|
+
super(url, options);
|
|
236
|
+
this.on(
|
|
237
|
+
'topologyDescriptionChanged',
|
|
238
|
+
(evt: TopologyDescriptionChangedEvent) => {
|
|
239
|
+
lastSeenTopology = evt.newDescription;
|
|
240
|
+
}
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (cliOptions.nodb) {
|
|
246
|
+
const clientOptionsCopy: MongoClientOptions &
|
|
247
|
+
Partial<DevtoolsConnectOptions> = {
|
|
248
|
+
...clientOptions,
|
|
249
|
+
};
|
|
250
|
+
delete clientOptionsCopy.productName;
|
|
251
|
+
delete clientOptionsCopy.productDocsLink;
|
|
252
|
+
delete clientOptionsCopy.oidc;
|
|
253
|
+
delete clientOptionsCopy.parentHandle;
|
|
254
|
+
delete clientOptionsCopy.parentState;
|
|
255
|
+
delete clientOptionsCopy.proxy;
|
|
256
|
+
delete clientOptionsCopy.applyProxyToOIDC;
|
|
257
|
+
client = new MongoshMongoClient(
|
|
258
|
+
connectionString.toString(),
|
|
259
|
+
clientOptionsCopy
|
|
260
|
+
);
|
|
261
|
+
} else {
|
|
262
|
+
({ client, state } = await connectMongoClient(
|
|
263
|
+
connectionString.toString(),
|
|
264
|
+
clientOptions,
|
|
265
|
+
bus,
|
|
266
|
+
MongoshMongoClient
|
|
267
|
+
));
|
|
268
|
+
}
|
|
269
|
+
clientOptions.parentState = state;
|
|
270
|
+
|
|
271
|
+
return new this(
|
|
272
|
+
client,
|
|
273
|
+
bus,
|
|
274
|
+
clientOptions,
|
|
275
|
+
connectionString,
|
|
276
|
+
lastSeenTopology
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
public readonly platform: ReplPlatform;
|
|
281
|
+
public readonly initialDb: string;
|
|
282
|
+
public mongoClient: MongoClient; // public for testing
|
|
283
|
+
private readonly uri?: ConnectionString;
|
|
284
|
+
private currentClientOptions: DevtoolsConnectOptions;
|
|
285
|
+
private dbcache: WeakMap<MongoClient, Map<string, Db>>;
|
|
286
|
+
public baseCmdOptions: OperationOptions; // public for testing
|
|
287
|
+
private bus: MongoshBus;
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Stores the last seen topology at the time when .connect() finishes.
|
|
291
|
+
*/
|
|
292
|
+
private _lastSeenTopology: TopologyDescription | undefined;
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Instantiate a new NodeDriverServiceProvider with the Node driver's connected
|
|
296
|
+
* MongoClient instance.
|
|
297
|
+
*
|
|
298
|
+
* @param {MongoClient} mongoClient - The Node drivers' MongoClient instance.
|
|
299
|
+
* @param {DevtoolsConnectOptions} clientOptions
|
|
300
|
+
* @param {string} uri - optional URI for telemetry.
|
|
301
|
+
*/
|
|
302
|
+
constructor(
|
|
303
|
+
mongoClient: MongoClient,
|
|
304
|
+
bus: MongoshBus,
|
|
305
|
+
clientOptions: DevtoolsConnectOptions,
|
|
306
|
+
uri?: ConnectionString,
|
|
307
|
+
lastSeenTopology?: TopologyDescription
|
|
308
|
+
) {
|
|
309
|
+
super(bsonlib());
|
|
310
|
+
|
|
311
|
+
this.bus = bus;
|
|
312
|
+
this.mongoClient = mongoClient;
|
|
313
|
+
this.uri = uri;
|
|
314
|
+
this._lastSeenTopology = lastSeenTopology;
|
|
315
|
+
this.platform = 'CLI';
|
|
316
|
+
try {
|
|
317
|
+
this.initialDb = (mongoClient as any).s.options.dbName || DEFAULT_DB;
|
|
318
|
+
} catch (err: any) {
|
|
319
|
+
this.initialDb = DEFAULT_DB;
|
|
320
|
+
}
|
|
321
|
+
this.currentClientOptions = clientOptions;
|
|
322
|
+
this.baseCmdOptions = { ...DEFAULT_BASE_OPTIONS }; // currently do not have any user-specified connection-wide command options, but I imagine we will eventually
|
|
323
|
+
this.dbcache = new WeakMap();
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
static getVersionInformation(): DependencyVersionInfo {
|
|
327
|
+
function tryCall<Fn extends () => any>(fn: Fn): ReturnType<Fn> | undefined {
|
|
328
|
+
try {
|
|
329
|
+
return fn();
|
|
330
|
+
} catch {
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return {
|
|
335
|
+
nodeDriverVersion: tryCall(() => require('mongodb/package.json').version),
|
|
336
|
+
libmongocryptVersion: tryCall(
|
|
337
|
+
() => ClientEncryption.libmongocryptVersion // getter that actually loads the native addon (!)
|
|
338
|
+
),
|
|
339
|
+
libmongocryptNodeBindingsVersion: tryCall(
|
|
340
|
+
() => require('mongodb-client-encryption/package.json').version
|
|
341
|
+
),
|
|
342
|
+
kerberosVersion: tryCall(() => require('kerberos/package.json').version),
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
maybeThrowBetterMissingOptionalDependencyError(
|
|
347
|
+
err: MongoMissingDependencyError
|
|
348
|
+
): never {
|
|
349
|
+
if (err.message.includes('kerberos')) {
|
|
350
|
+
try {
|
|
351
|
+
require('kerberos');
|
|
352
|
+
} catch (cause) {
|
|
353
|
+
if (
|
|
354
|
+
typeof cause === 'object' &&
|
|
355
|
+
cause &&
|
|
356
|
+
'message' in cause &&
|
|
357
|
+
typeof cause.message === 'string'
|
|
358
|
+
) {
|
|
359
|
+
// @ts-expect-error `cause` is ES2022+
|
|
360
|
+
throw new Error(`Could not load kerberos package: ${cause.message}`, {
|
|
361
|
+
cause,
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
if (err.message.includes('mongodb-client-encryption')) {
|
|
367
|
+
try {
|
|
368
|
+
require('mongodb-client-encryption');
|
|
369
|
+
} catch (cause) {
|
|
370
|
+
if (
|
|
371
|
+
typeof cause === 'object' &&
|
|
372
|
+
cause &&
|
|
373
|
+
'message' in cause &&
|
|
374
|
+
typeof cause.message === 'string'
|
|
375
|
+
) {
|
|
376
|
+
// https://jira.mongodb.org/browse/MONGOSH-1216
|
|
377
|
+
const extra =
|
|
378
|
+
'boxednode' in process
|
|
379
|
+
? ''
|
|
380
|
+
: '\n(If you are installing mongosh through homebrew or npm, consider downlading mongosh from https://www.mongodb.com/try/download/shell instead)';
|
|
381
|
+
throw new Error(
|
|
382
|
+
`Could not load mongodb-client-encryption package: ${cause.message}${extra}`,
|
|
383
|
+
// @ts-expect-error `cause` is ES2022+
|
|
384
|
+
{ cause }
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
throw err;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
async connectMongoClient(
|
|
393
|
+
connectionString: ConnectionString | string,
|
|
394
|
+
clientOptions: DevtoolsConnectOptions
|
|
395
|
+
): Promise<{ client: MongoClient; state: DevtoolsConnectionState }> {
|
|
396
|
+
try {
|
|
397
|
+
return await connectMongoClient(
|
|
398
|
+
connectionString.toString(),
|
|
399
|
+
clientOptions,
|
|
400
|
+
this.bus,
|
|
401
|
+
MongoClientCtor
|
|
402
|
+
);
|
|
403
|
+
} catch (err: unknown) {
|
|
404
|
+
if (
|
|
405
|
+
typeof err === 'object' &&
|
|
406
|
+
err &&
|
|
407
|
+
'name' in err &&
|
|
408
|
+
err.name === 'MongoMissingDependencyError'
|
|
409
|
+
) {
|
|
410
|
+
this.maybeThrowBetterMissingOptionalDependencyError(
|
|
411
|
+
err as MongoMissingDependencyError
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
throw err;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
async getNewConnection(
|
|
419
|
+
uri: string,
|
|
420
|
+
options: Partial<DevtoolsConnectOptions> = {}
|
|
421
|
+
): Promise<NodeDriverServiceProvider> {
|
|
422
|
+
const connectionString = new ConnectionString(uri);
|
|
423
|
+
const clientOptions = this.processDriverOptions(connectionString, options);
|
|
424
|
+
|
|
425
|
+
const { client, state } = await this.connectMongoClient(
|
|
426
|
+
connectionString.toString(),
|
|
427
|
+
clientOptions
|
|
428
|
+
);
|
|
429
|
+
clientOptions.parentState = state;
|
|
430
|
+
return new NodeDriverServiceProvider(
|
|
431
|
+
client,
|
|
432
|
+
this.bus,
|
|
433
|
+
clientOptions,
|
|
434
|
+
connectionString,
|
|
435
|
+
this._lastSeenTopology
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
_getHostnameForConnection(
|
|
440
|
+
topology?: TopologyDescription
|
|
441
|
+
): string | undefined {
|
|
442
|
+
return topology?.servers?.values().next().value.hostAddress.host;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
async getConnectionInfo(): Promise<ConnectionInfo> {
|
|
446
|
+
const [buildInfo = null, atlasVersion = null, fcv = null, atlascliInfo] =
|
|
447
|
+
await Promise.all([
|
|
448
|
+
this.runCommandWithCheck(
|
|
449
|
+
'admin',
|
|
450
|
+
{ buildInfo: 1 },
|
|
451
|
+
this.baseCmdOptions
|
|
452
|
+
).catch(() => {}),
|
|
453
|
+
this.runCommandWithCheck(
|
|
454
|
+
'admin',
|
|
455
|
+
{ atlasVersion: 1 },
|
|
456
|
+
this.baseCmdOptions
|
|
457
|
+
).catch(() => {}),
|
|
458
|
+
this.runCommandWithCheck(
|
|
459
|
+
'admin',
|
|
460
|
+
{ getParameter: 1, featureCompatibilityVersion: 1 },
|
|
461
|
+
this.baseCmdOptions
|
|
462
|
+
).catch(() => {}),
|
|
463
|
+
this.countDocuments('admin', 'atlascli', {
|
|
464
|
+
managedClusterType: 'atlasCliLocalDevCluster',
|
|
465
|
+
}).catch(() => 0),
|
|
466
|
+
]);
|
|
467
|
+
|
|
468
|
+
const resolvedHostname = this._getHostnameForConnection(
|
|
469
|
+
this._lastSeenTopology
|
|
470
|
+
);
|
|
471
|
+
|
|
472
|
+
const extraConnectionInfo = getConnectExtraInfo({
|
|
473
|
+
connectionString: this.uri,
|
|
474
|
+
buildInfo,
|
|
475
|
+
atlasVersion,
|
|
476
|
+
resolvedHostname,
|
|
477
|
+
isLocalAtlas: !!atlascliInfo,
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
return {
|
|
481
|
+
buildInfo,
|
|
482
|
+
resolvedHostname,
|
|
483
|
+
extraInfo: {
|
|
484
|
+
...extraConnectionInfo,
|
|
485
|
+
fcv: fcv?.featureCompatibilityVersion?.version,
|
|
486
|
+
},
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
async renameCollection(
|
|
491
|
+
database: string,
|
|
492
|
+
oldName: string,
|
|
493
|
+
newName: string,
|
|
494
|
+
options: RenameOptions = {},
|
|
495
|
+
dbOptions?: DbOptions
|
|
496
|
+
): Promise<Collection> {
|
|
497
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
498
|
+
return await this.db(database, dbOptions).renameCollection(
|
|
499
|
+
oldName,
|
|
500
|
+
newName,
|
|
501
|
+
options
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Get the Db object from the client.
|
|
507
|
+
*
|
|
508
|
+
* @param {String} name - The database name.
|
|
509
|
+
* @param dbOptions
|
|
510
|
+
*
|
|
511
|
+
* @returns {Db} The database.
|
|
512
|
+
*/
|
|
513
|
+
private db(name: string, dbOptions: DbOptions = {}): Db {
|
|
514
|
+
const key = `${name}-${JSON.stringify(dbOptions)}`;
|
|
515
|
+
const dbcache = this.getDBCache();
|
|
516
|
+
const cached = dbcache.get(key);
|
|
517
|
+
if (cached) {
|
|
518
|
+
return cached;
|
|
519
|
+
}
|
|
520
|
+
const db = this.mongoClient.db(name, dbOptions);
|
|
521
|
+
dbcache.set(key, db);
|
|
522
|
+
return db;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Wrapper to make this available for testing.
|
|
527
|
+
*/
|
|
528
|
+
_dbTestWrapper(name: string, dbOptions?: DbOptions): Db {
|
|
529
|
+
return this.db(name, dbOptions);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Return the db cache for the current MongoClient.
|
|
534
|
+
*/
|
|
535
|
+
private getDBCache(): Map<string, Db> {
|
|
536
|
+
const existing = this.dbcache.get(this.mongoClient);
|
|
537
|
+
if (existing) {
|
|
538
|
+
return existing;
|
|
539
|
+
}
|
|
540
|
+
this.dbcache.set(this.mongoClient, new Map());
|
|
541
|
+
return this.getDBCache();
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Run an aggregation pipeline.
|
|
546
|
+
*
|
|
547
|
+
* @param {String} database - the db name
|
|
548
|
+
* @param {String} collection - the collection name
|
|
549
|
+
* @param pipeline
|
|
550
|
+
* @param options
|
|
551
|
+
* allowDiskUse: Optional<Boolean>;
|
|
552
|
+
* batchSize: Optional<Int32>;
|
|
553
|
+
* bypassDocumentValidation: Optional<Boolean>;
|
|
554
|
+
* collation: Optional<Document>;
|
|
555
|
+
* maxTimeMS: Optional<Int64>;
|
|
556
|
+
* maxAwaitTimeMS: Optional<Int64>;
|
|
557
|
+
* comment: Optional<String>;
|
|
558
|
+
* hint: Optional<(String | Document = {})>;
|
|
559
|
+
* @param dbOptions
|
|
560
|
+
|
|
561
|
+
* @returns {Cursor} The aggregation cursor.
|
|
562
|
+
*/
|
|
563
|
+
aggregate(
|
|
564
|
+
database: string,
|
|
565
|
+
collection: string,
|
|
566
|
+
pipeline: Document[] = [],
|
|
567
|
+
options: AggregateOptions = {},
|
|
568
|
+
dbOptions?: DbOptions
|
|
569
|
+
): AggregationCursor {
|
|
570
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
571
|
+
return this.db(database, dbOptions)
|
|
572
|
+
.collection(collection)
|
|
573
|
+
.aggregate(pipeline, options);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* @param {String} database - the db name
|
|
578
|
+
* @param pipeline
|
|
579
|
+
* @param options
|
|
580
|
+
* allowDiskUse: Optional<Boolean>;
|
|
581
|
+
* batchSize: Optional<Int32>;
|
|
582
|
+
* bypassDocumentValidation: Optional<Boolean>;
|
|
583
|
+
* collation: Optional<Document>;
|
|
584
|
+
* maxTimeMS: Optional<Int64>;
|
|
585
|
+
* maxAwaitTimeMS: Optional<Int64>;
|
|
586
|
+
* comment: Optional<String>;
|
|
587
|
+
* hint: Optional<(String | Document = {})>;
|
|
588
|
+
* @param dbOptions
|
|
589
|
+
* j: Optional<Boolean>
|
|
590
|
+
* w: Optional<Int32 | String>
|
|
591
|
+
* wtimeoutMS: Optional<Int64>
|
|
592
|
+
* @return {any}
|
|
593
|
+
*/
|
|
594
|
+
aggregateDb(
|
|
595
|
+
database: string,
|
|
596
|
+
pipeline: Document[] = [],
|
|
597
|
+
options: AggregateOptions = {},
|
|
598
|
+
dbOptions?: DbOptions
|
|
599
|
+
): AggregationCursor {
|
|
600
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
601
|
+
const db: any = this.db(database, dbOptions) as any;
|
|
602
|
+
return db.aggregate(pipeline, options);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* @param {String} database - the db name
|
|
607
|
+
* @param {String} collection - the collection name
|
|
608
|
+
* @param requests
|
|
609
|
+
* @param options
|
|
610
|
+
* ordered: Boolean;
|
|
611
|
+
* bypassDocumentValidation: Optional<Boolean>;
|
|
612
|
+
* @param dbOptions
|
|
613
|
+
* j: Optional<Boolean>
|
|
614
|
+
* w: Optional<Int32 | String>
|
|
615
|
+
* wtimeoutMS: Optional<Int64>
|
|
616
|
+
* readConcern:
|
|
617
|
+
* level: <String local|majority|linearizable|available>
|
|
618
|
+
* @return {any}
|
|
619
|
+
*/
|
|
620
|
+
bulkWrite(
|
|
621
|
+
database: string,
|
|
622
|
+
collection: string,
|
|
623
|
+
requests: AnyBulkWriteOperation[],
|
|
624
|
+
options: BulkWriteOptions = {},
|
|
625
|
+
dbOptions?: DbOptions
|
|
626
|
+
): Promise<BulkWriteResult> {
|
|
627
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
628
|
+
return this.db(database, dbOptions)
|
|
629
|
+
.collection(collection)
|
|
630
|
+
.bulkWrite(requests, options);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Close the connection.
|
|
635
|
+
*
|
|
636
|
+
* @param {boolean} force - Whether to force close the connection.
|
|
637
|
+
*/
|
|
638
|
+
async close(force: boolean): Promise<void> {
|
|
639
|
+
this.dbcache.set(this.mongoClient, new Map());
|
|
640
|
+
if (force) {
|
|
641
|
+
await forceCloseMongoClient(this.mongoClient);
|
|
642
|
+
} else {
|
|
643
|
+
await this.mongoClient.close();
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
async suspend(): Promise<() => Promise<void>> {
|
|
648
|
+
await this.close(true);
|
|
649
|
+
return async () => {
|
|
650
|
+
await this.resetConnectionOptions({});
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Deprecated count command.
|
|
656
|
+
*
|
|
657
|
+
* @param {String} database - the db name
|
|
658
|
+
* @param {String} collection - the collection name
|
|
659
|
+
* @param query
|
|
660
|
+
* @param options
|
|
661
|
+
* collation: Optional<Document>
|
|
662
|
+
* hint: Optional<(String | Document = {})>;
|
|
663
|
+
* limit: Optional<Int64>;
|
|
664
|
+
* maxTimeMS: Optional<Int64>;
|
|
665
|
+
* skip: Optional<Int64>;
|
|
666
|
+
* @param dbOptions
|
|
667
|
+
* readConcern:
|
|
668
|
+
* level: <String local|majority|linearizable|available>
|
|
669
|
+
* @return {Promise<any>}
|
|
670
|
+
*/
|
|
671
|
+
count(
|
|
672
|
+
database: string,
|
|
673
|
+
collection: string,
|
|
674
|
+
query: Document = {},
|
|
675
|
+
options: CountOptions = {},
|
|
676
|
+
dbOptions?: DbOptions
|
|
677
|
+
): Promise<number> {
|
|
678
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
679
|
+
return this.db(database, dbOptions)
|
|
680
|
+
.collection(collection)
|
|
681
|
+
.count(query, options);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Get an exact document count from the collection.
|
|
686
|
+
*
|
|
687
|
+
* @param {String} database - the db name
|
|
688
|
+
* @param {String} collection - the collection name
|
|
689
|
+
* @param filter
|
|
690
|
+
* @param options
|
|
691
|
+
* hint: Optional<(String | Document = {})>;
|
|
692
|
+
* limit: Optional<Int64>;
|
|
693
|
+
* maxTimeMS: Optional<Int64>;
|
|
694
|
+
* skip: Optional<Int64>;
|
|
695
|
+
* @param dbOptions
|
|
696
|
+
* @return {any}
|
|
697
|
+
*/
|
|
698
|
+
countDocuments(
|
|
699
|
+
database: string,
|
|
700
|
+
collection: string,
|
|
701
|
+
filter: Document = {},
|
|
702
|
+
options: CountDocumentsOptions = {},
|
|
703
|
+
dbOptions?: DbOptions
|
|
704
|
+
): Promise<number> {
|
|
705
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
706
|
+
return this.db(database, dbOptions)
|
|
707
|
+
.collection(collection)
|
|
708
|
+
.countDocuments(filter, options);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Delete multiple documents from the collection.
|
|
713
|
+
*
|
|
714
|
+
* @param {String} database - The database name.
|
|
715
|
+
* @param {String} collection - The collection name.
|
|
716
|
+
* @param {Object} filter - The filter.
|
|
717
|
+
* @param {Object} options - The delete many options.
|
|
718
|
+
* @param {Object} dbOptions - The database options (i.e. readConcern, writeConcern. etc).
|
|
719
|
+
*
|
|
720
|
+
* @returns {Promise} The promise of the result.
|
|
721
|
+
*/
|
|
722
|
+
deleteMany(
|
|
723
|
+
database: string,
|
|
724
|
+
collection: string,
|
|
725
|
+
filter: Document = {},
|
|
726
|
+
options: DeleteOptions = {},
|
|
727
|
+
dbOptions?: DbOptions
|
|
728
|
+
): Promise<DeleteResult> {
|
|
729
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
730
|
+
return this.db(database, dbOptions)
|
|
731
|
+
.collection(collection)
|
|
732
|
+
.deleteMany(filter, options);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* Delete one document from the collection.
|
|
737
|
+
*
|
|
738
|
+
* @param {String} database - The database name.
|
|
739
|
+
* @param {String} collection - The collection name.
|
|
740
|
+
* @param {Object} filter - The filter.
|
|
741
|
+
* @param {Object} options - The delete one options.
|
|
742
|
+
* @param {Object} dbOptions - The database options (i.e. readConcern, writeConcern. etc).
|
|
743
|
+
*
|
|
744
|
+
* @returns {Promise} The promise of the result.
|
|
745
|
+
*/
|
|
746
|
+
deleteOne(
|
|
747
|
+
database: string,
|
|
748
|
+
collection: string,
|
|
749
|
+
filter: Document = {},
|
|
750
|
+
options: DeleteOptions = {},
|
|
751
|
+
dbOptions?: DbOptions
|
|
752
|
+
): Promise<DeleteResult> {
|
|
753
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
754
|
+
return this.db(database, dbOptions)
|
|
755
|
+
.collection(collection)
|
|
756
|
+
.deleteOne(filter, options);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* Get distinct values for the field.
|
|
761
|
+
*
|
|
762
|
+
* @param {String} database - The database name.
|
|
763
|
+
* @param {String} collection - The collection name.
|
|
764
|
+
* @param {String} fieldName - The field name.
|
|
765
|
+
* @param {Object} filter - The filter.
|
|
766
|
+
* @param {Object} options - The distinct options.
|
|
767
|
+
* @param {Object} dbOptions - The database options (i.e. readConcern, writeConcern. etc).
|
|
768
|
+
*
|
|
769
|
+
* @returns {Cursor} The cursor.
|
|
770
|
+
*/
|
|
771
|
+
distinct(
|
|
772
|
+
database: string,
|
|
773
|
+
collection: string,
|
|
774
|
+
fieldName: string,
|
|
775
|
+
filter: Document = {},
|
|
776
|
+
options: DistinctOptions = {},
|
|
777
|
+
dbOptions?: DbOptions
|
|
778
|
+
): Promise<Document[]> {
|
|
779
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
780
|
+
return this.db(database, dbOptions)
|
|
781
|
+
.collection(collection)
|
|
782
|
+
.distinct(fieldName, filter, options);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* Get an estimated document count from the collection.
|
|
787
|
+
*
|
|
788
|
+
* @param {String} database - The database name.
|
|
789
|
+
* @param {String} collection - The collection name.
|
|
790
|
+
* @param {Object} options - The count options.
|
|
791
|
+
* @param {Object} dbOptions - The database options (i.e. readConcern, writeConcern. etc).
|
|
792
|
+
*
|
|
793
|
+
* @returns {Promise} The promise of the result.
|
|
794
|
+
*/
|
|
795
|
+
estimatedDocumentCount(
|
|
796
|
+
database: string,
|
|
797
|
+
collection: string,
|
|
798
|
+
options: EstimatedDocumentCountOptions = {},
|
|
799
|
+
dbOptions?: DbOptions
|
|
800
|
+
): Promise<number> {
|
|
801
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
802
|
+
return this.db(database, dbOptions)
|
|
803
|
+
.collection(collection)
|
|
804
|
+
.estimatedDocumentCount(options);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* Find documents in the collection.
|
|
809
|
+
*
|
|
810
|
+
* @param {String} database - The database name.
|
|
811
|
+
* @param {String} collection - The collection name.
|
|
812
|
+
* @param {Object} filter - The filter.
|
|
813
|
+
* @param {Object} options - The find options.
|
|
814
|
+
*
|
|
815
|
+
* @param dbOptions
|
|
816
|
+
* @returns {Cursor} The cursor.
|
|
817
|
+
*/
|
|
818
|
+
find(
|
|
819
|
+
database: string,
|
|
820
|
+
collection: string,
|
|
821
|
+
filter: Document = {},
|
|
822
|
+
options: FindOptions = {},
|
|
823
|
+
dbOptions?: DbOptions
|
|
824
|
+
): FindCursor {
|
|
825
|
+
const findOptions: any = { ...this.baseCmdOptions, ...options };
|
|
826
|
+
if ('allowPartialResults' in findOptions) {
|
|
827
|
+
findOptions.partial = findOptions.allowPartialResults;
|
|
828
|
+
}
|
|
829
|
+
if ('noCursorTimeout' in findOptions) {
|
|
830
|
+
findOptions.timeout = findOptions.noCursorTimeout;
|
|
831
|
+
}
|
|
832
|
+
return this.db(database, dbOptions)
|
|
833
|
+
.collection(collection)
|
|
834
|
+
.find(filter, findOptions);
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/**
|
|
838
|
+
* Find one document and delete it.
|
|
839
|
+
*
|
|
840
|
+
* @param {String} database - The database name.
|
|
841
|
+
* @param {String} collection - The collection name.
|
|
842
|
+
* @param {Object} filter - The filter.
|
|
843
|
+
* @param {Object} options - The find options.
|
|
844
|
+
* @param {Object} dbOptions - The database options (i.e. readConcern, writeConcern. etc).
|
|
845
|
+
*
|
|
846
|
+
* @returns {Promise} The promise of the result.
|
|
847
|
+
*/
|
|
848
|
+
findOneAndDelete(
|
|
849
|
+
database: string,
|
|
850
|
+
collection: string,
|
|
851
|
+
filter: Document = {},
|
|
852
|
+
options: FindOneAndDeleteOptions = {},
|
|
853
|
+
dbOptions?: DbOptions
|
|
854
|
+
): Promise<Document | null> {
|
|
855
|
+
// TODO(MONGOSH-XXX): Consider removing the includeResultMetadata default
|
|
856
|
+
// since `false` is what gives the spec-compliant driver behavior.
|
|
857
|
+
options = {
|
|
858
|
+
includeResultMetadata: true,
|
|
859
|
+
...this.baseCmdOptions,
|
|
860
|
+
...options,
|
|
861
|
+
};
|
|
862
|
+
return this.db(database, dbOptions)
|
|
863
|
+
.collection(collection)
|
|
864
|
+
.findOneAndDelete(filter, options);
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* Find one document and replace it.
|
|
869
|
+
*
|
|
870
|
+
* @param {String} database - The database name.
|
|
871
|
+
* @param {String} collection - The collection name.
|
|
872
|
+
* @param {Object} filter - The filter.
|
|
873
|
+
* @param {Object} replacement - The replacement.
|
|
874
|
+
* @param {Object} options - The find options.
|
|
875
|
+
*
|
|
876
|
+
* @param dbOptions
|
|
877
|
+
* @returns {Promise} The promise of the result.
|
|
878
|
+
*/
|
|
879
|
+
findOneAndReplace(
|
|
880
|
+
database: string,
|
|
881
|
+
collection: string,
|
|
882
|
+
filter: Document = {},
|
|
883
|
+
replacement: Document = {},
|
|
884
|
+
options: FindOneAndReplaceOptions = {},
|
|
885
|
+
dbOptions?: DbOptions
|
|
886
|
+
): Promise<Document> {
|
|
887
|
+
const findOneAndReplaceOptions: any = {
|
|
888
|
+
includeResultMetadata: true,
|
|
889
|
+
...this.baseCmdOptions,
|
|
890
|
+
...options,
|
|
891
|
+
};
|
|
892
|
+
|
|
893
|
+
return (
|
|
894
|
+
this.db(database, dbOptions).collection(collection) as any
|
|
895
|
+
).findOneAndReplace(filter, replacement, findOneAndReplaceOptions);
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
/**
|
|
899
|
+
* Find one document and update it.
|
|
900
|
+
*
|
|
901
|
+
* @param {String} database - The database name.
|
|
902
|
+
* @param {String} collection - The collection name.
|
|
903
|
+
* @param {Object} filter - The filter.
|
|
904
|
+
* @param {(Object|Array)} update - The update.
|
|
905
|
+
* @param {Object} options - The find options.
|
|
906
|
+
*
|
|
907
|
+
* @param dbOptions
|
|
908
|
+
* @returns {Promise} The promise of the result.
|
|
909
|
+
*/
|
|
910
|
+
findOneAndUpdate(
|
|
911
|
+
database: string,
|
|
912
|
+
collection: string,
|
|
913
|
+
filter: Document = {},
|
|
914
|
+
update: Document | Document[] = {},
|
|
915
|
+
options: FindOneAndUpdateOptions = {},
|
|
916
|
+
dbOptions?: DbOptions
|
|
917
|
+
): Promise<Document> {
|
|
918
|
+
const findOneAndUpdateOptions = {
|
|
919
|
+
includeResultMetadata: true,
|
|
920
|
+
...this.baseCmdOptions,
|
|
921
|
+
...options,
|
|
922
|
+
};
|
|
923
|
+
|
|
924
|
+
return this.db(database, dbOptions)
|
|
925
|
+
.collection(collection)
|
|
926
|
+
.findOneAndUpdate(filter, update, findOneAndUpdateOptions) as any;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
/**
|
|
930
|
+
* Insert many documents into the collection.
|
|
931
|
+
*
|
|
932
|
+
* @param {string} database - The database name.
|
|
933
|
+
* @param {string} collection - The collection name.
|
|
934
|
+
* @param {Document[]} [docs=[]] - The documents.
|
|
935
|
+
* @param {Document} [options={}] - options - The insert many options.
|
|
936
|
+
* @param {DbOptions} [dbOptions] - The database options.
|
|
937
|
+
*
|
|
938
|
+
* @returns {Promise<InsertManyResult>}
|
|
939
|
+
*/
|
|
940
|
+
insertMany(
|
|
941
|
+
database: string,
|
|
942
|
+
collection: string,
|
|
943
|
+
docs: Document[] = [],
|
|
944
|
+
options: BulkWriteOptions = {},
|
|
945
|
+
dbOptions?: DbOptions
|
|
946
|
+
): Promise<InsertManyResult> {
|
|
947
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
948
|
+
return this.db(database, dbOptions)
|
|
949
|
+
.collection(collection)
|
|
950
|
+
.insertMany(docs, options);
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
/**
|
|
954
|
+
* Insert one document into the collection.
|
|
955
|
+
*
|
|
956
|
+
* @param {String} database - The database name.
|
|
957
|
+
* @param {String} collection - The collection name.
|
|
958
|
+
* @param {Object} doc - The document.
|
|
959
|
+
* @param {Object} options - The insert one options.
|
|
960
|
+
* @param {Object} dbOptions - The database options (i.e. readConcern, writeConcern. etc).
|
|
961
|
+
*
|
|
962
|
+
* @returns {Promise} The promise of the result.
|
|
963
|
+
*/
|
|
964
|
+
async insertOne(
|
|
965
|
+
database: string,
|
|
966
|
+
collection: string,
|
|
967
|
+
doc: Document = {},
|
|
968
|
+
options: InsertOneOptions = {},
|
|
969
|
+
dbOptions?: DbOptions
|
|
970
|
+
): Promise<InsertOneResult> {
|
|
971
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
972
|
+
return this.db(database, dbOptions)
|
|
973
|
+
.collection(collection)
|
|
974
|
+
.insertOne(doc, options);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
/**
|
|
978
|
+
* Replace a document with another.
|
|
979
|
+
*
|
|
980
|
+
* @param {String} database - The database name.
|
|
981
|
+
* @param {String} collection - The collection name.
|
|
982
|
+
* @param {Object} filter - The filter.
|
|
983
|
+
* @param {Object} replacement - The replacement document for matches.
|
|
984
|
+
* @param {Object} options - The replace options.
|
|
985
|
+
* @param {Object} dbOptions - The database options (i.e. readConcern, writeConcern. etc).
|
|
986
|
+
*
|
|
987
|
+
* @returns {Promise} The promise of the result.
|
|
988
|
+
*/
|
|
989
|
+
replaceOne(
|
|
990
|
+
database: string,
|
|
991
|
+
collection: string,
|
|
992
|
+
filter: Document = {},
|
|
993
|
+
replacement: Document = {},
|
|
994
|
+
options: ReplaceOptions = {},
|
|
995
|
+
dbOptions?: DbOptions
|
|
996
|
+
): Promise<UpdateResult> {
|
|
997
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
998
|
+
return this.db(database, dbOptions)
|
|
999
|
+
.collection(collection)
|
|
1000
|
+
.replaceOne(filter, replacement, options) as Promise<UpdateResult>;
|
|
1001
|
+
// `as UpdateResult` because we know we didn't request .explain() here.
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
/**
|
|
1005
|
+
* Run a command against the database.
|
|
1006
|
+
*
|
|
1007
|
+
* @param {String} database - The database name.
|
|
1008
|
+
* @param {Object} spec - The command specification.
|
|
1009
|
+
* @param {Object} options - The database options.
|
|
1010
|
+
* @param {Object} dbOptions - The connection-wide database options.
|
|
1011
|
+
*
|
|
1012
|
+
* @returns {Promise} The promise of command results.
|
|
1013
|
+
*/
|
|
1014
|
+
runCommand(
|
|
1015
|
+
database: string,
|
|
1016
|
+
spec: Document = {},
|
|
1017
|
+
options: RunCommandOptions = {},
|
|
1018
|
+
dbOptions?: DbOptions
|
|
1019
|
+
): Promise<Document> {
|
|
1020
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
1021
|
+
const db = this.db(database, dbOptions);
|
|
1022
|
+
return db.command(spec, options);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* Run a command against the database and check the results for ok: 0.
|
|
1027
|
+
*
|
|
1028
|
+
* @param {String} database - The database name.
|
|
1029
|
+
* @param {Object} spec - The command specification.
|
|
1030
|
+
* @param {Object} options - The database options.
|
|
1031
|
+
* @param {Object} dbOptions - The connection-wide database options.
|
|
1032
|
+
*
|
|
1033
|
+
* @returns {Promise} The promise of command results.
|
|
1034
|
+
*/
|
|
1035
|
+
async runCommandWithCheck(
|
|
1036
|
+
database: string,
|
|
1037
|
+
spec: Document = {},
|
|
1038
|
+
options: RunCommandOptions = {},
|
|
1039
|
+
dbOptions?: DbOptions
|
|
1040
|
+
): Promise<Document> {
|
|
1041
|
+
const result = await this.runCommand(database, spec, options, dbOptions);
|
|
1042
|
+
if (result.ok === 0) {
|
|
1043
|
+
throw new MongoshCommandFailed(JSON.stringify(spec));
|
|
1044
|
+
}
|
|
1045
|
+
return result as { ok: 1 };
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* Run a command against the database that returns a cursor.
|
|
1050
|
+
*
|
|
1051
|
+
* @param {String} database - The database name.
|
|
1052
|
+
* @param {Object} spec - The command specification.
|
|
1053
|
+
* @param {Object} options - The command options.
|
|
1054
|
+
* @param {Object} dbOptions - The connection-wide database options.
|
|
1055
|
+
*/
|
|
1056
|
+
runCursorCommand(
|
|
1057
|
+
database: string,
|
|
1058
|
+
spec: Document = {},
|
|
1059
|
+
options: RunCursorCommandOptions = {},
|
|
1060
|
+
dbOptions?: DbOptions
|
|
1061
|
+
): RunCommandCursor {
|
|
1062
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
1063
|
+
const db = this.db(database, dbOptions);
|
|
1064
|
+
return db.runCursorCommand(spec, options);
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
/**
|
|
1068
|
+
* list databases.
|
|
1069
|
+
*
|
|
1070
|
+
* @param {String} database - The database name.
|
|
1071
|
+
*
|
|
1072
|
+
* @returns {Promise} The promise of command results.
|
|
1073
|
+
*/
|
|
1074
|
+
listDatabases(
|
|
1075
|
+
database: string,
|
|
1076
|
+
options: ListDatabasesOptions = {}
|
|
1077
|
+
): Promise<Document> {
|
|
1078
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
1079
|
+
return this.db(database).admin().listDatabases(options);
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
/**
|
|
1083
|
+
* Update many document.
|
|
1084
|
+
*
|
|
1085
|
+
* @param {String} database - The database name.
|
|
1086
|
+
* @param {String} collection - The collection name.
|
|
1087
|
+
* @param {Object} filter - The filter.
|
|
1088
|
+
* @param {(Object|Array)} update - The updates.
|
|
1089
|
+
* @param {Object} options - The update options.
|
|
1090
|
+
* @param {Object} dbOptions - The database options (i.e. readConcern, writeConcern. etc).
|
|
1091
|
+
*
|
|
1092
|
+
* @returns {Promise} The promise of the result.
|
|
1093
|
+
*/
|
|
1094
|
+
async updateMany(
|
|
1095
|
+
database: string,
|
|
1096
|
+
collection: string,
|
|
1097
|
+
filter: Document = {},
|
|
1098
|
+
update: Document = {},
|
|
1099
|
+
options: UpdateOptions = {},
|
|
1100
|
+
dbOptions?: DbOptions
|
|
1101
|
+
): Promise<UpdateResult> {
|
|
1102
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
1103
|
+
return await this.db(database, dbOptions)
|
|
1104
|
+
.collection(collection)
|
|
1105
|
+
.updateMany(filter, update, options);
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
/**
|
|
1109
|
+
* Update a document.
|
|
1110
|
+
*
|
|
1111
|
+
* @param {String} database - The database name.
|
|
1112
|
+
* @param {String} collection - The collection name.
|
|
1113
|
+
* @param {Object} filter - The filter.
|
|
1114
|
+
* @param {(Object|Array)} update - The updates.
|
|
1115
|
+
* @param {Object} options - The update options.
|
|
1116
|
+
* @param {Object} dbOptions - The database options (i.e. readConcern, writeConcern. etc).
|
|
1117
|
+
*
|
|
1118
|
+
* @returns {Promise} The promise of the result.
|
|
1119
|
+
*/
|
|
1120
|
+
updateOne(
|
|
1121
|
+
database: string,
|
|
1122
|
+
collection: string,
|
|
1123
|
+
filter: Document = {},
|
|
1124
|
+
update: Document = {},
|
|
1125
|
+
options: UpdateOptions = {},
|
|
1126
|
+
dbOptions?: DbOptions
|
|
1127
|
+
): Promise<UpdateResult> {
|
|
1128
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
1129
|
+
return this.db(database, dbOptions)
|
|
1130
|
+
.collection(collection)
|
|
1131
|
+
.updateOne(filter, update, options);
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
/**
|
|
1135
|
+
* Get currently known topology information.
|
|
1136
|
+
*/
|
|
1137
|
+
getTopology(): any | undefined {
|
|
1138
|
+
return (this.mongoClient as any).topology;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
/**
|
|
1142
|
+
* Drop a database
|
|
1143
|
+
*
|
|
1144
|
+
* @param {String} db - The database name.
|
|
1145
|
+
* @param {Document} options - The write concern.
|
|
1146
|
+
*
|
|
1147
|
+
* @param dbOptions
|
|
1148
|
+
* @returns {Promise<Document>} The result of the operation.
|
|
1149
|
+
*/
|
|
1150
|
+
async dropDatabase(
|
|
1151
|
+
db: string,
|
|
1152
|
+
options: DropDatabaseOptions = {},
|
|
1153
|
+
dbOptions: DbOptions = {}
|
|
1154
|
+
): Promise<DropDatabaseResult> {
|
|
1155
|
+
const opts = { ...this.baseCmdOptions, ...options } as DropDatabaseOptions;
|
|
1156
|
+
const nativeResult = await this.db(db, dbOptions).dropDatabase(opts);
|
|
1157
|
+
|
|
1158
|
+
const ok = nativeResult ? 1 : 0;
|
|
1159
|
+
return {
|
|
1160
|
+
ok,
|
|
1161
|
+
...(ok ? { dropped: db } : {}),
|
|
1162
|
+
};
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
/**
|
|
1166
|
+
* Adds new indexes to a collection.
|
|
1167
|
+
*
|
|
1168
|
+
* @param {String} database - The db name.
|
|
1169
|
+
* @param {String} collection - The collection name.
|
|
1170
|
+
* @param {Object[]} indexSpecs the spec of the intexes to be created.
|
|
1171
|
+
* @param {Object} options - The command options.
|
|
1172
|
+
* @param {Object} dbOptions - The database options (i.e. readConcern, writeConcern. etc).
|
|
1173
|
+
* @return {Promise}
|
|
1174
|
+
*/
|
|
1175
|
+
async createIndexes(
|
|
1176
|
+
database: string,
|
|
1177
|
+
collection: string,
|
|
1178
|
+
indexSpecs: IndexDescription[],
|
|
1179
|
+
options: CreateIndexesOptions = {},
|
|
1180
|
+
dbOptions?: DbOptions
|
|
1181
|
+
): Promise<string[]> {
|
|
1182
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
1183
|
+
return this.db(database, dbOptions)
|
|
1184
|
+
.collection(collection)
|
|
1185
|
+
.createIndexes(indexSpecs, options);
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
/**
|
|
1189
|
+
* Returns an array that holds a list of documents that identify and
|
|
1190
|
+
* describe the existing indexes on the collection.
|
|
1191
|
+
*
|
|
1192
|
+
* @param {String} database - The db name.
|
|
1193
|
+
* @param {String} collection - The collection name.
|
|
1194
|
+
* @param options
|
|
1195
|
+
* @param {Object} dbOptions - The database options
|
|
1196
|
+
* (i.e. readConcern, writeConcern. etc).
|
|
1197
|
+
*
|
|
1198
|
+
* @return {Promise}
|
|
1199
|
+
*/
|
|
1200
|
+
async getIndexes(
|
|
1201
|
+
database: string,
|
|
1202
|
+
collection: string,
|
|
1203
|
+
options: ListIndexesOptions = {},
|
|
1204
|
+
dbOptions?: DbOptions
|
|
1205
|
+
): Promise<Document[]> {
|
|
1206
|
+
return await this.db(database, dbOptions)
|
|
1207
|
+
.collection(collection)
|
|
1208
|
+
.listIndexes({ ...this.baseCmdOptions, ...options })
|
|
1209
|
+
.toArray();
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
/**
|
|
1213
|
+
* Returns an array of collection infos
|
|
1214
|
+
*
|
|
1215
|
+
* @param {String} database - The db name.
|
|
1216
|
+
* @param {Document} filter - The filter.
|
|
1217
|
+
* @param {Document} options - The command options.
|
|
1218
|
+
* @param {Object} dbOptions - The database options
|
|
1219
|
+
* (i.e. readConcern, writeConcern. etc).
|
|
1220
|
+
*
|
|
1221
|
+
* @return {Promise}
|
|
1222
|
+
*/
|
|
1223
|
+
async listCollections(
|
|
1224
|
+
database: string,
|
|
1225
|
+
filter: Document = {},
|
|
1226
|
+
options: ListCollectionsOptions = {},
|
|
1227
|
+
dbOptions?: DbOptions
|
|
1228
|
+
): Promise<Document[]> {
|
|
1229
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
1230
|
+
return await this.db(database, dbOptions)
|
|
1231
|
+
.listCollections(filter, options)
|
|
1232
|
+
.toArray();
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
/**
|
|
1236
|
+
* Drops a the collection.
|
|
1237
|
+
*
|
|
1238
|
+
* @param {String} database - The db name.
|
|
1239
|
+
* @param {String} collection - The collection name.
|
|
1240
|
+
* @param options
|
|
1241
|
+
* @param {Object} dbOptions - The database options (i.e. readConcern, writeConcern. etc).
|
|
1242
|
+
*
|
|
1243
|
+
* @return {Promise}
|
|
1244
|
+
*/
|
|
1245
|
+
async dropCollection(
|
|
1246
|
+
database: string,
|
|
1247
|
+
collection: string,
|
|
1248
|
+
options: DropCollectionOptions = {},
|
|
1249
|
+
dbOptions?: DbOptions
|
|
1250
|
+
): Promise<boolean> {
|
|
1251
|
+
return this.db(database, dbOptions)
|
|
1252
|
+
.collection(collection)
|
|
1253
|
+
.drop({ ...this.baseCmdOptions, ...options });
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
/**
|
|
1257
|
+
* Authenticate
|
|
1258
|
+
*
|
|
1259
|
+
* @param authDoc
|
|
1260
|
+
*/
|
|
1261
|
+
async authenticate(authDoc: ShellAuthOptions): Promise<{ ok: 1 }> {
|
|
1262
|
+
// NOTE: we keep all the original options and just overwrite the auth ones.
|
|
1263
|
+
const auth: Auth = { username: authDoc.user, password: authDoc.pwd };
|
|
1264
|
+
await this.resetConnectionOptions({
|
|
1265
|
+
auth,
|
|
1266
|
+
...(authDoc.mechanism
|
|
1267
|
+
? { authMechanism: authDoc.mechanism as AuthMechanism }
|
|
1268
|
+
: {}),
|
|
1269
|
+
...(authDoc.authDb ? { authSource: authDoc.authDb } : {}),
|
|
1270
|
+
});
|
|
1271
|
+
return { ok: 1 };
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
async createCollection(
|
|
1275
|
+
dbName: string,
|
|
1276
|
+
collName: string,
|
|
1277
|
+
options: CreateCollectionOptions = {},
|
|
1278
|
+
dbOptions?: DbOptions
|
|
1279
|
+
): Promise<{ ok: number }> {
|
|
1280
|
+
options = { ...this.baseCmdOptions, ...options };
|
|
1281
|
+
await this.db(dbName, dbOptions).createCollection(collName, options);
|
|
1282
|
+
return { ok: 1 };
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
async createEncryptedCollection(
|
|
1286
|
+
dbName: string,
|
|
1287
|
+
collName: string,
|
|
1288
|
+
options: CreateEncryptedCollectionOptions,
|
|
1289
|
+
libmongocrypt: MongoCryptClientEncryption
|
|
1290
|
+
): Promise<{ collection: Collection; encryptedFields: Document }> {
|
|
1291
|
+
return await libmongocrypt.createEncryptedCollection(
|
|
1292
|
+
this.db(dbName),
|
|
1293
|
+
collName,
|
|
1294
|
+
options
|
|
1295
|
+
);
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
1299
|
+
async initializeBulkOp(
|
|
1300
|
+
dbName: string,
|
|
1301
|
+
collName: string,
|
|
1302
|
+
ordered: boolean,
|
|
1303
|
+
options: BulkWriteOptions = {},
|
|
1304
|
+
dbOptions?: DbOptions
|
|
1305
|
+
): Promise<any> {
|
|
1306
|
+
// Update to actual type after https://jira.mongodb.org/browse/MONGOSH-915
|
|
1307
|
+
if (ordered) {
|
|
1308
|
+
return this.db(dbName, dbOptions)
|
|
1309
|
+
.collection(collName)
|
|
1310
|
+
.initializeOrderedBulkOp(options);
|
|
1311
|
+
}
|
|
1312
|
+
return this.db(dbName, dbOptions)
|
|
1313
|
+
.collection(collName)
|
|
1314
|
+
.initializeUnorderedBulkOp(options);
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
getReadPreference(): ReadPreference {
|
|
1318
|
+
return this.mongoClient.readPreference;
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
getReadConcern(): ReadConcern | undefined {
|
|
1322
|
+
return this.mongoClient.readConcern;
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
getWriteConcern(): WriteConcern | undefined {
|
|
1326
|
+
return this.mongoClient.writeConcern;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
readPreferenceFromOptions(
|
|
1330
|
+
options?: Omit<ReadPreferenceFromOptions, 'session'>
|
|
1331
|
+
): ReadPreferenceLike | undefined {
|
|
1332
|
+
return ReadPreference.fromOptions(options);
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
/**
|
|
1336
|
+
* For instances where a user wants to set a option that requires a new MongoClient.
|
|
1337
|
+
*
|
|
1338
|
+
* @param options
|
|
1339
|
+
*/
|
|
1340
|
+
async resetConnectionOptions(options: MongoClientOptions): Promise<void> {
|
|
1341
|
+
this.bus.emit('mongosh-sp:reset-connection-options');
|
|
1342
|
+
this.currentClientOptions = {
|
|
1343
|
+
...this.currentClientOptions,
|
|
1344
|
+
...options,
|
|
1345
|
+
};
|
|
1346
|
+
const clientOptions = this.processDriverOptions(
|
|
1347
|
+
this.uri as ConnectionString,
|
|
1348
|
+
this.currentClientOptions
|
|
1349
|
+
);
|
|
1350
|
+
const { client, state } = await this.connectMongoClient(
|
|
1351
|
+
(this.uri as ConnectionString).toString(),
|
|
1352
|
+
clientOptions
|
|
1353
|
+
);
|
|
1354
|
+
try {
|
|
1355
|
+
await this.mongoClient.close();
|
|
1356
|
+
// eslint-disable-next-line no-empty
|
|
1357
|
+
} catch {}
|
|
1358
|
+
this.mongoClient = client;
|
|
1359
|
+
this.currentClientOptions.parentState = state;
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
startSession(options: ClientSessionOptions): ClientSession {
|
|
1363
|
+
return this.mongoClient.startSession(options);
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
watch(
|
|
1367
|
+
pipeline: Document[],
|
|
1368
|
+
options: ChangeStreamOptions,
|
|
1369
|
+
dbOptions: DbOptions = {},
|
|
1370
|
+
db?: string,
|
|
1371
|
+
coll?: string
|
|
1372
|
+
): ChangeStream<Document> {
|
|
1373
|
+
if (db === undefined && coll === undefined) {
|
|
1374
|
+
// TODO: watch not exported, see NODE-2934
|
|
1375
|
+
return (this.mongoClient as any).watch(pipeline, options);
|
|
1376
|
+
} else if (db !== undefined && coll === undefined) {
|
|
1377
|
+
return (this.db(db, dbOptions) as any).watch(pipeline, options);
|
|
1378
|
+
} else if (db !== undefined && coll !== undefined) {
|
|
1379
|
+
return (this.db(db, dbOptions).collection(coll) as any).watch(
|
|
1380
|
+
pipeline,
|
|
1381
|
+
options
|
|
1382
|
+
);
|
|
1383
|
+
}
|
|
1384
|
+
throw new MongoshInternalError(
|
|
1385
|
+
'Cannot call watch with defined collection but undefined db'
|
|
1386
|
+
);
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
get driverMetadata(): ClientMetadata | undefined {
|
|
1390
|
+
return this.getTopology()?.clientMetadata;
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
getRawClient(): MongoClient {
|
|
1394
|
+
return this.mongoClient;
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
getURI(): string | undefined {
|
|
1398
|
+
return this.uri?.href;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
getFleOptions(): AutoEncryptionOptions | undefined {
|
|
1402
|
+
return this.currentClientOptions.autoEncryption;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
// Internal, only exposed for testing
|
|
1406
|
+
static processDriverOptions(
|
|
1407
|
+
currentProviderInstance: NodeDriverServiceProvider | null,
|
|
1408
|
+
uri: ConnectionString,
|
|
1409
|
+
opts: DevtoolsConnectOptions
|
|
1410
|
+
): DevtoolsConnectOptions {
|
|
1411
|
+
const processedOptions = { ...DEFAULT_DRIVER_OPTIONS, ...opts };
|
|
1412
|
+
|
|
1413
|
+
if (currentProviderInstance?.currentClientOptions) {
|
|
1414
|
+
for (const key of ['productName', 'productDocsLink'] as const) {
|
|
1415
|
+
processedOptions[key] =
|
|
1416
|
+
currentProviderInstance.currentClientOptions[key];
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
processedOptions.oidc ??= {};
|
|
1420
|
+
for (const key of [
|
|
1421
|
+
'redirectURI',
|
|
1422
|
+
'openBrowser',
|
|
1423
|
+
'openBrowserTimeout',
|
|
1424
|
+
'notifyDeviceFlow',
|
|
1425
|
+
'allowedFlows',
|
|
1426
|
+
] as const) {
|
|
1427
|
+
// Template IIFE so that TS understands that `key` on the left-hand and right-hand side match
|
|
1428
|
+
(<T extends keyof typeof processedOptions.oidc>(key: T) => {
|
|
1429
|
+
const value =
|
|
1430
|
+
currentProviderInstance.currentClientOptions.oidc?.[key];
|
|
1431
|
+
if (value) {
|
|
1432
|
+
processedOptions.oidc[key] = value;
|
|
1433
|
+
}
|
|
1434
|
+
})(key);
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
if (
|
|
1439
|
+
processedOptions.parentState ||
|
|
1440
|
+
processedOptions.parentHandle ||
|
|
1441
|
+
!currentProviderInstance
|
|
1442
|
+
) {
|
|
1443
|
+
// Already set a parent state instance in the options explicitly,
|
|
1444
|
+
// or no state to inherit from a parent.
|
|
1445
|
+
return processedOptions;
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
const currentOpts = currentProviderInstance.currentClientOptions;
|
|
1449
|
+
const currentUri = currentProviderInstance.uri;
|
|
1450
|
+
if (
|
|
1451
|
+
currentUri &&
|
|
1452
|
+
isDeepStrictEqual(
|
|
1453
|
+
normalizeEndpointAndAuthConfiguration(currentUri, currentOpts),
|
|
1454
|
+
normalizeEndpointAndAuthConfiguration(uri, processedOptions)
|
|
1455
|
+
)
|
|
1456
|
+
) {
|
|
1457
|
+
if (currentOpts.parentState) {
|
|
1458
|
+
processedOptions.parentState = currentOpts.parentState;
|
|
1459
|
+
} else if (currentOpts.parentHandle) {
|
|
1460
|
+
processedOptions.parentHandle = currentOpts.parentHandle;
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
return processedOptions;
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
// Internal, only exposed for testing
|
|
1468
|
+
processDriverOptions(
|
|
1469
|
+
uri: ConnectionString,
|
|
1470
|
+
opts: Partial<DevtoolsConnectOptions>
|
|
1471
|
+
): DevtoolsConnectOptions {
|
|
1472
|
+
return NodeDriverServiceProvider.processDriverOptions(this, uri, {
|
|
1473
|
+
productName: this.currentClientOptions.productName,
|
|
1474
|
+
productDocsLink: this.currentClientOptions.productDocsLink,
|
|
1475
|
+
...opts,
|
|
1476
|
+
});
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
getSearchIndexes(
|
|
1480
|
+
database: string,
|
|
1481
|
+
collection: string,
|
|
1482
|
+
indexName?: string,
|
|
1483
|
+
// TODO(MONGOSH-1471): use ListSearchIndexesOptions once available
|
|
1484
|
+
options?: Document,
|
|
1485
|
+
dbOptions?: DbOptions
|
|
1486
|
+
): Promise<Document[]> {
|
|
1487
|
+
const col = this.db(database, dbOptions).collection(collection);
|
|
1488
|
+
if (indexName === undefined) {
|
|
1489
|
+
return col.listSearchIndexes(options).toArray();
|
|
1490
|
+
} else {
|
|
1491
|
+
return col.listSearchIndexes(indexName, options).toArray();
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
createSearchIndexes(
|
|
1496
|
+
database: string,
|
|
1497
|
+
collection: string,
|
|
1498
|
+
specs: SearchIndexDescription[],
|
|
1499
|
+
dbOptions?: DbOptions
|
|
1500
|
+
): Promise<string[]> {
|
|
1501
|
+
return this.db(database, dbOptions)
|
|
1502
|
+
.collection(collection)
|
|
1503
|
+
.createSearchIndexes(specs);
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
dropSearchIndex(
|
|
1507
|
+
database: string,
|
|
1508
|
+
collection: string,
|
|
1509
|
+
indexName: string,
|
|
1510
|
+
dbOptions?: DbOptions
|
|
1511
|
+
): Promise<void> {
|
|
1512
|
+
return this.db(database, dbOptions)
|
|
1513
|
+
.collection(collection)
|
|
1514
|
+
.dropSearchIndex(indexName);
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
updateSearchIndex(
|
|
1518
|
+
database: string,
|
|
1519
|
+
collection: string,
|
|
1520
|
+
indexName: string,
|
|
1521
|
+
definition: SearchIndexDescription,
|
|
1522
|
+
dbOptions?: DbOptions
|
|
1523
|
+
): Promise<void> {
|
|
1524
|
+
return this.db(database, dbOptions)
|
|
1525
|
+
.collection(collection)
|
|
1526
|
+
.updateSearchIndex(indexName, definition);
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
createClientEncryption(
|
|
1530
|
+
options: ClientEncryptionOptions
|
|
1531
|
+
): MongoCryptClientEncryption {
|
|
1532
|
+
return new ClientEncryption(this.mongoClient, options);
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
export { DevtoolsConnectOptions };
|