Skip to content

Commit 75aac5f

Browse files
authored
chore(service-provider-node-driver): reduce reliance on driver internals MONGOSH-2620 (#2526)
1 parent 9cca331 commit 75aac5f

File tree

12 files changed

+146
-162
lines changed

12 files changed

+146
-162
lines changed

packages/browser-repl/src/sandbox.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,10 @@ class DemoServiceProvider {
106106
};
107107
}
108108

109-
getTopology(): object {
109+
getTopologyDescription(): object {
110110
return {
111-
description: {
112-
type: 'ReplicaSetWithPrimary',
113-
setName: 'replset',
114-
},
111+
type: 'ReplicaSetWithPrimary',
112+
setName: 'replset',
115113
};
116114
}
117115

packages/java-shell/src/main/kotlin/com/mongodb/mongosh/service/JavaServiceProvider.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ internal class JavaServiceProvider(private var client: MongoClient?,
443443
}
444444

445445
@HostAccess.Export
446-
override fun getTopology(): Value = promise<Any?> {
446+
override fun getTopologyDescription(): Value = promise<Any?> {
447447
Left(NotImplementedError())
448448
}
449449

packages/java-shell/src/main/kotlin/com/mongodb/mongosh/service/ReadableServiceProvider.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ internal interface ReadableServiceProvider {
1313
fun distinct(database: String, collection: String, fieldName: String, filter: Value?, options: Value?): Value
1414
fun estimatedDocumentCount(database: String, collection: String, options: Value?): Value
1515
fun find(database: String, collection: String, filter: Value?, options: Value?): Cursor
16-
fun getTopology(): Value
16+
fun getTopologyDescription(): Value
1717
fun getIndexes(database: String, collection: String, options: Value?): Value
1818
fun listCollections(database: String, filter: Value?, options: Value?): Value
1919
}

packages/service-provider-core/src/all-transport-types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ export type {
7171
ObjectId as ObjectIdType,
7272
Timestamp as TimestampType,
7373
Binary as BinaryType,
74-
TopologyDescription,
7574
TopologyType,
7675
ServerType,
7776
AutoEncryptionOptions,

packages/service-provider-core/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ export * from './all-fle-types';
1010

1111
export { MapReduceOptions, FinalizeFunction } from './map-reduce-options';
1212

13+
export { TopologyDescription, ServerDescription } from './readable';
14+
1315
export {
1416
CreateEncryptedCollectionOptions,
1517
CheckMetadataConsistencyOptions,

packages/service-provider-core/src/readable.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import type {
1111
DbOptions,
1212
ReadPreferenceFromOptions,
1313
ReadPreferenceLike,
14+
TopologyType,
15+
ServerType,
1416
} from './all-transport-types';
1517
import type { ChangeStreamOptions } from './all-transport-types';
1618
import type {
@@ -19,6 +21,17 @@ import type {
1921
ServiceProviderFindCursor,
2022
} from './cursors';
2123

24+
// These are trimmed-down versions of the MongoDB driver types
25+
export interface ServerDescription {
26+
type?: ServerType;
27+
setName?: string | null;
28+
}
29+
export interface TopologyDescription {
30+
type?: TopologyType;
31+
setName?: string | null;
32+
servers?: Map<string, ServerDescription>;
33+
}
34+
2235
/**
2336
* Interface for read operations in the CRUD specification.
2437
*/
@@ -160,7 +173,7 @@ export default interface Readable {
160173
/**
161174
* Get currently known topology information.
162175
*/
163-
getTopology(): any;
176+
getTopologyDescription(): TopologyDescription | undefined;
164177

165178
/**
166179
* Returns an array that holds a list of documents that identify and

packages/service-provider-node-driver/src/compass/compass-service-provider.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { DevtoolsConnectOptions } from '../node-driver-service-provider';
22
import { NodeDriverServiceProvider } from '../node-driver-service-provider';
3-
import type { MongoClient } from 'mongodb';
3+
import type { MongoClient, TopologyDescription } from 'mongodb';
44
import type { ReplPlatform } from '@mongosh/service-provider-core';
55
import type ConnectionString from 'mongodb-connection-string-url';
66
import type { EventEmitter } from 'events';
@@ -22,9 +22,10 @@ export class CompassServiceProvider extends NodeDriverServiceProvider {
2222
mongoClient: MongoClient,
2323
bus: EventEmitter,
2424
driverOptions: DevtoolsConnectOptions,
25-
uri?: ConnectionString
25+
uri?: ConnectionString,
26+
lastSeenTopology?: TopologyDescription
2627
) {
27-
super(mongoClient, bus, driverOptions, uri);
28+
super(mongoClient, bus, driverOptions, uri, lastSeenTopology);
2829
this.platform = 'Compass';
2930
}
3031
}

packages/service-provider-node-driver/src/node-driver-provider.integration.spec.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -807,12 +807,6 @@ describe('NodeDriverServiceProvider [integration]', function () {
807807
});
808808
});
809809

810-
describe('#driverMetadata', function () {
811-
it('returns information about the driver instance', function () {
812-
expect(serviceProvider.driverMetadata?.driver.name).to.equal('nodejs');
813-
});
814-
});
815-
816810
describe('#getURI', function () {
817811
it('returns the current URI', function () {
818812
expect(serviceProvider.getURI()).to.equal(connectionString);

packages/service-provider-node-driver/src/node-driver-service-provider.ts

Lines changed: 59 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type {
22
Auth,
33
AuthMechanism,
4-
ClientMetadata,
54
ReadPreferenceFromOptions,
65
ReadPreferenceLike,
76
OperationOptions,
@@ -242,18 +241,6 @@ export class NodeDriverServiceProvider
242241
let state: DevtoolsConnectionState | undefined;
243242
let lastSeenTopology: TopologyDescription | undefined;
244243

245-
class MongoshMongoClient extends MongoClientCtor {
246-
constructor(url: string, options?: MongoClientOptions) {
247-
super(url, options);
248-
this.on(
249-
'topologyDescriptionChanged',
250-
(evt: TopologyDescriptionChangedEvent) => {
251-
lastSeenTopology = evt.newDescription;
252-
}
253-
);
254-
}
255-
}
256-
257244
if (cliOptions.nodb) {
258245
const clientOptionsCopy: MongoClientOptions &
259246
Partial<DevtoolsConnectOptions> = {
@@ -266,16 +253,15 @@ export class NodeDriverServiceProvider
266253
delete clientOptionsCopy.parentState;
267254
delete clientOptionsCopy.proxy;
268255
delete clientOptionsCopy.applyProxyToOIDC;
269-
client = new MongoshMongoClient(
256+
client = new MongoClientCtor(
270257
connectionString.toString(),
271258
clientOptionsCopy
272259
);
273260
} else {
274-
({ client, state } = await connectMongoClient(
261+
({ client, state, lastSeenTopology } = await this.connectMongoClient(
275262
connectionString.toString(),
276263
clientOptions,
277-
bus,
278-
MongoshMongoClient
264+
bus
279265
));
280266
}
281267
clientOptions.parentState = state;
@@ -299,13 +285,13 @@ export class NodeDriverServiceProvider
299285
private bus: MongoshBus;
300286

301287
/**
302-
* Stores the last seen topology at the time when .connect() finishes.
288+
* Stores the last known topology for the MongoClient instance.
303289
*/
304290
private _lastSeenTopology: TopologyDescription | undefined;
305291

306292
/**
307293
* Instantiate a new NodeDriverServiceProvider with the Node driver's connected
308-
* MongoClient instance.
294+
* MongoClient instance. Do not call this directly, it is only public for testing.
309295
*
310296
* @param {MongoClient} mongoClient - The Node drivers' MongoClient instance.
311297
* @param {DevtoolsConnectOptions} clientOptions
@@ -326,13 +312,20 @@ export class NodeDriverServiceProvider
326312
this._lastSeenTopology = lastSeenTopology;
327313
this.platform = 'CLI';
328314
try {
329-
this.initialDb = (mongoClient as any).s.options.dbName || DEFAULT_DB;
315+
this.initialDb = mongoClient.options.dbName || DEFAULT_DB;
330316
} catch (err: any) {
331317
this.initialDb = DEFAULT_DB;
332318
}
333319
this.currentClientOptions = clientOptions;
334320
this.baseCmdOptions = { ...DEFAULT_BASE_OPTIONS }; // currently do not have any user-specified connection-wide command options, but I imagine we will eventually
335321
this.dbcache = new WeakMap();
322+
323+
this.mongoClient.on?.(
324+
'topologyDescriptionChanged',
325+
(evt: TopologyDescriptionChangedEvent) => {
326+
this._lastSeenTopology = evt.newDescription;
327+
}
328+
);
336329
}
337330

338331
static getVersionInformation(): DependencyVersionInfo {
@@ -355,7 +348,7 @@ export class NodeDriverServiceProvider
355348
};
356349
}
357350

358-
maybeThrowBetterMissingOptionalDependencyError(
351+
static maybeThrowBetterMissingOptionalDependencyError(
359352
err: MongoMissingDependencyError
360353
): never {
361354
if (err.message.includes('kerberos')) {
@@ -401,17 +394,37 @@ export class NodeDriverServiceProvider
401394
throw err;
402395
}
403396

404-
async connectMongoClient(
397+
private static async connectMongoClient(
405398
connectionString: ConnectionString | string,
406-
clientOptions: DevtoolsConnectOptions
407-
): Promise<{ client: MongoClient; state: DevtoolsConnectionState }> {
399+
clientOptions: DevtoolsConnectOptions,
400+
bus: MongoshBus
401+
): Promise<{
402+
client: MongoClient;
403+
state: DevtoolsConnectionState;
404+
lastSeenTopology: TopologyDescription | undefined;
405+
}> {
406+
let lastSeenTopology: TopologyDescription | undefined;
407+
408+
class MongoshMongoClient extends MongoClientCtor {
409+
constructor(url: string, options?: MongoClientOptions) {
410+
super(url, options);
411+
this.on(
412+
'topologyDescriptionChanged',
413+
(evt: TopologyDescriptionChangedEvent) => {
414+
lastSeenTopology = evt.newDescription;
415+
}
416+
);
417+
}
418+
}
419+
408420
try {
409-
return await connectMongoClient(
421+
const result = await connectMongoClient(
410422
connectionString.toString(),
411423
clientOptions,
412-
this.bus,
413-
MongoClientCtor
424+
bus,
425+
MongoshMongoClient
414426
);
427+
return { ...result, lastSeenTopology };
415428
} catch (err: unknown) {
416429
if (
417430
typeof err === 'object' &&
@@ -434,17 +447,19 @@ export class NodeDriverServiceProvider
434447
const connectionString = new ConnectionString(uri);
435448
const clientOptions = this.processDriverOptions(connectionString, options);
436449

437-
const { client, state } = await this.connectMongoClient(
438-
connectionString.toString(),
439-
clientOptions
440-
);
450+
const { client, state, lastSeenTopology } =
451+
await NodeDriverServiceProvider.connectMongoClient(
452+
connectionString.toString(),
453+
clientOptions,
454+
this.bus
455+
);
441456
clientOptions.parentState = state;
442457
return new NodeDriverServiceProvider(
443458
client,
444459
this.bus,
445460
clientOptions,
446461
connectionString,
447-
this._lastSeenTopology
462+
lastSeenTopology ?? this._lastSeenTopology
448463
);
449464
}
450465

@@ -1152,8 +1167,8 @@ export class NodeDriverServiceProvider
11521167
/**
11531168
* Get currently known topology information.
11541169
*/
1155-
getTopology(): any | undefined {
1156-
return (this.mongoClient as any).topology;
1170+
getTopologyDescription(): TopologyDescription | undefined {
1171+
return this._lastSeenTopology;
11571172
}
11581173

11591174
/**
@@ -1365,16 +1380,19 @@ export class NodeDriverServiceProvider
13651380
this.uri as ConnectionString,
13661381
this.currentClientOptions
13671382
);
1368-
const { client, state } = await this.connectMongoClient(
1369-
(this.uri as ConnectionString).toString(),
1370-
clientOptions
1371-
);
1383+
const { client, state, lastSeenTopology } =
1384+
await NodeDriverServiceProvider.connectMongoClient(
1385+
(this.uri as ConnectionString).toString(),
1386+
clientOptions,
1387+
this.bus
1388+
);
13721389
try {
13731390
await this.mongoClient.close();
13741391
// eslint-disable-next-line no-empty
13751392
} catch {}
13761393
this.mongoClient = client;
13771394
this.currentClientOptions.parentState = state;
1395+
if (lastSeenTopology) this._lastSeenTopology = lastSeenTopology;
13781396
}
13791397

13801398
startSession(options: ClientSessionOptions): ClientSession {
@@ -1389,25 +1407,17 @@ export class NodeDriverServiceProvider
13891407
coll?: string
13901408
): ChangeStream<Document> {
13911409
if (db === undefined && coll === undefined) {
1392-
// TODO: watch not exported, see NODE-2934
1393-
return (this.mongoClient as any).watch(pipeline, options);
1410+
return this.mongoClient.watch(pipeline, options);
13941411
} else if (db !== undefined && coll === undefined) {
1395-
return (this.db(db, dbOptions) as any).watch(pipeline, options);
1412+
return this.db(db, dbOptions).watch(pipeline, options);
13961413
} else if (db !== undefined && coll !== undefined) {
1397-
return (this.db(db, dbOptions).collection(coll) as any).watch(
1398-
pipeline,
1399-
options
1400-
);
1414+
return this.db(db, dbOptions).collection(coll).watch(pipeline, options);
14011415
}
14021416
throw new MongoshInternalError(
14031417
'Cannot call watch with defined collection but undefined db'
14041418
);
14051419
}
14061420

1407-
get driverMetadata(): ClientMetadata | undefined {
1408-
return this.getTopology()?.clientMetadata;
1409-
}
1410-
14111421
getRawClient(): MongoClient {
14121422
return this.mongoClient;
14131423
}

packages/shell-api/src/integration.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2568,11 +2568,11 @@ describe('Shell API (integration)', function () {
25682568
it('reconnects', async function () {
25692569
const oldMC = serviceProvider.mongoClient;
25702570
expect(
2571-
(serviceProvider.mongoClient as any).s.options.readPreference.mode
2571+
serviceProvider.mongoClient.options.readPreference.mode
25722572
).to.deep.equal('primary');
25732573
await mongo.setReadPref('secondaryPreferred');
25742574
expect(
2575-
(serviceProvider.mongoClient as any).s.options.readPreference.mode
2575+
serviceProvider.mongoClient.options.readPreference.mode
25762576
).to.equal('secondaryPreferred');
25772577
expect(serviceProvider.mongoClient).to.not.equal(oldMC);
25782578
});

0 commit comments

Comments
 (0)