diff --git a/src/editors/playgroundController.ts b/src/editors/playgroundController.ts index 6e932d433..e1403fa23 100644 --- a/src/editors/playgroundController.ts +++ b/src/editors/playgroundController.ts @@ -97,6 +97,21 @@ const countAggregationStagesInString = (str: string) => { .length; }; +enum TranspilerExportMode { + PIPELINE = 'Pipeline', + QUERY = 'Query', + DELETE_QUERY = 'Delete Query', + UPDATE_QUERY = 'Update Query', +} +const exportModeMapping: Record< + ExportToLanguageMode, + TranspilerExportMode | undefined +> = { + [ExportToLanguageMode.AGGREGATION]: TranspilerExportMode.PIPELINE, + [ExportToLanguageMode.QUERY]: TranspilerExportMode.QUERY, + [ExportToLanguageMode.OTHER]: undefined, +}; + /** * This controller manages playground. */ @@ -807,7 +822,13 @@ export default class PlaygroundController { let imports = ''; if (importStatements) { - imports = transpiler.shell[language].getImports(driverSyntax); + const exportMode = this._playgroundSelectedCodeActionProvider.mode + ? exportModeMapping[this._playgroundSelectedCodeActionProvider.mode] + : undefined; + imports = transpiler.shell[language].getImports( + exportMode, + driverSyntax + ); } this._playgroundResult = { diff --git a/src/test/suite/editors/playgroundSelectedCodeActionProvider.test.ts b/src/test/suite/editors/playgroundSelectedCodeActionProvider.test.ts index 3950d7dc7..1dea18fbd 100644 --- a/src/test/suite/editors/playgroundSelectedCodeActionProvider.test.ts +++ b/src/test/suite/editors/playgroundSelectedCodeActionProvider.test.ts @@ -195,69 +195,456 @@ suite('Playground Selected CodeAction Provider Test Suite', function () { } }); - test('exports to java and includes builders', async () => { - const textFromEditor = "{ name: '22' }"; - const selection = { - start: { line: 0, character: 0 }, - end: { line: 0, character: 14 }, - } as vscode.Selection; - const mode = ExportToLanguageMode.QUERY; - const activeTextEditor = { - document: { getText: () => textFromEditor }, - } as vscode.TextEditor; + suite('exports to java', () => { + const expectedResult = { + namespace: 'DATABASE_NAME.COLLECTION_NAME', + type: null, + content: 'new Document("name", "22")', + language: 'java', + }; + + beforeEach(async () => { + const textFromEditor = "{ name: '22' }"; + const selection = { + start: { line: 0, character: 0 }, + end: { line: 0, character: 14 }, + } as vscode.Selection; + const mode = ExportToLanguageMode.QUERY; + const activeTextEditor = { + document: { getText: () => textFromEditor }, + } as vscode.TextEditor; + + mdbTestExtension.testExtensionController._playgroundController._selectedText = + textFromEditor; + mdbTestExtension.testExtensionController._playgroundController._playgroundSelectedCodeActionProvider.selection = + selection; + mdbTestExtension.testExtensionController._playgroundController._playgroundSelectedCodeActionProvider.mode = + mode; + mdbTestExtension.testExtensionController._playgroundController._activeTextEditor = + activeTextEditor; + + testCodeActionProvider.refresh({ selection, mode }); + + // this is to ensure we're starting each test in the same state + await vscode.commands.executeCommand( + 'mdb.changeExportToLanguageAddons', + { + ...mdbTestExtension.testExtensionController._playgroundController + ._exportToLanguageCodeLensProvider._exportToLanguageAddons, + builders: false, + importStatements: false, + driverSyntax: false, + } + ); + }); - mdbTestExtension.testExtensionController._playgroundController._selectedText = - textFromEditor; - mdbTestExtension.testExtensionController._playgroundController._playgroundSelectedCodeActionProvider.selection = - selection; - mdbTestExtension.testExtensionController._playgroundController._playgroundSelectedCodeActionProvider.mode = - mode; - mdbTestExtension.testExtensionController._playgroundController._activeTextEditor = - activeTextEditor; + test('include builders (only)', async () => { + const codeActions = testCodeActionProvider.provideCodeActions(); - testCodeActionProvider.refresh({ selection, mode }); + if (!codeActions) { + expect.fail('No code actions'); + return false; + } - const codeActions = testCodeActionProvider.provideCodeActions(); - expect(codeActions).to.exist; + expect(codeActions.length).to.be.equal(TOTAL_CODEACTIONS_COUNT); + const actionCommand = codeActions[2].command; + + if (!actionCommand) { + expect.fail('Action command not found'); + return false; + } + + expect(actionCommand.command).to.be.equal('mdb.exportToJava'); + expect(actionCommand.title).to.be.equal('Export To Java'); + + await vscode.commands.executeCommand(actionCommand.command); + + let codeLenses = + mdbTestExtension.testExtensionController._playgroundController._exportToLanguageCodeLensProvider.provideCodeLenses(); + expect(codeLenses.length).to.be.equal(3); + let lensesObj = { lenses: codeLenses }; + expect(lensesObj).to.have.nested.property( + 'lenses[0].command.title', + 'Include Import Statements' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[1].command.title', + 'Include Driver Syntax' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[2].command.title', + 'Use Builders' + ); + + // Only java queries supports builders. + await vscode.commands.executeCommand( + 'mdb.changeExportToLanguageAddons', + { + ...mdbTestExtension.testExtensionController._playgroundController + ._exportToLanguageCodeLensProvider._exportToLanguageAddons, + builders: true, + importStatements: false, + driverSyntax: false, + } + ); + + codeLenses = + mdbTestExtension.testExtensionController._playgroundController._exportToLanguageCodeLensProvider.provideCodeLenses(); + lensesObj = { lenses: codeLenses }; + expect(lensesObj).to.have.nested.property( + 'lenses[0].command.title', + 'Include Import Statements' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[1].command.title', + 'Include Driver Syntax' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[2].command.title', + 'Use Raw Query' + ); + + expectedResult.content = 'eq("name", "22")'; + expect( + mdbTestExtension.testExtensionController._playgroundController + ._playgroundResult + ).to.be.deep.equal(expectedResult); + }); + + test('include driver syntax (only)', async () => { + const codeActions = testCodeActionProvider.provideCodeActions(); + + if (!codeActions) { + expect.fail('No code actions'); + return false; + } - if (codeActions) { expect(codeActions.length).to.be.equal(TOTAL_CODEACTIONS_COUNT); const actionCommand = codeActions[2].command; - if (actionCommand) { - expect(actionCommand.command).to.be.equal('mdb.exportToJava'); - expect(actionCommand.title).to.be.equal('Export To Java'); + if (!actionCommand) { + expect.fail('Action command not found'); + return false; + } - await vscode.commands.executeCommand(actionCommand.command); + expect(actionCommand.command).to.be.equal('mdb.exportToJava'); + expect(actionCommand.title).to.be.equal('Export To Java'); - const expectedResult = { - namespace: 'DATABASE_NAME.COLLECTION_NAME', - type: null, - content: 'new Document("name", "22")', - language: 'java', - }; + await vscode.commands.executeCommand(actionCommand.command); - const codeLenses = - mdbTestExtension.testExtensionController._playgroundController._exportToLanguageCodeLensProvider.provideCodeLenses(); - expect(codeLenses.length).to.be.equal(3); + let codeLenses = + mdbTestExtension.testExtensionController._playgroundController._exportToLanguageCodeLensProvider.provideCodeLenses(); + expect(codeLenses.length).to.be.equal(3); + let lensesObj = { lenses: codeLenses }; + expect(lensesObj).to.have.nested.property( + 'lenses[0].command.title', + 'Include Import Statements' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[1].command.title', + 'Include Driver Syntax' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[2].command.title', + 'Use Builders' + ); - // Only java queries supports builders. - await vscode.commands.executeCommand( - 'mdb.changeExportToLanguageAddons', - { - ...mdbTestExtension.testExtensionController._playgroundController - ._exportToLanguageCodeLensProvider._exportToLanguageAddons, - builders: true, - } - ); + await vscode.commands.executeCommand( + 'mdb.changeExportToLanguageAddons', + { + ...mdbTestExtension.testExtensionController._playgroundController + ._exportToLanguageCodeLensProvider._exportToLanguageAddons, + builders: false, + importStatements: false, + driverSyntax: true, + } + ); - expectedResult.content = 'eq("name", "22")'; - expect( - mdbTestExtension.testExtensionController._playgroundController - ._playgroundResult - ).to.be.deep.equal(expectedResult); + codeLenses = + mdbTestExtension.testExtensionController._playgroundController._exportToLanguageCodeLensProvider.provideCodeLenses(); + lensesObj = { lenses: codeLenses }; + expect(lensesObj).to.have.nested.property( + 'lenses[0].command.title', + 'Include Import Statements' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[1].command.title', + 'Exclude Driver Syntax' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[2].command.title', + 'Use Builders' + ); + + const driverSyntaxRawQuery = + 'Bson filter = new Document("name", "22");'; + expect( + mdbTestExtension.testExtensionController._playgroundController + ._playgroundResult?.content + ).to.include(driverSyntaxRawQuery); + }); + + test('include import statements (only)', async () => { + const codeActions = testCodeActionProvider.provideCodeActions(); + + if (!codeActions) { + expect.fail('No code actions'); + return false; } - } + + expect(codeActions.length).to.be.equal(TOTAL_CODEACTIONS_COUNT); + const actionCommand = codeActions[2].command; + + if (!actionCommand) { + expect.fail('Action command not found'); + return false; + } + + expect(actionCommand.command).to.be.equal('mdb.exportToJava'); + expect(actionCommand.title).to.be.equal('Export To Java'); + + await vscode.commands.executeCommand(actionCommand.command); + + let codeLenses = + mdbTestExtension.testExtensionController._playgroundController._exportToLanguageCodeLensProvider.provideCodeLenses(); + expect(codeLenses.length).to.be.equal(3); + let lensesObj = { lenses: codeLenses }; + expect(lensesObj).to.have.nested.property( + 'lenses[0].command.title', + 'Include Import Statements' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[1].command.title', + 'Include Driver Syntax' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[2].command.title', + 'Use Builders' + ); + + await vscode.commands.executeCommand( + 'mdb.changeExportToLanguageAddons', + { + ...mdbTestExtension.testExtensionController._playgroundController + ._exportToLanguageCodeLensProvider._exportToLanguageAddons, + builders: false, + importStatements: true, + driverSyntax: false, + } + ); + + codeLenses = + mdbTestExtension.testExtensionController._playgroundController._exportToLanguageCodeLensProvider.provideCodeLenses(); + lensesObj = { lenses: codeLenses }; + expect(lensesObj).to.have.nested.property( + 'lenses[0].command.title', + 'Exclude Import Statements' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[1].command.title', + 'Include Driver Syntax' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[2].command.title', + 'Use Builders' + ); + + // imports without driver syntax are limited + const rawQueryWithImport = + 'import org.bson.Document;\n\nnew Document("name", "22")'; + expect( + mdbTestExtension.testExtensionController._playgroundController + ._playgroundResult?.content + ).to.deep.equal(rawQueryWithImport); + }); + + test('include driver syntax and import statements (in a single export)', async () => { + const codeActions = testCodeActionProvider.provideCodeActions(); + + if (!codeActions) { + expect.fail('No code actions'); + return false; + } + + expect(codeActions.length).to.be.equal(TOTAL_CODEACTIONS_COUNT); + const actionCommand = codeActions[2].command; + + if (!actionCommand) { + expect.fail('Action command not found'); + return false; + } + + expect(actionCommand.command).to.be.equal('mdb.exportToJava'); + expect(actionCommand.title).to.be.equal('Export To Java'); + + await vscode.commands.executeCommand(actionCommand.command); + + let codeLenses = + mdbTestExtension.testExtensionController._playgroundController._exportToLanguageCodeLensProvider.provideCodeLenses(); + expect(codeLenses.length).to.be.equal(3); + let lensesObj = { lenses: codeLenses }; + expect(lensesObj).to.have.nested.property( + 'lenses[0].command.title', + 'Include Import Statements' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[1].command.title', + 'Include Driver Syntax' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[2].command.title', + 'Use Builders' + ); + await vscode.commands.executeCommand( + 'mdb.changeExportToLanguageAddons', + { + ...mdbTestExtension.testExtensionController._playgroundController + ._exportToLanguageCodeLensProvider._exportToLanguageAddons, + builders: false, + importStatements: true, + driverSyntax: true, + } + ); + + codeLenses = + mdbTestExtension.testExtensionController._playgroundController._exportToLanguageCodeLensProvider.provideCodeLenses(); + lensesObj = { lenses: codeLenses }; + expect(lensesObj).to.have.nested.property( + 'lenses[0].command.title', + 'Exclude Import Statements' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[1].command.title', + 'Exclude Driver Syntax' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[2].command.title', + 'Use Builders' + ); + + // With driver syntax, java includes generic import statements + const mongoClientImport = 'import com.mongodb.MongoClient;'; + // as well as import statements which depend on the exportToLanguageMode. the following is for QUERY + const queryImport = 'import com.mongodb.client.FindIterable;'; + const content = + mdbTestExtension.testExtensionController._playgroundController + ._playgroundResult?.content; + expect(content).to.include(mongoClientImport); + expect(content).to.include(queryImport); + }); + + test('include driver syntax and then import statements in a subsequent export', async () => { + const codeActions = testCodeActionProvider.provideCodeActions(); + + if (!codeActions) { + expect.fail('No code actions'); + return false; + } + + expect(codeActions.length).to.be.equal(TOTAL_CODEACTIONS_COUNT); + const actionCommand = codeActions[2].command; + + if (!actionCommand) { + expect.fail('Action command not found'); + return false; + } + + expect(actionCommand.command).to.be.equal('mdb.exportToJava'); + expect(actionCommand.title).to.be.equal('Export To Java'); + + /* 1st export - we'll select drivers only */ + await vscode.commands.executeCommand(actionCommand.command); + + let codeLenses = + mdbTestExtension.testExtensionController._playgroundController._exportToLanguageCodeLensProvider.provideCodeLenses(); + expect(codeLenses.length).to.be.equal(3); + let lensesObj = { lenses: codeLenses }; + expect(lensesObj).to.have.nested.property( + 'lenses[0].command.title', + 'Include Import Statements' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[1].command.title', + 'Include Driver Syntax' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[2].command.title', + 'Use Builders' + ); + + await vscode.commands.executeCommand( + 'mdb.changeExportToLanguageAddons', + { + ...mdbTestExtension.testExtensionController._playgroundController + ._exportToLanguageCodeLensProvider._exportToLanguageAddons, + builders: false, + importStatements: false, + driverSyntax: true, + } + ); + + codeLenses = + mdbTestExtension.testExtensionController._playgroundController._exportToLanguageCodeLensProvider.provideCodeLenses(); + lensesObj = { lenses: codeLenses }; + expect(lensesObj).to.have.nested.property( + 'lenses[0].command.title', + 'Include Import Statements' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[1].command.title', + 'Exclude Driver Syntax' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[2].command.title', + 'Use Builders' + ); + + /* 2nd export - this time we add import statements on top of drivers */ + await vscode.commands.executeCommand(actionCommand.command); + + codeLenses = + mdbTestExtension.testExtensionController._playgroundController._exportToLanguageCodeLensProvider.provideCodeLenses(); + expect(codeLenses.length).to.be.equal(3); + lensesObj = { lenses: codeLenses }; + // the state is persisted from the 1st export + expect(lensesObj).to.have.nested.property( + 'lenses[1].command.title', + 'Exclude Driver Syntax' + ); + + // We add import on top of the drivers + await vscode.commands.executeCommand( + 'mdb.changeExportToLanguageAddons', + { + ...mdbTestExtension.testExtensionController._playgroundController + ._exportToLanguageCodeLensProvider._exportToLanguageAddons, + importStatements: true, + } + ); + + codeLenses = + mdbTestExtension.testExtensionController._playgroundController._exportToLanguageCodeLensProvider.provideCodeLenses(); + expect(codeLenses.length).to.be.equal(3); + lensesObj = { lenses: codeLenses }; + // the state is persisted from the 1st export + expect(lensesObj).to.have.nested.property( + 'lenses[0].command.title', + 'Exclude Import Statements' + ); + expect(lensesObj).to.have.nested.property( + 'lenses[1].command.title', + 'Exclude Driver Syntax' + ); + + // The imports and driver syntax are both applied + const mongoClientImport = 'import com.mongodb.MongoClient;'; + const queryImport = 'import com.mongodb.client.FindIterable;'; + const content = + mdbTestExtension.testExtensionController._playgroundController + ._playgroundResult?.content; + expect(content).to.include(mongoClientImport); + expect(content).to.include(queryImport); + }); }); test('exports to csharp and includes import statements', async () => {