Skip to content

Commit efa6e30

Browse files
authored
VSCODE-138: Quick index creation (#161)
1 parent 4332ae7 commit efa6e30

12 files changed

+397
-59
lines changed

package.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,18 @@
296296
"command": "mdb.copySchemaFieldName",
297297
"title": "Copy Field Name"
298298
},
299+
{
300+
"command": "mdb.refreshIndexes",
301+
"title": "Refresh"
302+
},
303+
{
304+
"command": "mdb.createIndexFromTreeView",
305+
"title": "Create New Index...",
306+
"icon": {
307+
"light": "images/light/plus-circle.svg",
308+
"dark": "images/dark/plus-circle.svg"
309+
}
310+
},
299311
{
300312
"command": "mdb.startStreamLanguageServerLogs",
301313
"title": "LSP Inspector: Start Stream LSP Logs"
@@ -462,6 +474,19 @@
462474
{
463475
"command": "mdb.copySchemaFieldName",
464476
"when": "view == mongoDB && viewItem == fieldTreeItem"
477+
},
478+
{
479+
"command": "mdb.createIndexFromTreeView",
480+
"when": "view == mongoDB && viewItem == indexListTreeItem",
481+
"group": "inline"
482+
},
483+
{
484+
"command": "mdb.refreshIndexes",
485+
"when": "view == mongoDB && viewItem == indexListTreeItem"
486+
},
487+
{
488+
"command": "mdb.createIndexFromTreeView",
489+
"when": "view == mongoDB && viewItem == indexListTreeItem"
465490
}
466491
],
467492
"editor/title": [
@@ -568,6 +593,14 @@
568593
"command": "mdb.runPlayground",
569594
"when": "false"
570595
},
596+
{
597+
"command": "mdb.createIndexFromTreeView",
598+
"when": "false"
599+
},
600+
{
601+
"command": "mdb.refreshIndexes",
602+
"when": "false"
603+
},
571604
{
572605
"command": "mdb.copySchemaFieldName",
573606
"when": "false"

src/editors/playgroundController.ts

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import PartialExecutionCodeLensProvider from './partialExecutionCodeLensProvider
99
import { OutputChannel, ProgressLocation, TextEditor } from 'vscode';
1010
import playgroundTemplate from '../templates/playgroundTemplate';
1111
import playgroundSearchTemplate from '../templates/playgroundSearchTemplate';
12+
import playgroundCreateIndexTemplate from '../templates/playgroundCreateIndexTemplate';
1213
import { createLogger } from '../logging';
1314

1415
const log = createLogger('playground controller');
@@ -96,7 +97,7 @@ export default class PlaygroundController {
9697
editor.textEditor.document &&
9798
editor.textEditor.document.languageId === 'mongodb'
9899
) {
99-
this._selectedText = (editor.selections as Array<any>)
100+
this._selectedText = (editor.selections as Array<vscode.Selection>)
100101
.sort((a, b) => (a.start.line > b.start.line ? 1 : -1)) // Sort lines selected as alt+click
101102
.map((item, index) => {
102103
if (index === editor.selections.length - 1) {
@@ -153,15 +154,10 @@ export default class PlaygroundController {
153154
return this._languageServerController.disconnectFromServiceProvider();
154155
}
155156

156-
public createPlaygroundForSearch(
157-
databaseName: string,
158-
collectionName: string
157+
private createPlaygroundFileWithContent(
158+
content: string | undefined
159159
): Promise<boolean> {
160160
return new Promise((resolve, reject) => {
161-
const content = playgroundSearchTemplate
162-
.replace('CURRENT_DATABASE', databaseName)
163-
.replace('CURRENT_COLLECTION', collectionName);
164-
165161
vscode.workspace
166162
.openTextDocument({
167163
language: 'mongodb',
@@ -175,6 +171,28 @@ export default class PlaygroundController {
175171
});
176172
}
177173

174+
public createPlaygroundForSearch(
175+
databaseName: string,
176+
collectionName: string
177+
): Promise<boolean> {
178+
const content = playgroundSearchTemplate
179+
.replace('CURRENT_DATABASE', databaseName)
180+
.replace('CURRENT_COLLECTION', collectionName);
181+
182+
return this.createPlaygroundFileWithContent(content);
183+
}
184+
185+
public createPlaygroundForNewIndex(
186+
databaseName: string,
187+
collectionName: string
188+
): Promise<boolean> {
189+
const content = playgroundCreateIndexTemplate
190+
.replace('CURRENT_DATABASE', databaseName)
191+
.replace('CURRENT_COLLECTION', collectionName);
192+
193+
return this.createPlaygroundFileWithContent(content);
194+
}
195+
178196
public createPlayground(): Promise<boolean> {
179197
const useDefaultTemplate = !!vscode.workspace
180198
.getConfiguration('mdb')
@@ -214,7 +232,7 @@ export default class PlaygroundController {
214232
return this._activeTextEditor?.document.getText() || '';
215233
}
216234

217-
private getSelectedText(selection: any): string {
235+
private getSelectedText(selection: vscode.Range): string {
218236
return this._activeTextEditor?.document.getText(selection) || '';
219237
}
220238

@@ -234,7 +252,7 @@ export default class PlaygroundController {
234252
cancellable: true
235253
},
236254
async (progress, token) => {
237-
token.onCancellationRequested(async () => {
255+
token.onCancellationRequested(() => {
238256
// If a user clicked the cancel button terminate all playground scripts.
239257
this._languageServerController.cancelAll();
240258
this._outputChannel.clear();
@@ -301,7 +319,7 @@ export default class PlaygroundController {
301319
});
302320
}
303321

304-
public runSelectedPlaygroundBlocks() {
322+
public runSelectedPlaygroundBlocks(): Promise<boolean> {
305323
if (this._activeTextEditor && this._activeTextEditor.document) {
306324
const selections = this._activeTextEditor.selections;
307325

@@ -324,7 +342,7 @@ export default class PlaygroundController {
324342
return this.evaluatePlayground();
325343
}
326344

327-
public runAllPlaygroundBlocks() {
345+
public runAllPlaygroundBlocks(): Promise<boolean> {
328346
if (this._activeTextEditor) {
329347
this._isPartialRun = false;
330348
this._codeToEvaluate = this.getAllText();
@@ -333,7 +351,7 @@ export default class PlaygroundController {
333351
return this.evaluatePlayground();
334352
}
335353

336-
public runAllOrSelectedPlaygroundBlocks() {
354+
public runAllOrSelectedPlaygroundBlocks(): Promise<boolean> {
337355
if (this._activeTextEditor && this._activeTextEditor.document) {
338356
const selections = this._activeTextEditor.selections;
339357

src/explorer/indexListTreeItem.ts

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as vscode from 'vscode';
22
const path = require('path');
33

44
import { createLogger } from '../logging';
5-
import IndexTreeItem from './indexTreeItem';
5+
import IndexTreeItem, { IndexModel } from './indexTreeItem';
66
import TreeItemParent from './treeItemParentInterface';
77
import { sortTreeItemsByLabel } from './treeItemUtils';
88
import { getImagesPath } from '../extensionConstants';
@@ -14,7 +14,7 @@ const ITEM_LABEL = 'Indexes';
1414
export default class IndexListTreeItem extends vscode.TreeItem
1515
implements TreeItemParent, vscode.TreeDataProvider<IndexListTreeItem> {
1616
cacheIsUpToDate = false;
17-
private _childrenCache: vscode.TreeItem[] = [];
17+
private _childrenCache: IndexTreeItem[] = [];
1818

1919
contextValue = 'indexListTreeItem';
2020

@@ -32,7 +32,7 @@ export default class IndexListTreeItem extends vscode.TreeItem
3232
dataService: any,
3333
isExpanded: boolean,
3434
cacheIsUpToDate: boolean,
35-
existingCache: vscode.TreeItem[]
35+
existingCache: IndexTreeItem[]
3636
) {
3737
super(
3838
ITEM_LABEL,
@@ -61,7 +61,7 @@ export default class IndexListTreeItem extends vscode.TreeItem
6161
return element;
6262
}
6363

64-
getIndexes(): Promise<any> {
64+
getIndexes(): Promise<IndexModel[]> {
6565
const namespace = this.namespace;
6666

6767
log.info(`fetching indexes from namespace ${namespace}`);
@@ -72,7 +72,7 @@ export default class IndexListTreeItem extends vscode.TreeItem
7272
{
7373
/* No options */
7474
},
75-
(err: Error, indexes: any[]) => {
75+
(err: Error, indexes: IndexModel[]) => {
7676
if (err) {
7777
return reject(err);
7878
}
@@ -89,6 +89,20 @@ export default class IndexListTreeItem extends vscode.TreeItem
8989
}
9090

9191
if (this.cacheIsUpToDate) {
92+
const pastChildrenCache = this._childrenCache;
93+
this._childrenCache = [];
94+
95+
// We manually rebuild each node to ensure we update the expanded state.
96+
pastChildrenCache.forEach((cachedItem: IndexTreeItem) => {
97+
this._childrenCache.push(
98+
new IndexTreeItem(
99+
cachedItem.index,
100+
cachedItem.namespace,
101+
cachedItem.isExpanded
102+
)
103+
);
104+
});
105+
92106
return this._childrenCache;
93107
}
94108

@@ -100,10 +114,10 @@ export default class IndexListTreeItem extends vscode.TreeItem
100114
const namespace = this.namespace;
101115

102116
this._childrenCache = sortTreeItemsByLabel(
103-
indexes.map((index) => {
104-
return new IndexTreeItem(index, namespace);
117+
indexes.map((index: IndexModel) => {
118+
return new IndexTreeItem(index, namespace, false /* Not expanded. */);
105119
})
106-
);
120+
) as IndexTreeItem[];
107121
} else {
108122
this._childrenCache = [];
109123
}
@@ -123,14 +137,19 @@ export default class IndexListTreeItem extends vscode.TreeItem
123137
return Promise.resolve(true);
124138
}
125139

126-
getChildrenCache(): vscode.TreeItem[] {
140+
getChildrenCache(): IndexTreeItem[] {
127141
if (this.cacheIsUpToDate) {
128142
return this._childrenCache;
129143
}
130144

131145
return [];
132146
}
133147

148+
resetCache(): void {
149+
this.cacheIsUpToDate = false;
150+
this._childrenCache = [];
151+
}
152+
134153
get iconPath():
135154
| string
136155
| vscode.Uri

src/explorer/indexTreeItem.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as vscode from 'vscode';
22
const path = require('path');
33

44
import { getImagesPath } from '../extensionConstants';
5+
import TreeItemParent from './treeItemParentInterface';
56

67
export enum IndexKeyType {
78
ASCENDING = 1,
@@ -13,7 +14,7 @@ export enum IndexKeyType {
1314
GEOHAYSTACK = 'geoHaystack'
1415
}
1516

16-
type IndexModel = {
17+
export type IndexModel = {
1718
v: number;
1819
key: {
1920
[key: string]: IndexKeyType;
@@ -91,10 +92,10 @@ export class IndexFieldTreeItem extends vscode.TreeItem
9192
}
9293

9394
export default class IndexTreeItem extends vscode.TreeItem
94-
implements vscode.TreeDataProvider<IndexTreeItem> {
95+
implements vscode.TreeDataProvider<IndexTreeItem>, TreeItemParent {
9596
contextValue = 'indexTreeItem';
9697

97-
private index: IndexModel;
98+
index: IndexModel;
9899

99100
namespace: string;
100101

@@ -103,14 +104,24 @@ export default class IndexTreeItem extends vscode.TreeItem
103104
// asynchronous resources.
104105
doesNotRequireTreeUpdate = true;
105106

106-
constructor(index: IndexModel, namespace: string) {
107-
super(index.name, vscode.TreeItemCollapsibleState.Collapsed);
107+
isExpanded: boolean;
108+
cacheIsUpToDate = true;
109+
110+
constructor(index: IndexModel, namespace: string, isExpanded: boolean) {
111+
super(
112+
index.name,
113+
isExpanded
114+
? vscode.TreeItemCollapsibleState.Expanded
115+
: vscode.TreeItemCollapsibleState.Collapsed
116+
);
108117

109118
this.index = index;
110119

111120
this.namespace = namespace;
112121

113122
this.id = `${index.name}-${namespace}`;
123+
124+
this.isExpanded = isExpanded;
114125
}
115126

116127
get tooltip(): string {
@@ -132,4 +143,14 @@ export default class IndexTreeItem extends vscode.TreeItem
132143
)
133144
);
134145
}
146+
147+
onDidCollapse(): void {
148+
this.isExpanded = false;
149+
}
150+
151+
onDidExpand(): Promise<boolean> {
152+
this.isExpanded = true;
153+
154+
return Promise.resolve(true);
155+
}
135156
}

src/mdbExtensionController.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import DocumentListTreeItem from './explorer/documentListTreeItem';
2121
import DocumentTreeItem from './explorer/documentTreeItem';
2222
import WebviewController from './views/webviewController';
2323
import FieldTreeItem from './explorer/fieldTreeItem';
24+
import IndexListTreeItem from './explorer/indexListTreeItem';
2425

2526
const log = createLogger('commands');
2627

@@ -272,20 +273,11 @@ export default class MDBExtensionController implements vscode.Disposable {
272273
);
273274
this.registerCommand(
274275
'mdb.searchForDocuments',
275-
async (element: DocumentListTreeItem): Promise<boolean> => {
276-
if (this._connectionController.isDisconnecting()) {
277-
vscode.window.showErrorMessage(
278-
'Unable to add collection: currently disconnecting.'
279-
);
280-
return false;
281-
}
282-
283-
this._playgroundController.createPlaygroundForSearch(
276+
(element: DocumentListTreeItem): Promise<boolean> => {
277+
return this._playgroundController.createPlaygroundForSearch(
284278
element.databaseName,
285279
element.collectionName
286280
);
287-
288-
return true;
289281
}
290282
);
291283
this.registerCommand(
@@ -421,6 +413,22 @@ export default class MDBExtensionController implements vscode.Disposable {
421413
return true;
422414
}
423415
);
416+
this.registerCommand(
417+
'mdb.refreshIndexes',
418+
(indexListTreeItem: IndexListTreeItem): Promise<boolean> => {
419+
indexListTreeItem.resetCache();
420+
return this._explorerController.refresh();
421+
}
422+
);
423+
this.registerCommand(
424+
'mdb.createIndexFromTreeView',
425+
(indexListTreeItem: IndexListTreeItem): Promise<boolean> => {
426+
return this._playgroundController.createPlaygroundForNewIndex(
427+
indexListTreeItem.databaseName,
428+
indexListTreeItem.collectionName
429+
);
430+
}
431+
);
424432
}
425433

426434
dispose(): void {

0 commit comments

Comments
 (0)