@@ -26,29 +26,37 @@ type MongoDBAutocompleterOptions = {
2626} ;
2727
2828class DatabaseSchema {
29- private collectionNames : string [ ] ;
29+ private collectionNames : Set < string > ;
3030 private collectionSchemas : Record < string , JSONSchema > ;
3131
3232 constructor ( ) {
33- this . collectionNames = [ ] ;
33+ // TODO: this is kinda the only real reason for this class: So we can keep
34+ // track of the known collectionNames for a database. It could be all the
35+ // names from a listCollections() or it could just be all the ones we've
36+ // auto-completed for. The schemas can come from the autocompletion context.
37+ // This can probably be added to the autocompletion context.
38+ this . collectionNames = new Set ( ) ;
3439 this . collectionSchemas = Object . create ( null ) ;
3540 }
3641
3742 setCollectionNames ( collectionNames : string [ ] ) : void {
38- this . collectionNames = collectionNames ;
43+ this . collectionNames = new Set ( collectionNames ) ;
3944 }
4045
4146 setCollectionSchema ( collectionName : string , schema : JSONSchema ) : void {
47+ this . collectionNames . add ( collectionName ) ;
4248 this . collectionSchemas [ collectionName ] = schema ;
4349 }
4450
4551 toTypescriptTypeDefinition ( ) : string {
46- const collectionProperties = this . collectionNames . map ( ( collectionName ) => {
47- const def = this . collectionSchemas [ collectionName ]
48- ? toTypescriptTypeDefinition ( this . collectionSchemas [ collectionName ] )
49- : `{}` ;
50- return ` '${ collectionName } ': ShellAPI.Collection<${ def } >;` ;
51- } ) ;
52+ const collectionProperties = [ ...this . collectionNames . values ( ) ] . map (
53+ ( collectionName ) => {
54+ const def = this . collectionSchemas [ collectionName ]
55+ ? toTypescriptTypeDefinition ( this . collectionSchemas [ collectionName ] )
56+ : `{}` ;
57+ return ` '${ collectionName } ': ShellAPI.Collection<${ def } >;` ;
58+ }
59+ ) ;
5260
5361 return `{
5462 ${ collectionProperties . join ( '\n' ) }
@@ -57,35 +65,28 @@ class DatabaseSchema {
5765}
5866
5967class ConnectionSchema {
60- private readonly databaseNames : string [ ] ;
61- private databaseName : string ;
68+ private readonly databaseNames : Set < string > ;
6269 private readonly databaseSchemas : Record < string , DatabaseSchema > ;
6370
6471 constructor ( ) {
65- this . databaseNames = [ ] ;
66- this . databaseName = 'test' ;
72+ // TODO: this is kinda the only real reason for this class: So we can keep
73+ // track of the known databaseNames for a connection. It could be all the
74+ // names from a listDatabases() or it could just be all the ones we've
75+ // auto-completed for. The schemas can come from the autocompletion context.
76+ // This can probably be added to the autocompletion context.
77+ this . databaseNames = new Set ( ) ;
6778 this . databaseSchemas = Object . create ( null ) ;
68-
69- this . addDatabase ( this . databaseName ) ;
70- }
71-
72- setDatabaseName ( databaseName : string ) {
73- this . databaseName = databaseName ;
74- }
75-
76- getCurrentDatabaseName ( ) : string {
77- return this . databaseName ;
7879 }
7980
8081 addDatabase ( databaseName : string ) {
81- this . databaseNames . push ( databaseName ) ;
82- this . databaseSchemas [ databaseName ] = new DatabaseSchema ( ) ;
82+ this . databaseNames . add ( databaseName ) ;
83+ if ( ! this . databaseSchemas [ databaseName ] ) {
84+ this . databaseSchemas [ databaseName ] = new DatabaseSchema ( ) ;
85+ }
8386 }
8487
8588 setDatabaseCollectionNames ( databaseName : string , collectionNames : string [ ] ) {
86- if ( ! this . databaseSchemas [ databaseName ] ) {
87- throw new Error ( `expected ${ databaseName } to be known` ) ;
88- }
89+ this . addDatabase ( databaseName ) ;
8990 this . databaseSchemas [ databaseName ] . setCollectionNames ( collectionNames ) ;
9091 }
9192
@@ -94,33 +95,38 @@ class ConnectionSchema {
9495 collectionName : string ,
9596 collectionSchema : JSONSchema
9697 ) {
97- if ( ! this . databaseSchemas [ databaseName ] ) {
98- throw new Error ( `expected ${ databaseName } to be known` ) ;
99- }
98+ this . addDatabase ( databaseName ) ;
10099 this . databaseSchemas [ databaseName ] . setCollectionSchema (
101100 collectionName ,
102101 collectionSchema
103102 ) ;
104103 }
105104
106105 toTypescriptTypeDefinition ( ) : string {
107- const databaseProperties = this . databaseNames . map ( ( databaseName ) => {
108- const def = this . databaseSchemas [ databaseName ]
109- ? this . databaseSchemas [ databaseName ] . toTypescriptTypeDefinition ( )
110- : `{}` ;
111- return ` '${ databaseName } ': ShellAPI.Database & ${ def } ` ;
112- } ) ;
106+ const databaseProperties = [ ...this . databaseNames . values ( ) ] . map (
107+ ( databaseName ) => {
108+ const def = this . databaseSchemas [ databaseName ]
109+ ? this . databaseSchemas [ databaseName ] . toTypescriptTypeDefinition ( )
110+ : `{}` ;
111+ return ` '${ databaseName } ': ShellAPI.Database & ${ def } ` ;
112+ }
113+ ) ;
113114
114115 return `{
115116 ${ databaseProperties . join ( '\n' ) }
116117}` ;
117118 }
118119}
119120
121+ type AutocompleteOptions = {
122+ connectionId : string ;
123+ databaseName : string ;
124+ position ?: number ;
125+ } ;
126+
120127export default class MongoDBAutocompleter {
121128 private readonly context : AutocompletionContext ;
122129 private connectionSchemas : Record < string , ConnectionSchema > ;
123- private currentConnectionKey : string | undefined ;
124130 private readonly autocompleter : Autocompleter ;
125131
126132 constructor ( { context, autocompleterOptions } : MongoDBAutocompleterOptions ) {
@@ -141,30 +147,11 @@ export default class MongoDBAutocompleter {
141147 this . autocompleter . updateCode ( { 'shell-api.d.ts' : loadShellAPI ( ) } ) ;
142148 }
143149
144- setConnectionKey ( connectionKey : string ) {
145- this . currentConnectionKey = connectionKey ;
146- this . connectionSchemas [ this . currentConnectionKey ] = new ConnectionSchema ( ) ;
147- this . autocompleter . updateCode ( {
148- [ `${ connectionKey } .d.ts` ] : this . getConnectionCode (
149- this . currentConnectionKey
150- ) ,
151- } ) ;
152-
153- // do we need this? it will be rewritten before auto-completing anyway
154- //this.autocompleter.updateCode({ 'current-globals.d.ts': this.getCurrentGlobalsCode() });
155- }
156-
157- setDatabaseName ( databaseName : string ) : void {
158- this . getActiveConnection ( ) . setDatabaseName ( databaseName ) ;
159- // do we need this? it will be rewritten before auto-completing anyway
160- //this.autocompleter.updateCode({ 'current-globals.d.ts': this.getCurrentGlobalsCode() });
161- }
162-
163- getActiveConnection ( ) : ConnectionSchema {
164- if ( ! this . currentConnectionKey ) {
165- throw new Error ( 'No active connection' ) ;
150+ addConnection ( connectionId : string ) : ConnectionSchema {
151+ if ( ! this . connectionSchemas [ connectionId ] ) {
152+ this . connectionSchemas [ connectionId ] = new ConnectionSchema ( ) ;
166153 }
167- return this . connectionSchemas [ this . currentConnectionKey ] ;
154+ return this . connectionSchemas [ connectionId ] ;
168155 }
169156
170157 getConnectionCode ( connectionKey : string ) : string {
@@ -183,20 +170,15 @@ declare global {
183170` ;
184171 }
185172
186- getCurrentGlobalsCode ( ) {
187- if ( ! this . currentConnectionKey ) {
188- throw new Error ( 'No active connection' ) ;
189- }
190-
191- const databaseName = this . getActiveConnection ( ) . getCurrentDatabaseName ( ) ;
173+ getCurrentGlobalsCode ( connectionId : string , databaseName : string ) {
192174 return `
193175/// <reference path="shell-api.d.ts" />
194- /// <reference path="${ this . currentConnectionKey } .d.ts" />
176+ /// <reference path="${ connectionId } .d.ts" />
195177
196178export {}; // turns this into an "external module"
197179
198180declare global {
199- type CurrentDatabaseSchema = Connection${ this . currentConnectionKey } .ServerSchema['${ databaseName } '];
181+ type CurrentDatabaseSchema = Connection${ connectionId } .ServerSchema['${ databaseName } '];
200182
201183 var db: CurrentDatabaseSchema;
202184 var use: (collection: string) => CurrentDatabaseSchema;
@@ -206,12 +188,8 @@ declare global {
206188
207189 async autocomplete (
208190 code : string ,
209- position ?: number
191+ { connectionId , databaseName , position } : AutocompleteOptions
210192 ) : Promise < AutoCompletion [ ] > {
211- if ( ! this . currentConnectionKey ) {
212- throw new Error ( 'No active connection' ) ;
213- }
214-
215193 if ( typeof position === 'undefined' ) {
216194 position = code . length ;
217195 }
@@ -237,40 +215,40 @@ declare global {
237215 [ ] ;
238216
239217 schema = await this . context . schemaInformationForAggregation (
240- this . currentConnectionKey ,
241- this . getActiveConnection ( ) . getCurrentDatabaseName ( ) ,
218+ connectionId ,
219+ databaseName ,
242220 collectionName ,
243221 pipelineToDryRun as Pipeline
244222 ) ;
245223 } else {
246224 schema = await this . context . schemaInformationForCollection (
247- this . currentConnectionKey ,
248- this . getActiveConnection ( ) . getCurrentDatabaseName ( ) ,
225+ connectionId ,
226+ databaseName ,
249227 collectionName
250228 ) ;
251229 }
252230
253- const activeConnection = this . getActiveConnection ( ) ;
254- const databaseName = this . getActiveConnection ( ) . getCurrentDatabaseName ( ) ;
255- activeConnection . addCollectionSchema ( databaseName , collectionName , schema ) ;
231+ const connection = this . addConnection ( connectionId ) ;
232+ connection . addCollectionSchema ( databaseName , collectionName , schema ) ;
256233
257234 const collectionNames = await this . context . collectionsForDatabase (
258- this . currentConnectionKey ,
235+ connectionId ,
259236 databaseName
260237 ) ;
261- activeConnection . setDatabaseCollectionNames ( databaseName , collectionNames ) ;
238+ connection . setDatabaseCollectionNames ( databaseName , collectionNames ) ;
262239
263240 // TODO: the problem with doing it this way is that, while the collection
264241 // schema might be cached, we'll be generating TypeScript for it (and every
265242 // other collection in the db and in fact every db in the server) every
266243 // time.
267244 this . autocompleter . updateCode ( {
268- [ `${ this . currentConnectionKey } .d.ts` ] : this . getConnectionCode (
269- this . currentConnectionKey
270- ) ,
245+ [ `${ connectionId } .d.ts` ] : this . getConnectionCode ( connectionId ) ,
271246 } ) ;
272247 this . autocompleter . updateCode ( {
273- 'current-globals.d.ts' : this . getCurrentGlobalsCode ( ) ,
248+ 'current-globals.d.ts' : this . getCurrentGlobalsCode (
249+ connectionId ,
250+ databaseName
251+ ) ,
274252 } ) ;
275253
276254 return this . autocompleter . autocomplete ( code , position ) ;
0 commit comments