From 75cbb8c1a37135463f2af2ec6ca11b2f13c8bb25 Mon Sep 17 00:00:00 2001 From: Mitchell Sternke Date: Mon, 1 Aug 2016 13:23:56 -0700 Subject: [PATCH 1/2] Initial code for switching database on the current server --- package.json | 5 +++ src/controllers/connectionManager.ts | 18 +++++++++ src/controllers/controller.ts | 7 ++++ src/models/constants.ts | 4 ++ src/views/connectionUI.ts | 57 ++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+) diff --git a/package.json b/package.json index 97798a8ffe..902cd8ac61 100644 --- a/package.json +++ b/package.json @@ -98,6 +98,11 @@ "command": "extension.disconnect", "title": "Disconnect active connection", "category": "MSSQL" + }, + { + "command": "extension.chooseDatabase", + "title": "Switch database on current server", + "category": "MSSQL" } ], "keybindings": [ diff --git a/src/controllers/connectionManager.ts b/src/controllers/connectionManager.ts index 7ecb5d7296..aca02849a4 100644 --- a/src/controllers/connectionManager.ts +++ b/src/controllers/connectionManager.ts @@ -74,6 +74,24 @@ export default class ConnectionManager { return this._connection && this._connection.connected; } + // choose database to use on current server + public onChooseDatabase(): void { + const self = this; + + if (typeof self._connection === 'undefined' || typeof self._connectionCreds === 'undefined') { + Utils.showWarnMsg(Constants.msgChooseDatabaseNotConnected); + return; + } + + self.connectionUI.showDatabasesOnCurrentServer(self._connectionCreds).then( newDatabaseCredentials => { + if (typeof newDatabaseCredentials !== 'undefined') { + self.onDisconnect().then( () => { + self.connect(newDatabaseCredentials); + }); + } + }); + } + // close active connection, if any public onDisconnect(): Promise { return new Promise((resolve, reject) => { diff --git a/src/controllers/controller.ts b/src/controllers/controller.ts index 5fdf642ed6..9aa1fd1390 100644 --- a/src/controllers/controller.ts +++ b/src/controllers/controller.ts @@ -51,6 +51,8 @@ export default class MainController implements vscode.Disposable { this._event.on(Constants.cmdDisconnect, () => { self.onDisconnect(); }); this.registerCommand(Constants.cmdRunQuery); this._event.on(Constants.cmdRunQuery, () => { self.onRunQuery(); }); + this.registerCommand(Constants.cmdChooseDatabase); + this._event.on(Constants.cmdChooseDatabase, () => { self.onChooseDatabase(); } ); // Init status bar this._statusview = new StatusView(); @@ -76,6 +78,11 @@ export default class MainController implements vscode.Disposable { Utils.logDebug(Constants.extensionActivated); } + // Choose a new database from the current server + private onChooseDatabase(): void { + return this._connectionMgr.onChooseDatabase(); + } + // Close active connection, if any private onDisconnect(): Promise { return this._connectionMgr.onDisconnect(); diff --git a/src/models/constants.ts b/src/models/constants.ts index 2db3395fc7..aa0e900e49 100644 --- a/src/models/constants.ts +++ b/src/models/constants.ts @@ -6,6 +6,7 @@ export const outputChannelName = 'MSSQL'; export const cmdRunQuery = 'extension.runQuery'; export const cmdConnect = 'extension.connect'; export const cmdDisconnect = 'extension.disconnect'; +export const cmdChooseDatabase = 'extension.chooseDatabase'; export const sqlDbPrefix = '.database.windows.net'; export const defaultConnectionTimeout = 15000; @@ -49,6 +50,9 @@ export const msgContentProviderOnClear = 'Content provider: clear called'; export const msgContentProviderOnUpdateContent = 'Content provider: updateContent called'; export const msgContentProviderProvideContent = 'Content provider: provideTextDocumentContent called: '; +export const msgChooseDatabaseNotConnected = 'Not connected. Please connect to a server first.'; +export const msgChooseDatabasePlaceholder = 'Choose a database from the list below'; + export const extensionActivated = 'activated.'; export const extensionDeactivated = 'de-activated.'; export const msgOpenSqlFile = `To use this command, Open a .sql file -or- diff --git a/src/views/connectionUI.ts b/src/views/connectionUI.ts index 4e0eebb484..98984d0b10 100644 --- a/src/views/connectionUI.ts +++ b/src/views/connectionUI.ts @@ -5,6 +5,7 @@ import { RecentConnections } from '../models/recentConnections'; import Interfaces = require('../models/interfaces'); let async = require('async'); +const mssql = require('mssql'); export class ConnectionUI { // Helper to let user choose a connection from a picklist @@ -33,6 +34,62 @@ export class ConnectionUI { }); } + // Helper to let the user choose a database on the current server + // TODO: refactor this to use the service layer/SMO once the plumbing/conversion is complete + public showDatabasesOnCurrentServer(currentCredentials: Interfaces.IConnectionCredentials): Promise { + const self = this; + return new Promise((resolve, reject) => { + // create a new connection to the master db using the current connection as a base + const masterCredentials = { + connectionTimeout: currentCredentials.connectionTimeout, + database: 'master', + options: currentCredentials.options, + password: currentCredentials.password, + requestTimeout: currentCredentials.connectionTimeout, + server: currentCredentials.server, + user: currentCredentials.user + }; + const masterConnection = new mssql.Connection(masterCredentials); + + masterConnection.connect().then( () => { + // query sys.databases for a list of databases on the server + new mssql.Request(masterConnection).query('SELECT name FROM sys.databases').then( recordset => { + const pickListItems = recordset.map(record => { + return { + label: record.name, + description: '', + detail: '', + connectionCreds: { + connectionTimeout: currentCredentials.connectionTimeout, + database: record.name, + options: currentCredentials.options, + password: currentCredentials.password, + requestTimeout: currentCredentials.requestTimeout, + server: currentCredentials.server, + user: currentCredentials.user + } + }; + }); + + const pickListOptions: vscode.QuickPickOptions = { + placeHolder: Constants.msgChooseDatabasePlaceholder + }; + + // show database picklist, and modify the current connection to switch the active database + vscode.window.showQuickPick(pickListItems, pickListOptions).then( selection => { + if (typeof selection !== 'undefined') { + resolve(selection.connectionCreds); + } else { + resolve(undefined); + } + }); + }).catch( err => { + reject(err); + }); + }); + }); + } + // Helper to prompt user to open VS Code user settings or workspace settings private openUserOrWorkspaceSettings(): void { let openGlobalSettingsItem: vscode.MessageItem = { From 2a7425e17f6df69825855a4c92d79da6205a9d0e Mon Sep 17 00:00:00 2001 From: Mitchell Sternke Date: Mon, 1 Aug 2016 17:03:44 -0700 Subject: [PATCH 2/2] Using Object.assign now instead of manual copying --- src/views/connectionUI.ts | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/views/connectionUI.ts b/src/views/connectionUI.ts index 98984d0b10..9b27965bb9 100644 --- a/src/views/connectionUI.ts +++ b/src/views/connectionUI.ts @@ -40,34 +40,24 @@ export class ConnectionUI { const self = this; return new Promise((resolve, reject) => { // create a new connection to the master db using the current connection as a base - const masterCredentials = { - connectionTimeout: currentCredentials.connectionTimeout, - database: 'master', - options: currentCredentials.options, - password: currentCredentials.password, - requestTimeout: currentCredentials.connectionTimeout, - server: currentCredentials.server, - user: currentCredentials.user - }; + let masterCredentials: Interfaces.IConnectionCredentials = {}; + Object.assign(masterCredentials, currentCredentials); + masterCredentials.database = 'master'; const masterConnection = new mssql.Connection(masterCredentials); masterConnection.connect().then( () => { // query sys.databases for a list of databases on the server new mssql.Request(masterConnection).query('SELECT name FROM sys.databases').then( recordset => { const pickListItems = recordset.map(record => { + let newCredentials: Interfaces.IConnectionCredentials = {}; + Object.assign(newCredentials, currentCredentials); + newCredentials.database = record.name; + return { label: record.name, description: '', detail: '', - connectionCreds: { - connectionTimeout: currentCredentials.connectionTimeout, - database: record.name, - options: currentCredentials.options, - password: currentCredentials.password, - requestTimeout: currentCredentials.requestTimeout, - server: currentCredentials.server, - user: currentCredentials.user - } + connectionCreds: newCredentials }; });