From cbf3ca726f614beff71f570ed4c58d4be3c72f3c Mon Sep 17 00:00:00 2001 From: David Shiflet Date: Mon, 29 Apr 2019 13:10:19 -0400 Subject: [PATCH] Connect opened query editors to the server (#5207) * Connect opened query editors to the ser * only show firewall rule error for one file * remove unused imports * sync to latest * add comment * one more comment --- .../commandLine/common/commandLineService.ts | 61 ++++++++++++++----- .../commandLine/commandLineService.test.ts | 46 +++++++++++++- 2 files changed, 89 insertions(+), 18 deletions(-) diff --git a/src/sql/workbench/services/commandLine/common/commandLineService.ts b/src/sql/workbench/services/commandLine/common/commandLineService.ts index 313d424e6b..df5ed7a744 100644 --- a/src/sql/workbench/services/commandLine/common/commandLineService.ts +++ b/src/sql/workbench/services/commandLine/common/commandLineService.ts @@ -8,7 +8,7 @@ import { ConnectionProfile } from 'sql/platform/connection/common/connectionProf import { ConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup'; import { equalsIgnoreCase } from 'vs/base/common/strings'; import { ICommandLineProcessing } from 'sql/workbench/services/commandLine/common/commandLine'; -import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement'; +import { IConnectionManagementService, IConnectionCompletionOptions, ConnectionType, RunQueryOnConnectionMode } from 'sql/platform/connection/common/connectionManagement'; import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import * as Constants from 'sql/platform/connection/common/constants'; @@ -25,6 +25,8 @@ import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; import { localize } from 'vs/nls'; +import { QueryInput } from 'sql/workbench/parts/query/common/queryInput'; +import { URI } from 'vs/base/common/uri'; export class CommandLineService implements ICommandLineProcessing { public _serviceBrand: any; @@ -67,7 +69,7 @@ export class CommandLineService implements ICommandLineProcessing { // We base our logic on the combination of (server, command) values. // (serverName, commandName) => Connect object explorer and execute the command, passing the connection profile to the command. Do not load query editor. // (null, commandName) => Launch the command with a null connection. If the command implementation needs a connection, it will need to create it. - // (serverName, null) => Connect object explorer and open a new query editor + // (serverName, null) => Connect object explorer and open a new query editor if no file names are passed. If file names are passed, connect their editors to the server. // (null, null) => Prompt for a connection unless there are registered servers public async processCommandLine(args: ParsedArgs): Promise { let profile: IConnectionProfile = undefined; @@ -108,20 +110,49 @@ export class CommandLineService implements ICommandLineProcessing { } await this._commandService.executeCommand(commandName, connectedContext); } else if (profile) { - if (this._statusBarService) { - this._statusBarService.setStatusMessage(localize('openingNewQueryLabel', 'Opening new query:') + profile.serverName, 2500); + // If we were given a file and it was opened with the sql editor, + // we want to connect the given profile to to it. + // If more than one file was passed, only show the connection dialog error on one of them. + if (args._ && args._.length > 0) { + await args._.forEach((f, i) => this.processFile(URI.file(f).toString(), profile, i === 0)); } - // Default to showing new query - try { - await TaskUtilities.newQuery(profile, - this._connectionManagementService, - this._queryEditorService, - this._objectExplorerService, - this._editorService); - } catch (error) { - warn('unable to open query editor ' + error); - // Note: we are intentionally swallowing this error. - // In part this is to accommodate unit testing where we don't want to set up the query stack + else { + // Default to showing new query + if (this._statusBarService) { + this._statusBarService.setStatusMessage(localize('openingNewQueryLabel', 'Opening new query:') + profile.serverName, 2500); + } + try { + await TaskUtilities.newQuery(profile, + this._connectionManagementService, + this._queryEditorService, + this._objectExplorerService, + this._editorService); + } catch (error) { + warn('unable to open query editor ' + error); + // Note: we are intentionally swallowing this error. + // In part this is to accommodate unit testing where we don't want to set up the query stack + } + } + } + } + + // If an open and connectable query editor exists for the given URI, attach it to the connection profile + private async processFile(uriString: string, profile: IConnectionProfile, warnOnConnectFailure: boolean): Promise { + let activeEditor = this._editorService.editors.filter(v => v.getResource().toString() === uriString).pop(); + if (activeEditor) { + let queryInput = activeEditor as QueryInput; + if (queryInput && queryInput.connectEnabled) { + let options: IConnectionCompletionOptions = { + params: { connectionType: ConnectionType.editor, runQueryOnCompletion: RunQueryOnConnectionMode.none, input: queryInput }, + saveTheConnection: false, + showDashboard: false, + showConnectionDialogOnError: warnOnConnectFailure, + showFirewallRuleOnError: warnOnConnectFailure + }; + if (this._statusBarService) { + this._statusBarService.setStatusMessage(localize('connectingQueryLabel', 'Connecting query file'), 2500); + } + await this._connectionManagementService.connect(profile, uriString, options); } } } diff --git a/src/sqltest/parts/commandLine/commandLineService.test.ts b/src/sqltest/parts/commandLine/commandLineService.test.ts index 46c052eafa..79ab706179 100644 --- a/src/sqltest/parts/commandLine/commandLineService.test.ts +++ b/src/sqltest/parts/commandLine/commandLineService.test.ts @@ -16,7 +16,7 @@ import { CapabilitiesTestService } from 'sqltest/stubs/capabilitiesTestService'; import { QueryEditorService } from 'sql/workbench/services/queryEditor/browser/queryEditorService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ObjectExplorerService } from 'sql/workbench/services/objectExplorer/common/objectExplorerService'; -import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement'; +import { IConnectionManagementService, IConnectionCompletionOptions, ConnectionType } from 'sql/platform/connection/common/connectionManagement'; import { ConnectionStore } from 'sql/platform/connection/common/connectionStore'; import { TestConnectionManagementService } from 'sqltest/stubs/connectionManagementService.test'; import { ICommandService } from 'vs/platform/commands/common/commands'; @@ -25,6 +25,9 @@ import { WorkspaceConfigurationTestService } from 'sqltest/stubs/workspaceConfig import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; import { assertThrowsAsync } from 'sqltest/utils/testUtils'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { TestEditorService } from 'vs/workbench/test/workbenchTestServices'; +import { QueryInput } from 'sql/workbench/parts/query/common/queryInput'; +import { URI } from 'vs/base/common/uri'; class TestParsedArgs implements ParsedArgs { [arg: string]: any; @@ -106,7 +109,8 @@ suite('commandLineService tests', () => { function getCommandLineService(connectionManagementService: IConnectionManagementService, configurationService: IConfigurationService, capabilitiesService?: ICapabilitiesService, - commandService?: ICommandService + commandService?: ICommandService, + editorService?: IEditorService ): CommandLineService { let service = new CommandLineService( capabilitiesService, @@ -114,7 +118,7 @@ suite('commandLineService tests', () => { undefined, undefined, undefined, - undefined, + editorService, commandService, configurationService, undefined @@ -351,4 +355,40 @@ suite('commandLineService tests', () => { await service.processCommandLine(args); connectionManagementService.verifyAll(); }); + + test('processCommandLine connects opened query files to given server', async () => { + const connectionManagementService: TypeMoq.Mock + = TypeMoq.Mock.ofType(TestConnectionManagementService, TypeMoq.MockBehavior.Strict); + const args: TestParsedArgs = new TestParsedArgs(); + args.server = 'myserver'; + args.database = 'mydatabase'; + args.user = 'myuser'; + args._ = ['c:\\dir\\file.sql']; + connectionManagementService.setup((c) => c.showConnectionDialog()).verifiable(TypeMoq.Times.never()); + connectionManagementService.setup(c => c.hasRegisteredServers()).returns(() => true).verifiable(TypeMoq.Times.atMostOnce()); + connectionManagementService.setup(c => c.getConnectionGroups(TypeMoq.It.isAny())).returns(() => []); + let originalProfile: IConnectionProfile = undefined; + connectionManagementService.setup(c => c.connectIfNotConnected(TypeMoq.It.is(p => p.serverName === 'myserver' && p.authenticationType === Constants.sqlLogin), 'connection', true)) + .returns((conn) => { + originalProfile = conn; + return Promise.resolve('unused'); + }).verifiable(TypeMoq.Times.once()); + connectionManagementService.setup(c => c.getConnectionProfileById(TypeMoq.It.isAnyString())).returns(() => originalProfile); + const configurationService = getConfigurationServiceMock(true); + const queryInput: TypeMoq.Mock = TypeMoq.Mock.ofType(QueryInput); + let uri = URI.file(args._[0]); + queryInput.setup(q => q.connectEnabled).returns(() => 1 === 1).verifiable(TypeMoq.Times.once()); + queryInput.setup(q => q.getResource()).returns(() => uri).verifiable(TypeMoq.Times.once()); + const editorService: TypeMoq.Mock = TypeMoq.Mock.ofType(TestEditorService, TypeMoq.MockBehavior.Strict); + editorService.setup(e => e.editors).returns(() => [queryInput.object]); + connectionManagementService.setup(c => + c.connect(TypeMoq.It.is(p => p.serverName === 'myserver' && p.authenticationType === Constants.sqlLogin), + uri.toString(), + TypeMoq.It.is(i => i.params.input === queryInput.object && i.params.connectionType === ConnectionType.editor)) + ).verifiable(TypeMoq.Times.once()); + let service = getCommandLineService(connectionManagementService.object, configurationService.object, capabilitiesService, undefined, editorService.object); + await service.processCommandLine(args); + queryInput.verifyAll(); + connectionManagementService.verifyAll(); + }); });