Capabilities Cache (#831)

* init

* finished compile erros

* fixed all merge conflicts

* fix dialog problems

* formatting

* fix opening dialog on first open

* fix various problems with connectiondialog

* formatting

* fix tests
This commit is contained in:
Anthony Dresser
2018-03-08 17:16:40 -08:00
committed by GitHub
parent 45b1ae1fb1
commit 8b2ea4f0a0
26 changed files with 302 additions and 414 deletions

View File

@@ -111,4 +111,3 @@ export class TrieMap<E> {
return result;
}
}

View File

@@ -43,19 +43,12 @@ export class AdminService implements IAdminService {
private _providers: { [handle: string]: sqlops.AdminServicesProvider; } = Object.create(null);
private _providerOptions: { [handle: string]: sqlops.AdminServicesOptions; } = Object.create(null);
constructor(
@IInstantiationService private _instantiationService: IInstantiationService,
@IWorkbenchEditorService private _editorService: IWorkbenchEditorService,
@IConnectionManagementService private _connectionService: IConnectionManagementService,
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService
) {
if (_capabilitiesService && _capabilitiesService.onProviderRegisteredEvent) {
_capabilitiesService.onProviderRegisteredEvent((capabilities => {
this._providerOptions[capabilities.providerName] = capabilities.adminServicesProvider;
}));
}
}
private _runAction<T>(uri: string, action: (handler: sqlops.AdminServicesProvider) => Thenable<T>): Thenable<T> {

View File

@@ -29,32 +29,14 @@ export interface ISaveGroupResult {
*/
export class ConnectionConfig implements IConnectionConfig {
private _providerCapabilitiesMap: { [providerName: string]: sqlops.DataProtocolServerCapabilities };
/**
* Constructor.
*/
public constructor(
private _configurationEditService: ConfigurationEditingService,
private _workspaceConfigurationService: IWorkspaceConfigurationService,
private _capabilitiesService: ICapabilitiesService,
cachedMetadata?: sqlops.DataProtocolServerCapabilities[]
) {
this._providerCapabilitiesMap = {};
this.setCachedMetadata(cachedMetadata);
if (this._capabilitiesService && this._capabilitiesService.onCapabilitiesReady()) {
this._capabilitiesService.onCapabilitiesReady().then(() => {
this.setCachedMetadata(this._capabilitiesService.getCapabilities());
});
}
}
public setCachedMetadata(cachedMetadata: sqlops.DataProtocolServerCapabilities[]): void {
if (cachedMetadata) {
cachedMetadata.forEach(item => {
this.updateCapabilitiesCache(item.providerName, item);
});
}
}
private _capabilitiesService: ICapabilitiesService
) { }
/**
* Returns connection groups from user and workspace settings.
@@ -81,44 +63,6 @@ export class ConnectionConfig implements IConnectionConfig {
return allGroups;
}
private updateCapabilitiesCache(providerName: string, providerCapabilities: sqlops.DataProtocolServerCapabilities): void {
if (providerName && providerCapabilities) {
this._providerCapabilitiesMap[providerName] = providerCapabilities;
}
}
private getCapabilitiesFromCache(providerName: string): sqlops.DataProtocolServerCapabilities {
if (providerName in this._providerCapabilitiesMap) {
return this._providerCapabilitiesMap[providerName];
}
return undefined;
}
/**
* Returns the capabilities for given provider name. First tries to get it from capabilitiesService and if it's not registered yet,
* Gets the data from the metadata stored in the config
* @param providerName Provider Name
*/
public getCapabilities(providerName: string): sqlops.DataProtocolServerCapabilities {
let result: sqlops.DataProtocolServerCapabilities = this.getCapabilitiesFromCache(providerName);
if (result) {
return result;
} else {
let capabilities = this._capabilitiesService.getCapabilities();
if (capabilities) {
let providerCapabilities = capabilities.find(c => c.providerName === providerName);
if (providerCapabilities) {
this.updateCapabilitiesCache(providerName, providerCapabilities);
return providerCapabilities;
} else {
return undefined;
}
} else {
return undefined;
}
}
}
/**
* Add a new connection to the connection config.
*/
@@ -131,14 +75,12 @@ export class ConnectionConfig implements IConnectionConfig {
profiles = [];
}
let providerCapabilities = this.getCapabilities(profile.providerName);
let connectionProfile = this.getConnectionProfileInstance(profile, groupId, providerCapabilities);
let newProfile = ConnectionProfile.convertToProfileStore(providerCapabilities, connectionProfile);
let connectionProfile = this.getConnectionProfileInstance(profile, groupId);
let newProfile = ConnectionProfile.convertToProfileStore(this._capabilitiesService, connectionProfile);
// Remove the profile if already set
var sameProfileInList = profiles.find(value => {
let providerCapabilities = this.getCapabilities(value.providerName);
let providerConnectionProfile = ConnectionProfile.createFromStoredProfile(value, providerCapabilities);
let providerConnectionProfile = ConnectionProfile.createFromStoredProfile(value, this._capabilitiesService);
return providerConnectionProfile.matches(connectionProfile);
});
if (sameProfileInList) {
@@ -159,10 +101,10 @@ export class ConnectionConfig implements IConnectionConfig {
});
}
private getConnectionProfileInstance(profile: IConnectionProfile, groupId: string, providerCapabilities: sqlops.DataProtocolServerCapabilities): ConnectionProfile {
private getConnectionProfileInstance(profile: IConnectionProfile, groupId: string): ConnectionProfile {
let connectionProfile = profile as ConnectionProfile;
if (connectionProfile === undefined) {
connectionProfile = new ConnectionProfile(providerCapabilities, profile);
connectionProfile = new ConnectionProfile(this._capabilitiesService, profile);
}
connectionProfile.groupId = groupId;
return connectionProfile;
@@ -286,15 +228,7 @@ export class ConnectionConfig implements IConnectionConfig {
}
let connectionProfiles = profiles.map(p => {
let capabilitiesForProvider = this.getCapabilities(p.providerName);
let providerConnectionProfile = ConnectionProfile.createFromStoredProfile(p, capabilitiesForProvider);
providerConnectionProfile.setServerCapabilities(capabilitiesForProvider);
this._capabilitiesService.onProviderRegisteredEvent((serverCapabilities) => {
providerConnectionProfile.onProviderRegistered(serverCapabilities);
});
return providerConnectionProfile;
return ConnectionProfile.createFromStoredProfile(p, this._capabilitiesService);
});
return connectionProfiles;
@@ -308,8 +242,7 @@ export class ConnectionConfig implements IConnectionConfig {
let profiles = this._workspaceConfigurationService.inspect<IConnectionProfileStore[]>(Constants.connectionsArrayName).user;
// Remove the profile from the connections
profiles = profiles.filter(value => {
let providerCapabilities = this.getCapabilities(value.providerName);
let providerConnectionProfile = ConnectionProfile.createFromStoredProfile(value, providerCapabilities);
let providerConnectionProfile = ConnectionProfile.createFromStoredProfile(value, this._capabilitiesService);
return providerConnectionProfile.getOptionsKey() !== profile.getOptionsKey();
});
@@ -330,8 +263,7 @@ export class ConnectionConfig implements IConnectionConfig {
let profiles = this._workspaceConfigurationService.inspect<IConnectionProfileStore[]>(Constants.connectionsArrayName).user;
// Remove the profiles from the connections
profiles = profiles.filter(value => {
let providerCapabilities = this.getCapabilities(value.providerName);
let providerConnectionProfile = ConnectionProfile.createFromStoredProfile(value, providerCapabilities);
let providerConnectionProfile = ConnectionProfile.createFromStoredProfile(value, this._capabilitiesService);
return !connections.some((val) => val.getOptionsKey() === providerConnectionProfile.getOptionsKey());
});
@@ -382,13 +314,12 @@ export class ConnectionConfig implements IConnectionConfig {
let profiles = target === ConfigurationTarget.USER ? this._workspaceConfigurationService.inspect<IConnectionProfileStore[]>(Constants.connectionsArrayName).user :
this._workspaceConfigurationService.inspect<IConnectionProfileStore[]>(Constants.connectionsArrayName).workspace;
if (profiles) {
let providerCapabilities = this.getCapabilities(profile.providerName);
if (profile.parent && profile.parent.id === Constants.unsavedGroupId) {
profile.groupId = newGroupID;
profiles.push(ConnectionProfile.convertToProfileStore(providerCapabilities, profile));
profiles.push(ConnectionProfile.convertToProfileStore(this._capabilitiesService, profile));
} else {
profiles.forEach((value) => {
let configProf = ConnectionProfile.createFromStoredProfile(value, providerCapabilities);
let configProf = ConnectionProfile.createFromStoredProfile(value, this._capabilitiesService);
if (configProf.getOptionsKey() === profile.getOptionsKey()) {
value.groupId = newGroupID;
}

View File

@@ -216,8 +216,6 @@ export interface IConnectionManagementService {
hasRegisteredServers(): boolean;
getCapabilities(providerName: string): sqlops.DataProtocolServerCapabilities;
canChangeConnectionConfig(profile: ConnectionProfile, newGroupID: string): boolean;
getTabColorForUri(uri: string): string;

View File

@@ -137,9 +137,9 @@ export class ConnectionManagementService implements IConnectionManagementService
100 /* High Priority */
));
if (_capabilitiesService && _capabilitiesService.onProviderRegisteredEvent) {
_capabilitiesService.onProviderRegisteredEvent((capabilities => {
if (capabilities.providerName === 'MSSQL') {
if (_capabilitiesService) {
_capabilitiesService.onCapabilitiesRegistered((p => {
if (p === 'MSSQL') {
if (!this.hasRegisteredServers()) {
// prompt the user for a new connection on startup if no profiles are registered
this.showConnectionDialog();
@@ -679,21 +679,13 @@ export class ConnectionManagementService implements IConnectionManagementService
return Object.keys(this._providers);
}
public getCapabilities(providerName: string): sqlops.DataProtocolServerCapabilities {
let capabilities = this._capabilitiesService.getCapabilities();
if (capabilities !== undefined && capabilities.length > 0) {
return capabilities.find(c => c.providerName === providerName);
}
return undefined;
}
public getAdvancedProperties(): sqlops.ConnectionOption[] {
let capabilities = this._capabilitiesService.getCapabilities();
if (capabilities !== undefined && capabilities.length > 0) {
let providers = this._capabilitiesService.providers;
if (providers !== undefined && providers.length > 0) {
// just grab the first registered provider for now, this needs to change
// to lookup based on currently select provider
let providerCapabilities = capabilities[0];
let providerCapabilities = this._capabilitiesService.getCapabilities(providers[0]);
if (!!providerCapabilities.connectionProvider) {
return providerCapabilities.connectionProvider.options;
}
@@ -1362,7 +1354,7 @@ export class ConnectionManagementService implements IConnectionManagementService
}
// Find the password option for the connection provider
let passwordOption = this._capabilitiesService.getCapabilities().find(capability => capability.providerName === profile.providerName).connectionProvider.options.find(
let passwordOption = this._capabilitiesService.getCapabilities(profile.providerName).connectionProvider.options.find(
option => option.specialValueType === ConnectionOptionSpecialType.password);
if (!passwordOption) {
return undefined;

View File

@@ -12,6 +12,8 @@ import * as interfaces from 'sql/parts/connection/common/interfaces';
import { equalsIgnoreCase } from 'vs/base/common/strings';
import { generateUuid } from 'vs/base/common/uuid';
import * as objects from 'sql/base/common/objects';
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
import { isString } from 'vs/base/common/types';
// Concrete implementation of the IConnectionProfile interface
@@ -28,9 +30,13 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
public saveProfile: boolean;
public isDisconnecting: boolean = false;
public constructor(serverCapabilities?: sqlops.DataProtocolServerCapabilities, model?: interfaces.IConnectionProfile) {
super(serverCapabilities, model);
if (model) {
public constructor(
capabilitiesService: ICapabilitiesService,
model: string | interfaces.IConnectionProfile
) {
super(capabilitiesService, model);
if (model && !isString(model)) {
this.groupId = model.groupId;
this.groupFullName = model.groupFullName;
this.savePassword = model.savePassword;
@@ -91,7 +97,7 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
}
public clone(): ConnectionProfile {
let instance = new ConnectionProfile(this._serverCapabilities, this);
let instance = new ConnectionProfile(this.capabilitiesService, this);
return instance;
}
@@ -137,12 +143,6 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
return super.getOptionsKey();
}
public onProviderRegistered(serverCapabilities: sqlops.DataProtocolServerCapabilities): void {
if (serverCapabilities.providerName === this.providerName) {
this.setServerCapabilities(serverCapabilities);
}
}
public toIConnectionProfile(): interfaces.IConnectionProfile {
let result: interfaces.IConnectionProfile = {
serverName: this.serverName,
@@ -170,8 +170,19 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
};
}
public static createFromStoredProfile(profile: interfaces.IConnectionProfileStore, serverCapabilities: sqlops.DataProtocolServerCapabilities): ConnectionProfile {
let connectionInfo = new ConnectionProfile(serverCapabilities, undefined);
public static fromIConnectionProfile(capabilitiesService: ICapabilitiesService, profile: interfaces.IConnectionProfile) {
if (profile) {
if (profile instanceof ConnectionProfile) {
return profile;
} else {
return new ConnectionProfile(capabilitiesService, profile);
}
}
return undefined;
}
public static createFromStoredProfile(profile: interfaces.IConnectionProfileStore, capabilitiesService: ICapabilitiesService): ConnectionProfile {
let connectionInfo = new ConnectionProfile(capabilitiesService, profile.providerName);
connectionInfo.options = profile.options;
// append group ID and original display name to build unique OE session ID
@@ -187,28 +198,11 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
return connectionInfo;
}
public static convertToConnectionProfile(serverCapabilities: sqlops.DataProtocolServerCapabilities, conn: interfaces.IConnectionProfile): ConnectionProfile {
if (conn) {
let connectionProfile: ConnectionProfile = undefined;
let connectionProfileInstance = conn as ConnectionProfile;
if (connectionProfileInstance && conn instanceof ConnectionProfile) {
connectionProfile = connectionProfileInstance;
connectionProfile.setServerCapabilities(serverCapabilities);
} else {
connectionProfile = new ConnectionProfile(serverCapabilities, conn);
}
return connectionProfile;
} else {
return undefined;
}
}
public static convertToProfileStore(
serverCapabilities: sqlops.DataProtocolServerCapabilities,
capabilitiesService: ICapabilitiesService,
connectionProfile: interfaces.IConnectionProfile): interfaces.IConnectionProfileStore {
if (connectionProfile) {
let connectionInfo = ConnectionProfile.convertToConnectionProfile(serverCapabilities, connectionProfile);
let connectionInfo = ConnectionProfile.fromIConnectionProfile(capabilitiesService, connectionProfile);
let profile: interfaces.IConnectionProfileStore = {
options: {},
groupId: connectionProfile.groupId,
@@ -224,5 +218,4 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
return undefined;
}
}
}

View File

@@ -22,25 +22,6 @@ export class ConnectionStatusManager {
this._providerCapabilitiesMap = {};
}
public getCapabilities(providerName: string): sqlops.DataProtocolServerCapabilities {
let result: sqlops.DataProtocolServerCapabilities;
if (providerName in this._providerCapabilitiesMap) {
result = this._providerCapabilitiesMap[providerName];
} else {
let capabilities = this._capabilitiesService.getCapabilities();
if (capabilities) {
let providerCapabilities = capabilities.find(c => c.providerName === providerName);
if (providerCapabilities) {
this._providerCapabilitiesMap[providerName] = providerCapabilities;
result = providerCapabilities;
}
}
}
return result;
}
public findConnection(id: string): ConnectionManagementInfo {
if (id in this._connections) {
return this._connections[id];
@@ -80,15 +61,14 @@ export class ConnectionStatusManager {
public addConnection(connection: IConnectionProfile, id: string): ConnectionManagementInfo {
// Always create a copy and save that in the list
let connectionProfile = new ConnectionProfile(this.getCapabilities(connection.providerName), connection);
const self = this;
let connectionProfile = new ConnectionProfile(this._capabilitiesService, connection);
let connectionInfo: ConnectionManagementInfo = new ConnectionManagementInfo();
connectionInfo.providerId = connection.providerName;
connectionInfo.extensionTimer = StopWatch.create();
connectionInfo.intelliSenseTimer = StopWatch.create();
connectionInfo.connectionProfile = connectionProfile;
connectionInfo.connecting = true;
self._connections[id] = connectionInfo;
this._connections[id] = connectionInfo;
connectionInfo.serviceTimer = StopWatch.create();
connectionInfo.ownerUri = id;

View File

@@ -50,14 +50,8 @@ export class ConnectionStore {
this._groupIdToFullNameMap = {};
this._groupFullNameToIdMap = {};
if (!this._connectionConfig) {
let cachedServerCapabilities = this.getCachedServerCapabilities();
this._connectionConfig = new ConnectionConfig(this._configurationEditService,
this._workspaceConfigurationService, this._capabilitiesService, cachedServerCapabilities);
}
if (_capabilitiesService) {
_capabilitiesService.onProviderRegisteredEvent(e => {
this.saveCachedServerCapabilities();
});
this._workspaceConfigurationService, this._capabilitiesService);
}
}
@@ -84,8 +78,8 @@ export class ConnectionStore {
* @returns {string} formatted string with server, DB and username
*/
public formatCredentialId(connectionProfile: IConnectionProfile, itemType?: string): string {
let connectionProfileInstance: ConnectionProfile = ConnectionProfile.convertToConnectionProfile(
this._connectionConfig.getCapabilities(connectionProfile.providerName), connectionProfile);
let connectionProfileInstance: ConnectionProfile = ConnectionProfile.fromIConnectionProfile(
this._capabilitiesService, connectionProfile);
if (!connectionProfileInstance.getConnectionInfoId()) {
throw new Error('Missing Id, which is required');
}
@@ -111,7 +105,7 @@ export class ConnectionStore {
*/
public isPasswordRequired(connection: IConnectionProfile): boolean {
if (connection) {
let connectionProfile = ConnectionProfile.convertToConnectionProfile(this._connectionConfig.getCapabilities(connection.providerName), connection);
let connectionProfile = ConnectionProfile.fromIConnectionProfile(this._capabilitiesService, connection);
return connectionProfile.isPasswordRequired();
} else {
return false;
@@ -174,7 +168,6 @@ export class ConnectionStore {
// Add necessary default properties before returning
// this is needed to support immediate connections
ConnInfo.fixupConnectionCredentials(profile);
this.saveCachedServerCapabilities();
resolve(profile);
}, err => {
reject(err);
@@ -214,23 +207,6 @@ export class ConnectionStore {
});
}
private getCachedServerCapabilities(): sqlops.DataProtocolServerCapabilities[] {
if (this._memento) {
let metadata: sqlops.DataProtocolServerCapabilities[] = this._memento[Constants.capabilitiesOptions];
return metadata;
} else {
return undefined;
}
}
private saveCachedServerCapabilities(): void {
if (this._memento) {
let capabilities = this._capabilitiesService.getCapabilities();
this._memento[Constants.capabilitiesOptions] = capabilities;
}
}
/**
* Gets the list of recently used connections. These will not include the password - a separate call to
* {addSavedPassword} is needed to fill that before connecting
@@ -250,11 +226,7 @@ export class ConnectionStore {
private convertConfigValuesToConnectionProfiles(configValues: IConnectionProfile[]): ConnectionProfile[] {
return configValues.map(c => {
if (c) {
let capabilities = this._connectionConfig.getCapabilities(c.providerName);
let connectionProfile = new ConnectionProfile(capabilities, c);
this._capabilitiesService.onProviderRegisteredEvent((serverCapabilities) => {
connectionProfile.onProviderRegistered(serverCapabilities);
});
let connectionProfile = new ConnectionProfile(this._capabilitiesService, c);
if (connectionProfile.saveProfile) {
if (!connectionProfile.groupFullName && connectionProfile.groupId) {
connectionProfile.groupFullName = this.getGroupFullName(connectionProfile.groupId);
@@ -289,7 +261,7 @@ export class ConnectionStore {
public getProfileWithoutPassword(conn: IConnectionProfile): ConnectionProfile {
if (conn) {
let savedConn: ConnectionProfile = ConnectionProfile.convertToConnectionProfile(this._connectionConfig.getCapabilities(conn.providerName), conn);
let savedConn: ConnectionProfile = ConnectionProfile.fromIConnectionProfile(this._capabilitiesService, conn);
savedConn = savedConn.withoutPassword();
return savedConn;

View File

@@ -23,8 +23,6 @@ export interface IConnectionConfig {
getAllGroups(): IConnectionProfileGroup[];
changeGroupIdForConnectionGroup(source: ConnectionProfileGroup, target: ConnectionProfileGroup): Promise<void>;
changeGroupIdForConnection(source: ConnectionProfile, targetGroupId: string): Promise<void>;
setCachedMetadata(cachedMetaData: sqlops.DataProtocolServerCapabilities[]): void;
getCapabilities(providerName: string): sqlops.DataProtocolServerCapabilities;
editGroup(group: ConnectionProfileGroup): Promise<void>;
deleteConnection(profile: ConnectionProfile): Promise<void>;
deleteGroup(group: ConnectionProfileGroup): Promise<void>;

View File

@@ -5,45 +5,68 @@
'use strict';
import { Disposable } from 'vs/base/common/lifecycle';
import { isString } from 'vs/base/common/types';
import * as sqlops from 'sqlops';
import * as interfaces from 'sql/parts/connection/common/interfaces';
import { ConnectionOptionSpecialType, ServiceOptionType } from 'sql/workbench/api/common/sqlExtHostTypes';
import * as Constants from 'sql/parts/connection/common/constants';
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
export class ProviderConnectionInfo implements sqlops.ConnectionInfo {
export class ProviderConnectionInfo extends Disposable implements sqlops.ConnectionInfo {
options: { [name: string]: any };
options: { [name: string]: any } = {};
public providerName: string;
private _providerName: string;
protected _serverCapabilities: sqlops.DataProtocolServerCapabilities;
private static readonly SqlAuthentication = 'SqlLogin';
public static readonly ProviderPropertyName = 'providerName';
public constructor(serverCapabilities?: sqlops.DataProtocolServerCapabilities, model?: interfaces.IConnectionProfile) {
this.options = {};
if (serverCapabilities) {
this._serverCapabilities = serverCapabilities;
this.providerName = serverCapabilities.providerName;
}
if (model) {
if (model.options && this._serverCapabilities) {
this._serverCapabilities.connectionProvider.options.forEach(option => {
let value = model.options[option.name];
this.options[option.name] = value;
});
public constructor(
protected capabilitiesService: ICapabilitiesService,
model: string | interfaces.IConnectionProfile
) {
super();
// we can't really do a whole lot if we don't have a provider
if (isString(model) || (model && model.providerName)) {
this.providerName = isString(model) ? model : model.providerName;
if (!isString(model)) {
if (model.options && this._serverCapabilities) {
this._serverCapabilities.connectionProvider.options.forEach(option => {
let value = model.options[option.name];
this.options[option.name] = value;
});
}
this.serverName = model.serverName;
this.authenticationType = model.authenticationType;
this.databaseName = model.databaseName;
this.password = model.password;
this.userName = model.userName;
}
this.serverName = model.serverName;
this.authenticationType = model.authenticationType;
this.databaseName = model.databaseName;
this.password = model.password;
this.userName = model.userName;
}
}
public get providerName(): string {
return this._providerName;
}
public set providerName(name: string) {
this._providerName = name;
if (!this._serverCapabilities) {
this._serverCapabilities = this.capabilitiesService.getCapabilities(this.providerName);
this._register(this.capabilitiesService.onCapabilitiesRegistered(e => {
if (e === this.providerName) {
this._serverCapabilities = this.capabilitiesService.getCapabilities(e);
}
}));
}
}
public clone(): ProviderConnectionInfo {
let instance = new ProviderConnectionInfo(this._serverCapabilities);
let instance = new ProviderConnectionInfo(this.capabilitiesService, this.providerName);
instance.options = Object.assign({}, this.options);
instance.providerName = this.providerName;
return instance;
}
@@ -51,10 +74,6 @@ export class ProviderConnectionInfo implements sqlops.ConnectionInfo {
return this._serverCapabilities;
}
public setServerCapabilities(value: sqlops.DataProtocolServerCapabilities) {
this._serverCapabilities = value;
}
public get serverName(): string {
return this.getSpecialTypeOptionValue(ConnectionOptionSpecialType.serverName);
}

View File

@@ -65,13 +65,12 @@ export class ConnectionDialogService implements IConnectionDialogService {
private _connectionManagementService: IConnectionManagementService;
private _container: HTMLElement;
private _connectionDialog: ConnectionDialogWidget;
private _connectionControllerMap: { [providerDisplayName: string]: IConnectionComponentController };
private _connectionControllerMap: { [providerDisplayName: string]: IConnectionComponentController } = {};
private _model: ConnectionProfile;
private _params: INewConnectionParams;
private _inputModel: IConnectionProfile;
private _capabilitiesMaps: { [providerDisplayName: string]: sqlops.DataProtocolServerCapabilities };
private _providerNameToDisplayNameMap: { [providerDisplayName: string]: string };
private _providerTypes: string[];
private _providerNameToDisplayNameMap: { [providerDisplayName: string]: string } = {};
private _providerTypes: string[] = [];
private _currentProviderType: string = 'Microsoft SQL Server';
private _connecting: boolean = false;
private _connectionErrorTitle = localize('connectionError', 'Connection error');
@@ -85,29 +84,11 @@ export class ConnectionDialogService implements IConnectionDialogService {
@IWindowsService private _windowsService: IWindowsService,
@IClipboardService private _clipboardService: IClipboardService,
@ICommandService private _commandService: ICommandService
) {
this._capabilitiesMaps = {};
this._providerNameToDisplayNameMap = {};
this._connectionControllerMap = {};
this._providerTypes = [];
if (_capabilitiesService) {
_capabilitiesService.onProviderRegisteredEvent((capabilities => {
let defaultProvider = this.getDefaultProviderName();
if (capabilities.providerName === defaultProvider) {
this.showDialogWithModel();
}
}));
}
}
) { }
private getDefaultProviderName() {
if (this._workspaceConfigurationService) {
let defaultProvider = WorkbenchUtils.getSqlConfigValue<string>(this._workspaceConfigurationService, Constants.defaultEngine);
if (defaultProvider
&& this._capabilitiesMaps
&& defaultProvider in this._capabilitiesMaps) {
return defaultProvider;
}
}
// as a fallback, default to MSSQL if the value from settings is not available
return Constants.mssqlProviderName;
@@ -209,7 +190,7 @@ export class ConnectionDialogService implements IConnectionDialogService {
// Set the model name, initialize the controller if needed, and return the controller
this._model.providerName = providerName;
if (!this._connectionControllerMap[providerName]) {
this._connectionControllerMap[providerName] = this._instantiationService.createInstance(ConnectionController, this._container, this._connectionManagementService, this._capabilitiesMaps[providerName], {
this._connectionControllerMap[providerName] = this._instantiationService.createInstance(ConnectionController, this._container, this._connectionManagementService, this._capabilitiesService.getCapabilities(providerName), {
onSetConnectButton: (enable: boolean) => this.handleSetConnectButtonEnable(enable)
}, providerName);
}
@@ -222,7 +203,7 @@ export class ConnectionDialogService implements IConnectionDialogService {
private handleShowUiComponent(input: OnShowUIResponse) {
this._currentProviderType = input.selectedProviderType;
this._model = new ConnectionProfile(this._capabilitiesMaps[this.getCurrentProviderName()], this._model);
this._model = new ConnectionProfile(this._capabilitiesService, this._model);
this.uiController.showUiComponent(input.container);
}
@@ -249,9 +230,11 @@ export class ConnectionDialogService implements IConnectionDialogService {
private updateModelServerCapabilities(model: IConnectionProfile) {
this._model = this.createModel(model);
this._currentProviderType = this._providerNameToDisplayNameMap[this._model.providerName];
if (this._connectionDialog) {
this._connectionDialog.updateProvider(this._currentProviderType);
if (this._model.providerName) {
this._currentProviderType = this._providerNameToDisplayNameMap[this._model.providerName];
if (this._connectionDialog) {
this._connectionDialog.updateProvider(this._currentProviderType);
}
}
}
@@ -259,8 +242,7 @@ export class ConnectionDialogService implements IConnectionDialogService {
let defaultProvider = this.getDefaultProviderName();
let providerName = model ? model.providerName : defaultProvider;
providerName = providerName ? providerName : defaultProvider;
let serverCapabilities = this._capabilitiesMaps[providerName];
let newProfile = new ConnectionProfile(serverCapabilities, model);
let newProfile = new ConnectionProfile(this._capabilitiesService, model || providerName);
newProfile.saveProfile = true;
newProfile.generateNewId();
// If connecting from a query editor set "save connection" to false
@@ -270,23 +252,11 @@ export class ConnectionDialogService implements IConnectionDialogService {
return newProfile;
}
private cacheCapabilities(capabilities: sqlops.DataProtocolServerCapabilities) {
if (capabilities) {
this._providerTypes.push(capabilities.providerDisplayName);
this._capabilitiesMaps[capabilities.providerName] = capabilities;
this._providerNameToDisplayNameMap[capabilities.providerName] = capabilities.providerDisplayName;
}
}
private showDialogWithModel(): TPromise<void> {
return new TPromise<void>((resolve, reject) => {
if (this.getDefaultProviderName() in this._capabilitiesMaps) {
this.updateModelServerCapabilities(this._inputModel);
this.doShowDialog(this._params);
}
let none: void;
resolve(none);
this.updateModelServerCapabilities(this._inputModel);
this.doShowDialog(this._params);
resolve(null);
});
}
@@ -305,14 +275,14 @@ export class ConnectionDialogService implements IConnectionDialogService {
let capabilitiesPromise: Promise<void> = Promise.resolve();
if (this._providerTypes.length === 0) {
capabilitiesPromise = this._capabilitiesService.onCapabilitiesReady().then(() => {
let capabilities = this._capabilitiesService.getCapabilities();
capabilities.forEach(c => {
this.cacheCapabilities(c);
this._capabilitiesService.providers.map(p => {
let capabilities = this._capabilitiesService.getCapabilities(p);
this._providerTypes.push(capabilities.providerDisplayName);
this._providerNameToDisplayNameMap[capabilities.providerName] = capabilities.providerDisplayName;
});
});
}
capabilitiesPromise.then(success => {
capabilitiesPromise.then(s => {
this.updateModelServerCapabilities(model);
// If connecting from a query editor set "save connection" to false
if (params && params.input && params.connectionType === ConnectionType.editor) {
@@ -324,7 +294,7 @@ export class ConnectionDialogService implements IConnectionDialogService {
this.showErrorDialog(Severity.Error, this._connectionErrorTitle, connectionResult.errorMessage, connectionResult.callStack);
}
}));
}, err => reject(err));
}, e => reject(e));
});
}

View File

@@ -274,7 +274,7 @@ export class ConnectionDialogWidget extends Modal {
resolve(confirmed);
});
//this._messageService.confirm(confirm).then(confirmation => {
//this._messageService.confirm(confirm).then(confirmation => {
// if (!confirmation.confirmed) {
// return TPromise.as(false);
// } else {
@@ -453,7 +453,6 @@ export class ConnectionDialogWidget extends Modal {
public updateProvider(displayName: string) {
this._providerTypeSelectBox.selectWithOptionName(displayName);
this.onProviderTypeSelected(displayName);
}
public set databaseDropdownExpanded(val: boolean) {

View File

@@ -105,7 +105,7 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
this._register(toDisposableSubscription(this._bootstrap.metadataService.databaseNames.subscribe(
data => {
let profileData = data.map(d => {
let profile = new ConnectionProfile(currentProfile.serverCapabilities, currentProfile);
let profile = new ConnectionProfile(this._bootstrap.capabilitiesService, currentProfile);
profile.databaseName = d;
return profile;
});

View File

@@ -22,6 +22,7 @@ import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { TPromise } from 'vs/base/common/winjs.base';
import * as ConnectionUtils from 'sql/parts/connection/common/utils';
import { ProviderConnectionInfo } from 'sql/parts/connection/common/providerConnectionInfo';
import { ServiceOption } from 'sqlops';
export class BackupService implements IBackupService {
@@ -88,7 +89,6 @@ export class BackupUiService implements IBackupUiService {
public _serviceBrand: any;
private _backupDialogs: { [providerName: string]: BackupDialog | OptionsDialog } = {};
private _currentProvider: string;
private _optionsMap: { [providerName: string]: sqlops.ServiceOption[] } = {};
private _optionValues: { [optionName: string]: any } = {};
private _connectionUri: string;
private static _connectionUniqueId: number = 0;
@@ -115,20 +115,22 @@ export class BackupUiService implements IBackupUiService {
});
}
private getOptions(provider: string): ServiceOption[] {
let feature = this._capabilitiesService.getCapabilities(this._currentProvider).features.find(f => f.featureName === 'backup');
if (feature) {
return feature.optionsMetadata;
} else {
return undefined;
}
}
public showBackupDialog(connection: IConnectionProfile): TPromise<void> {
let self = this;
self._connectionUri = ConnectionUtils.generateUri(connection);
self._currentProvider = connection.providerName;
let backupDialog = self._backupDialogs[self._currentProvider];
if (!backupDialog) {
let capabilitiesList = this._capabilitiesService.getCapabilities();
capabilitiesList.forEach(providerCapabilities => {
let backupFeature = providerCapabilities.features.find(feature => feature.featureName === 'backup');
if (backupFeature && backupFeature.optionsMetadata) {
this._optionsMap[providerCapabilities.providerName] = backupFeature.optionsMetadata;
}
});
let backupOptions = self._optionsMap[self._currentProvider];
let backupOptions = this.getOptions(this._currentProvider);
if (backupOptions) {
backupDialog = self._instantiationService ? self._instantiationService.createInstance(
OptionsDialog, 'Backup database - ' + connection.serverName + ':' + connection.databaseName, 'BackupOptions', undefined) : undefined;
@@ -141,7 +143,7 @@ export class BackupUiService implements IBackupUiService {
self._backupDialogs[self._currentProvider] = backupDialog;
}
let backupOptions = this._optionsMap[self._currentProvider];
let backupOptions = this.getOptions(this._currentProvider);
return new TPromise<void>(() => {
if (backupOptions) {
(backupDialog as OptionsDialog).open(backupOptions, self._optionValues);

View File

@@ -139,7 +139,7 @@ export class RestoreDialogController implements IRestoreDialogController {
private _sessionId: string;
private readonly _restoreFeature = 'Restore';
private readonly _restoreTaskName: string = 'Restore Database';
private readonly _restoreCompleted : string = 'Completed';
private readonly _restoreCompleted: string = 'Completed';
private _optionValues: { [optionName: string]: any } = {};
constructor(
@@ -178,11 +178,11 @@ export class RestoreDialogController implements IRestoreDialogController {
private isSuccessfulRestore(response: TaskNode): boolean {
return (response.taskName === this._restoreTaskName &&
response.message === this._restoreCompleted &&
(response.status === TaskStatus.succeeded ||
response.status === TaskStatus.succeededWithWarning) &&
(response.taskExecutionMode === TaskExecutionMode.execute ||
response.taskExecutionMode === TaskExecutionMode.executeAndScript));
response.message === this._restoreCompleted &&
(response.status === TaskStatus.succeeded ||
response.status === TaskStatus.succeededWithWarning) &&
(response.taskExecutionMode === TaskExecutionMode.execute ||
response.taskExecutionMode === TaskExecutionMode.executeAndScript));
}
private handleMssqlOnValidateFile(overwriteTargetDatabase: boolean = false): void {
@@ -266,7 +266,7 @@ export class RestoreDialogController implements IRestoreDialogController {
private getRestoreOption(): sqlops.ServiceOption[] {
let options: sqlops.ServiceOption[] = [];
let providerId: string = this.getCurrentProviderId();
let providerCapabilities = this._capabilitiesService.getCapabilities().find(c => c.providerName === providerId);
let providerCapabilities = this._capabilitiesService.getCapabilities(providerId);
if (providerCapabilities) {
let restoreMetadataProvider = providerCapabilities.features.find(f => f.featureName === this._restoreFeature);

View File

@@ -38,6 +38,7 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { MenuRegistry, ExecuteCommandAction } from 'vs/platform/actions/common/actions';
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
const labelDisplay = nls.localize("insights.item", "Item");
const valueDisplay = nls.localize("insights.value", "Value");
@@ -129,7 +130,8 @@ export class InsightsDialogView extends Modal {
@IContextMenuService private _contextMenuService: IContextMenuService,
@ITelemetryService telemetryService: ITelemetryService,
@IContextKeyService contextKeyService: IContextKeyService,
@ICommandService private _commandService: ICommandService
@ICommandService private _commandService: ICommandService,
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService
) {
super(nls.localize("InsightsDialogTitle", "Insights"), TelemetryKeys.Insights, partService, telemetryService, contextKeyService);
this._model.onDataChange(e => this.build());
@@ -388,7 +390,7 @@ export class InsightsDialogView extends Modal {
}
let currentProfile = this._connectionProfile as ConnectionProfile;
let profile = new ConnectionProfile(currentProfile.serverCapabilities, currentProfile);
let profile = new ConnectionProfile(this._capabilitiesService, currentProfile);
profile.databaseName = database;
profile.serverName = server;
profile.userName = user;

View File

@@ -19,6 +19,7 @@ import * as TelemetryUtils from 'sql/common/telemetryUtilities';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { warn, error } from 'sql/base/common/log';
import { ServerTreeView } from 'sql/parts/registeredServer/viewlet/serverTreeView';
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
export const SERVICE_ID = 'ObjectExplorerService';
@@ -102,7 +103,8 @@ export class ObjectExplorerService implements IObjectExplorerService {
constructor(
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@ITelemetryService private _telemetryService: ITelemetryService
@ITelemetryService private _telemetryService: ITelemetryService,
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService
) {
this._onUpdateObjectExplorerNodes = new Emitter<ObjectExplorerNodeEventArgs>();
this._activeObjectExplorerNodes = {};
@@ -124,8 +126,7 @@ export class ObjectExplorerService implements IObjectExplorerService {
public updateObjectExplorerNodes(connection: IConnectionProfile): Promise<void> {
return this._connectionManagementService.addSavedPassword(connection).then(withPassword => {
let connectionProfile = ConnectionProfile.convertToConnectionProfile(
this._connectionManagementService.getCapabilities(connection.providerName), withPassword);
let connectionProfile = ConnectionProfile.fromIConnectionProfile(this._capabilitiesService, withPassword);
return this.updateNewObjectExplorerNode(connectionProfile);
});
}

View File

@@ -7,19 +7,32 @@
import { ConnectionManagementInfo } from 'sql/parts/connection/common/connectionManagementInfo';
import * as Constants from 'sql/common/constants';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Deferred } from 'sql/base/common/promise';
import * as sqlops from 'sqlops';
import Event, { Emitter } from 'vs/base/common/event';
import { IAction } from 'vs/base/common/actions';
import { Deferred } from 'sql/base/common/promise';
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IExtensionManagementService, ILocalExtension, IExtensionEnablementService, LocalExtensionType } from 'vs/platform/extensionManagement/common/extensionManagement';
import { Memento } from 'vs/workbench/common/memento';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
import { IStorageService } from 'vs/platform/storage/common/storage';
export const SERVICE_ID = 'capabilitiesService';
export const HOST_NAME = 'sqlops';
export const HOST_VERSION = '1.0';
interface IProtocolMomento {
[id: string]: sqlops.DataProtocolServerCapabilities;
}
export const clientCapabilities = {
hostName: HOST_NAME,
hostVersion: HOST_VERSION
};
export const ICapabilitiesService = createDecorator<ICapabilitiesService>(SERVICE_ID);
/**
@@ -31,7 +44,7 @@ export interface ICapabilitiesService {
/**
* Retrieve a list of registered capabilities providers
*/
getCapabilities(): sqlops.DataProtocolServerCapabilities[];
getCapabilities(provider: string): sqlops.DataProtocolServerCapabilities;
/**
* Register a capabilities provider
@@ -43,43 +56,38 @@ export interface ICapabilitiesService {
*/
isFeatureAvailable(action: IAction, connectionManagementInfo: ConnectionManagementInfo): boolean;
/**
* Event raised when a provider is registered
*/
onProviderRegisteredEvent: Event<sqlops.DataProtocolServerCapabilities>;
/**
* Promise fulfilled when Capabilities are ready
*/
onCapabilitiesReady(): Promise<void>;
/**
* When a new capabilities is registered, it emits the provider name, be to use to get the new capabilities
*/
readonly onCapabilitiesRegistered: Event<string>;
/**
* Get an array of all known providers
*/
readonly providers: string[];
}
/**
* Capabilities service implementation class. This class provides the ability
* to discover the DMP capabilties that a DMP provider offers.
*/
export class CapabilitiesService implements ICapabilitiesService {
export class CapabilitiesService extends Disposable implements ICapabilitiesService {
public _serviceBrand: any;
private _momento = new Memento('capabilitiesCache');
private static DATA_PROVIDER_CATEGORY: string = 'Data Provider';
private _providers: sqlops.CapabilitiesProvider[] = [];
private _capabilities: sqlops.DataProtocolServerCapabilities[] = [];
private _onProviderRegistered: Emitter<sqlops.DataProtocolServerCapabilities>;
private _clientCapabilties: sqlops.DataProtocolClientCapabilities = {
hostName: HOST_NAME,
hostVersion: HOST_VERSION
};
private disposables: IDisposable[] = [];
private _onCapabilitiesReady: Deferred<void>;
private _onCapabilitiesReady = new Deferred<void>();
// Setting this to 1 by default as we have MS SQL provider by default and then we increament
// this number based on extensions installed.
@@ -89,12 +97,15 @@ export class CapabilitiesService implements ICapabilitiesService {
private _registeredCapabilities: number = 0;
constructor( @IExtensionManagementService private extensionManagementService: IExtensionManagementService,
@IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService) {
private _onCapabilitiesRegistered = this._register(new Emitter<string>());
public readonly onCapabilitiesRegistered = this._onCapabilitiesRegistered.event;
this._onProviderRegistered = new Emitter<sqlops.DataProtocolServerCapabilities>();
this.disposables.push(this._onProviderRegistered);
this._onCapabilitiesReady = new Deferred();
constructor(
@IExtensionManagementService private extensionManagementService: IExtensionManagementService,
@IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService,
@IStorageService private _storageService: IStorageService
) {
super();
// Get extensions and filter where the category has 'Data Provider' in it
this.extensionManagementService.getInstalled(LocalExtensionType.User).then((extensions: ILocalExtension[]) => {
@@ -140,8 +151,16 @@ export class CapabilitiesService implements ICapabilitiesService {
/**
* Retrieve a list of registered server capabilities
*/
public getCapabilities(): sqlops.DataProtocolServerCapabilities[] {
return this._capabilities;
public getCapabilities(provider: string): sqlops.DataProtocolServerCapabilities {
return this.capabilities[provider];
}
public get providers(): string[] {
return Object.keys(this.capabilities);
}
private get capabilities(): IProtocolMomento {
return this._momento.getMemento(this._storageService) as IProtocolMomento;
}
/**
@@ -149,12 +168,11 @@ export class CapabilitiesService implements ICapabilitiesService {
* @param provider
*/
public registerProvider(provider: sqlops.CapabilitiesProvider): void {
this._providers.push(provider);
// request the capabilities from server
provider.getServerCapabilities(this._clientCapabilties).then(serverCapabilities => {
this._capabilities.push(serverCapabilities);
this._onProviderRegistered.fire(serverCapabilities);
provider.getServerCapabilities(clientCapabilities).then(serverCapabilities => {
this.capabilities[serverCapabilities.providerName] = serverCapabilities;
this._momento.saveMemento();
this._onCapabilitiesRegistered.fire(serverCapabilities.providerName);
this._registeredCapabilities++;
this.resolveCapabilitiesIfReady();
});
@@ -198,13 +216,4 @@ export class CapabilitiesService implements ICapabilitiesService {
}
}
// Event Emitters
public get onProviderRegisteredEvent(): Event<sqlops.DataProtocolServerCapabilities> {
return this._onProviderRegistered.event;
}
public dispose(): void {
this.disposables = dispose(this.disposables);
}
}

View File

@@ -74,7 +74,7 @@ export class SerializationService implements ISerializationService {
public getSerializationFeatureMetadataProvider(ownerUri: string): sqlops.FeatureMetadataProvider {
let providerId: string = this._connectionService.getProviderIdFromUri(ownerUri);
let providerCapabilities = this._capabilitiesService.getCapabilities().find(c => c.providerName === providerId);
let providerCapabilities = this._capabilitiesService.getCapabilities(providerId);
if (providerCapabilities) {
return providerCapabilities.features.find(f => f.featureName === SERVICE_ID);