diff --git a/images/dark/search-regular.svg b/images/dark/search-regular.svg new file mode 100644 index 000000000..a562d60b7 --- /dev/null +++ b/images/dark/search-regular.svg @@ -0,0 +1,4 @@ + diff --git a/images/light/search-regular.svg b/images/light/search-regular.svg new file mode 100644 index 000000000..e4b460efb --- /dev/null +++ b/images/light/search-regular.svg @@ -0,0 +1,4 @@ + diff --git a/package.json b/package.json index 1eb7be226..b66ce72fc 100644 --- a/package.json +++ b/package.json @@ -228,6 +228,14 @@ "dark": "images/dark/plus-circle.svg" } }, + { + "command": "mdb.searchForDocuments", + "title": "Search For Documents...", + "icon": { + "light": "images/light/search-regular.svg", + "dark": "images/dark/search-regular.svg" + } + }, { "command": "mdb.connectToConnectionTreeItem", "title": "Connect" @@ -427,13 +435,25 @@ "when": "view == mongoDB && viewItem == collectionTreeItem", "group": "3@1" }, + { + "command": "mdb.searchForDocuments", + "when": "view == mongoDB && viewItem == documentListTreeItem", + "group": "inline" + }, { "command": "mdb.viewCollectionDocuments", - "when": "view == mongoDB && viewItem == documentListTreeItem" + "when": "view == mongoDB && viewItem == documentListTreeItem", + "group": "1@1" }, { "command": "mdb.refreshDocumentList", - "when": "view == mongoDB && viewItem == documentListTreeItem" + "when": "view == mongoDB && viewItem == documentListTreeItem", + "group": "1@2" + }, + { + "command": "mdb.searchForDocuments", + "when": "view == mongoDB && viewItem == documentListTreeItem", + "group": "2@1" }, { "command": "mdb.refreshSchema", @@ -452,6 +472,10 @@ } ], "commandPalette": [ + { + "command": "mdb.searchForDocuments", + "when": "false" + }, { "command": "mdb.addConnection", "when": "false" diff --git a/src/editors/playgroundController.ts b/src/editors/playgroundController.ts index 078c89644..35d6a309e 100644 --- a/src/editors/playgroundController.ts +++ b/src/editors/playgroundController.ts @@ -8,6 +8,7 @@ import ActiveConnectionCodeLensProvider from './activeConnectionCodeLensProvider import PartialExecutionCodeLensProvider from './partialExecutionCodeLensProvider'; import { OutputChannel, ProgressLocation, TextEditor } from 'vscode'; import playgroundTemplate from '../templates/playgroundTemplate'; +import playgroundSearchTemplate from '../templates/playgroundSearchTemplate'; import { createLogger } from '../logging'; const log = createLogger('playground controller'); @@ -152,6 +153,28 @@ export default class PlaygroundController { return this._languageServerController.disconnectFromServiceProvider(); } + public createPlaygroundForSearch( + databaseName: string, + collectionName: string + ): Promise { + return new Promise((resolve, reject) => { + const content = playgroundSearchTemplate + .replace('CURRENT_DATABASE', databaseName) + .replace('CURRENT_COLLECTION', collectionName); + + vscode.workspace + .openTextDocument({ + language: 'mongodb', + content + }) + .then((document) => { + this._outputChannel.show(true); + vscode.window.showTextDocument(document); + resolve(true); + }, reject); + }); + } + public createPlayground(): Promise { const useDefaultTemplate = !!vscode.workspace .getConfiguration('mdb') diff --git a/src/explorer/explorerTreeController.ts b/src/explorer/explorerTreeController.ts index ae6583517..a8a820579 100644 --- a/src/explorer/explorerTreeController.ts +++ b/src/explorer/explorerTreeController.ts @@ -4,19 +4,15 @@ import ConnectionController, { DataServiceEventTypes } from '../connectionController'; import { DOCUMENT_ITEM } from './documentTreeItem'; -import ConnectionTreeItem from './connectionTreeItem'; -import DatabaseTreeItem from './databaseTreeItem'; -import CollectionTreeItem from './collectionTreeItem'; import MDBConnectionsTreeItem from './mdbConnectionsTreeItem'; import { createLogger } from '../logging'; import { DOCUMENT_LIST_ITEM, CollectionTypes } from './documentListTreeItem'; -import TreeItemParentInterface from './treeItemParentInterface'; const log = createLogger('explorer controller'); export default class ExplorerTreeController -implements vscode.TreeDataProvider { + implements vscode.TreeDataProvider { private _connectionController: ConnectionController; private _mdbConnectionsTreeItem: MDBConnectionsTreeItem; @@ -140,11 +136,7 @@ implements vscode.TreeDataProvider { return element; } - getChildren( - element?: any - ): Thenable< - | any[] - > { + getChildren(element?: any): Thenable { // When no element is present we are at the root. if (!element) { // We rebuild the connections tree each time in order to diff --git a/src/language/mongoDBService.ts b/src/language/mongoDBService.ts index eb4ad651d..9c7b31857 100644 --- a/src/language/mongoDBService.ts +++ b/src/language/mongoDBService.ts @@ -342,8 +342,8 @@ export default class MongoDBService { // ------ COMPLETION ------ // - // Check if string is a valid property name - private isValidPropertyName(str): boolean { + // Check if a string is a valid property name. + private isValidPropertyName(str: string): boolean { return /^(?![0-9])[a-zA-Z0-9$_]+$/.test(str); } diff --git a/src/mdbExtensionController.ts b/src/mdbExtensionController.ts index d5d71d545..6156af050 100644 --- a/src/mdbExtensionController.ts +++ b/src/mdbExtensionController.ts @@ -270,6 +270,24 @@ export default class MDBExtensionController implements vscode.Disposable { return successfullyAddedDatabase; } ); + this.registerCommand( + 'mdb.searchForDocuments', + async (element: DocumentListTreeItem): Promise => { + if (this._connectionController.isDisconnecting()) { + vscode.window.showErrorMessage( + 'Unable to add collection: currently disconnecting.' + ); + return false; + } + + this._playgroundController.createPlaygroundForSearch( + element.databaseName, + element.collectionName + ); + + return true; + } + ); this.registerCommand( 'mdb.copyDatabaseName', async (element: DatabaseTreeItem) => { diff --git a/src/templates/playgroundSearchTemplate.ts b/src/templates/playgroundSearchTemplate.ts new file mode 100644 index 000000000..438cacc86 --- /dev/null +++ b/src/templates/playgroundSearchTemplate.ts @@ -0,0 +1,32 @@ +const template: string = `// MongoDB Playground +// Use Ctrl+Space inside a snippet or a string literal to trigger completions. + +// The current database to use. +use('CURRENT_DATABASE'); + +// Search for documents in the current collection. +db.getCollection('CURRENT_COLLECTION') + .find( + { + /* + * Filter + * fieldA: value or expression + */ + }, + { + /* + * Projection + * _id: 0, // exclude _id + * fieldA: 1 // include field + */ + } + ) + .sort({ + /* + * fieldA: 1 // ascending + * fieldB: -1 // descending + */ + }); +`; + +export default template; diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index a93014ef4..60753c27a 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -54,6 +54,7 @@ suite('Extension Test Suite', () => { 'mdb.addCollection', 'mdb.viewCollectionDocuments', 'mdb.refreshDocumentList', + 'mdb.searchForDocuments', 'mdb.copyCollectionName', 'mdb.refreshCollection', 'mdb.refreshSchema', diff --git a/src/test/suite/mdbExtensionController.test.ts b/src/test/suite/mdbExtensionController.test.ts index a9d265026..5582c5c23 100644 --- a/src/test/suite/mdbExtensionController.test.ts +++ b/src/test/suite/mdbExtensionController.test.ts @@ -1229,6 +1229,31 @@ suite('MDBExtensionController Test Suite', () => { .then(done, done); }); + test('mdb.searchForDocuments should create a MongoDB playground with search template', async () => { + const mockOpenTextDocument = sinon.fake.resolves('untitled'); + sinon.replace(vscode.workspace, 'openTextDocument', mockOpenTextDocument); + + const mockShowTextDocument = sinon.fake.resolves(); + sinon.replace(vscode.window, 'showTextDocument', mockShowTextDocument); + + await vscode.commands.executeCommand( + 'mdb.searchForDocuments', + 'dbName', + 'collName' + ); + + assert(mockOpenTextDocument.firstArg.language === 'mongodb'); + assert( + mockOpenTextDocument.firstArg.content.includes( + 'Search for documents in the current collection.' + ) + ); + assert( + mockShowTextDocument.firstArg === 'untitled', + 'Expected it to call vscode to show the playground' + ); + }); + test('mdb.createPlayground should create a MongoDB playground with default template', async () => { const mockOpenTextDocument = sinon.fake.resolves('untitled'); sinon.replace(vscode.workspace, 'openTextDocument', mockOpenTextDocument);