11import type {
22 ServiceProvider ,
3- ServiceProviderAnyCursor ,
43 ServiceProviderAbstractCursor ,
54} from '@mongosh/service-provider-core' ;
65import { ServiceProviderCore } from '@mongosh/service-provider-core' ;
6+ import type { InspectOptions , inspect as _inspect } from 'util' ;
7+ import type { Document } from '@mongosh/service-provider-core' ;
78
89export class DeepInspectServiceProviderWrapper
910 extends ServiceProviderCore
@@ -24,26 +25,28 @@ export class DeepInspectServiceProviderWrapper
2425
2526 aggregate = cursorMethod ( 'aggregate' ) ;
2627 aggregateDb = cursorMethod ( 'aggregateDb' ) ;
27- count = bsonMethod ( 'count' ) ;
28- estimatedDocumentCount = bsonMethod ( 'estimatedDocumentCount' ) ;
29- countDocuments = bsonMethod ( 'countDocuments' ) ;
28+ count = forwardedMethod ( 'count' ) ;
29+ estimatedDocumentCount = forwardedMethod ( 'estimatedDocumentCount' ) ;
30+ countDocuments = forwardedMethod ( 'countDocuments' ) ;
3031 distinct = bsonMethod ( 'distinct' ) ;
3132 find = cursorMethod ( 'find' ) ;
3233 findOneAndDelete = bsonMethod ( 'findOneAndDelete' ) ;
3334 findOneAndReplace = bsonMethod ( 'findOneAndReplace' ) ;
3435 findOneAndUpdate = bsonMethod ( 'findOneAndUpdate' ) ;
35- getTopology = forwardedMethod ( 'getTopology ' ) ;
36+ getTopologyDescription = forwardedMethod ( 'getTopologyDescription ' ) ;
3637 getIndexes = bsonMethod ( 'getIndexes' ) ;
3738 listCollections = bsonMethod ( 'listCollections' ) ;
3839 readPreferenceFromOptions = forwardedMethod ( 'readPreferenceFromOptions' ) ;
39- watch = cursorMethod ( 'watch' ) ;
40+ // TODO: this should be a cursor method, but the types are incompatible
41+ watch = forwardedMethod ( 'watch' ) ;
4042 getSearchIndexes = bsonMethod ( 'getSearchIndexes' ) ;
4143 runCommand = bsonMethod ( 'runCommand' ) ;
4244 runCommandWithCheck = bsonMethod ( 'runCommandWithCheck' ) ;
4345 runCursorCommand = cursorMethod ( 'runCursorCommand' ) ;
4446 dropDatabase = bsonMethod ( 'dropDatabase' ) ;
45- dropCollection = bsonMethod ( 'dropCollection' ) ;
47+ dropCollection = forwardedMethod ( 'dropCollection' ) ;
4648 bulkWrite = bsonMethod ( 'bulkWrite' ) ;
49+ clientBulkWrite = bsonMethod ( 'clientBulkWrite' ) ;
4750 deleteMany = bsonMethod ( 'deleteMany' ) ;
4851 updateMany = bsonMethod ( 'updateMany' ) ;
4952 updateOne = bsonMethod ( 'updateOne' ) ;
@@ -53,15 +56,15 @@ export class DeepInspectServiceProviderWrapper
5356 insertOne = bsonMethod ( 'insertOne' ) ;
5457 replaceOne = bsonMethod ( 'replaceOne' ) ;
5558 initializeBulkOp = bsonMethod ( 'initializeBulkOp' ) ;
56- createSearchIndexes = bsonMethod ( 'createSearchIndexes' ) ;
59+ createSearchIndexes = forwardedMethod ( 'createSearchIndexes' ) ;
5760 close = forwardedMethod ( 'close' ) ;
5861 suspend = forwardedMethod ( 'suspend' ) ;
59- renameCollection = bsonMethod ( 'renameCollection' ) ;
60- dropSearchIndex = bsonMethod ( 'dropSearchIndex' ) ;
61- updateSearchIndex = bsonMethod ( 'updateSearchIndex' ) ;
62+ renameCollection = forwardedMethod ( 'renameCollection' ) ;
63+ dropSearchIndex = forwardedMethod ( 'dropSearchIndex' ) ;
64+ updateSearchIndex = forwardedMethod ( 'updateSearchIndex' ) ;
6265 listDatabases = bsonMethod ( 'listDatabases' ) ;
63- authenticate = bsonMethod ( 'authenticate' ) ;
64- createCollection = bsonMethod ( 'createCollection' ) ;
66+ authenticate = forwardedMethod ( 'authenticate' ) ;
67+ createCollection = forwardedMethod ( 'createCollection' ) ;
6568 getReadPreference = forwardedMethod ( 'getReadPreference' ) ;
6669 getReadConcern = forwardedMethod ( 'getReadConcern' ) ;
6770 getWriteConcern = forwardedMethod ( 'getWriteConcern' ) ;
@@ -72,6 +75,7 @@ export class DeepInspectServiceProviderWrapper
7275 get initialDb ( ) {
7376 return this . _sp . initialDb ;
7477 }
78+
7579 getURI = forwardedMethod ( 'getURI' ) ;
7680 getConnectionInfo = forwardedMethod ( 'getConnectionInfo' ) ;
7781 resetConnectionOptions = forwardedMethod ( 'resetConnectionOptions' ) ;
@@ -84,20 +88,11 @@ export class DeepInspectServiceProviderWrapper
8488 async getNewConnection (
8589 ...args : Parameters < ServiceProvider [ 'getNewConnection' ] >
8690 ) : Promise < ServiceProvider > {
87- return new DeepInspectServiceProviderWrapper (
88- await this . _sp . getNewConnection ( ...args )
89- ) ;
91+ const sp = await this . _sp . getNewConnection ( ...args ) ;
92+ return new DeepInspectServiceProviderWrapper ( sp as ServiceProvider ) ;
9093 }
9194}
9295
93- const cursorBsonMethods : ( keyof Partial < ServiceProviderAnyCursor > ) [ ] = [
94- 'next' ,
95- 'tryNext' ,
96- 'readBufferedDocuments' ,
97- 'toArray' ,
98- '' ,
99- ] ;
100-
10196type PickMethodsByReturnType < T , R > = {
10297 [ k in keyof T as NonNullable < T [ k ] > extends ( ...args : any [ ] ) => R
10398 ? k
@@ -107,33 +102,104 @@ type PickMethodsByReturnType<T, R> = {
107102function cursorMethod <
108103 K extends keyof PickMethodsByReturnType <
109104 ServiceProvider ,
110- ServiceProviderAnyCursor
105+ ServiceProviderAbstractCursor
111106 >
112107> (
113108 key : K
114109) : (
115110 ...args : Parameters < Required < ServiceProvider > [ K ] >
116111) => ReturnType < Required < ServiceProvider > [ K ] > {
117112 return function (
118- this : ServiceProvider ,
113+ this : DeepInspectServiceProviderWrapper ,
119114 ...args : Parameters < ServiceProvider [ K ] >
120115 ) : ReturnType < ServiceProvider [ K ] > {
121- return this [ key ] ( ...args ) ;
116+ // The problem here is that ReturnType<ServiceProvider[K]> results in
117+ // ServiceProviderAnyCursor which includes ServiceProviderChangeStream which
118+ // doesn't have readBufferedDocuments or toArray. We can try cast things to
119+ // ServiceProviderAbstractCursor, but then that's not assignable to
120+ // ServiceProviderAnyCursor. And that's why there's so much casting below.
121+ const cursor = ( this . _sp [ key ] as any ) ( ...args ) as any ;
122+
123+ cursor . next = cursorNext (
124+ cursor . next . bind ( cursor ) as ( ) => Promise < Document | null >
125+ ) ;
126+ cursor . tryNext = cursorTryNext (
127+ cursor . tryNext . bind ( cursor ) as ( ) => Promise < Document | null >
128+ ) ;
129+
130+ if ( cursor . readBufferedDocuments ) {
131+ cursor . readBufferedDocuments = cursorReadBufferedDocuments (
132+ cursor . readBufferedDocuments . bind ( cursor ) as (
133+ number ?: number
134+ ) => Document [ ]
135+ ) ;
136+ }
137+ if ( cursor . toArray ) {
138+ cursor . toArray = cursorToArray (
139+ cursor . toArray . bind ( cursor ) as ( ) => Promise < Document [ ] >
140+ ) ;
141+ }
142+
143+ return cursor ;
144+ } ;
145+ }
146+
147+ const customInspectSymbol = Symbol . for ( 'nodejs.util.inspect.custom' ) ;
148+
149+ function cursorNext (
150+ original : ( ) => Promise < Document | null >
151+ ) : ( ) => Promise < Document | null > {
152+ return async function ( ) : Promise < Document | null > {
153+ const result = await original ( ) ;
154+ if ( result ) {
155+ replaceWithCustomInspect ( result ) ;
156+ }
157+ return result ;
158+ } ;
159+ }
160+
161+ const cursorTryNext = cursorNext ;
162+
163+ function cursorReadBufferedDocuments (
164+ original : ( number ?: number ) => Document [ ]
165+ ) : ( number ?: number ) => Document [ ] {
166+ return function ( number ?: number ) : Document [ ] {
167+ const results = original ( number ) ;
168+
169+ replaceWithCustomInspect ( results ) ;
170+
171+ return results ;
172+ } ;
173+ }
174+
175+ function cursorToArray (
176+ original : ( ) => Promise < Document [ ] >
177+ ) : ( ) => Promise < Document [ ] > {
178+ return async function ( ) : Promise < Document [ ] > {
179+ const results = await original ( ) ;
180+
181+ replaceWithCustomInspect ( results ) ;
182+
183+ return results ;
122184 } ;
123185}
124186
125187function bsonMethod <
126- K extends keyof PickMethodsByReturnType < ServiceProvider , any >
188+ K extends keyof PickMethodsByReturnType < ServiceProvider , Promise < any > >
127189> (
128190 key : K
129191) : (
130192 ...args : Parameters < Required < ServiceProvider > [ K ] >
131193) => ReturnType < Required < ServiceProvider > [ K ] > {
132- return function (
133- this : ServiceProvider ,
194+ return async function (
195+ this : DeepInspectServiceProviderWrapper ,
134196 ...args : Parameters < Required < ServiceProvider > [ K ] >
135- ) : ReturnType < Required < ServiceProvider > [ K ] > {
136- return this [ key ] ( ...args ) ;
197+ ) : // eslint-disable-next-line @typescript-eslint/ban-ts-comment
198+ // @ts -ignore The returntype already contains a promise
199+ ReturnType < Required < ServiceProvider > [ K ] > {
200+ const result = await ( this . _sp [ key ] as any ) ( ...args ) ;
201+ replaceWithCustomInspect ( result ) ;
202+ return result ;
137203 } ;
138204}
139205
@@ -145,9 +211,47 @@ function forwardedMethod<
145211 ...args : Parameters < Required < ServiceProvider > [ K ] >
146212) => ReturnType < Required < ServiceProvider > [ K ] > {
147213 return function (
148- this : ServiceProvider ,
214+ this : DeepInspectServiceProviderWrapper ,
149215 ...args : Parameters < Required < ServiceProvider > [ K ] >
150216 ) : ReturnType < Required < ServiceProvider > [ K ] > {
151- return this [ key ] ( ...args ) ;
217+ // not wrapping the result at all because forwardedMethod() is for simple
218+ // values only
219+ return ( this . _sp [ key ] as any ) ( ...args ) ;
152220 } ;
153221}
222+
223+ function customDocumentInspect (
224+ this : Document ,
225+ depth : number ,
226+ inspectOptions : InspectOptions ,
227+ inspect : typeof _inspect
228+ ) {
229+ const newInspectOptions = {
230+ ...inspectOptions ,
231+ depth : Infinity ,
232+ maxArrayLength : Infinity ,
233+ maxStringLength : Infinity ,
234+ } ;
235+
236+ // reuse the standard inpect logic for an object without causing infinite
237+ // recursion
238+ const inspectBackup = ( this as any ) [ customInspectSymbol ] ;
239+ delete ( this as any ) [ customInspectSymbol ] ;
240+ const result = inspect ( this , newInspectOptions ) ;
241+ ( this as any ) [ customInspectSymbol ] = inspectBackup ;
242+ return result ;
243+ }
244+
245+ function replaceWithCustomInspect ( obj : any ) {
246+ if ( Array . isArray ( obj ) ) {
247+ ( obj as any ) [ customInspectSymbol ] = customDocumentInspect ;
248+ for ( const item of obj ) {
249+ replaceWithCustomInspect ( item ) ;
250+ }
251+ } else if ( obj && typeof obj === 'object' && obj !== null ) {
252+ obj [ customInspectSymbol ] = customDocumentInspect ;
253+ for ( const value of Object . values ( obj ) ) {
254+ replaceWithCustomInspect ( value ) ;
255+ }
256+ }
257+ }
0 commit comments