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; return result;
} }
} }

View File

@@ -43,19 +43,12 @@ export class AdminService implements IAdminService {
private _providers: { [handle: string]: sqlops.AdminServicesProvider; } = Object.create(null); private _providers: { [handle: string]: sqlops.AdminServicesProvider; } = Object.create(null);
private _providerOptions: { [handle: string]: sqlops.AdminServicesOptions; } = Object.create(null);
constructor( constructor(
@IInstantiationService private _instantiationService: IInstantiationService, @IInstantiationService private _instantiationService: IInstantiationService,
@IWorkbenchEditorService private _editorService: IWorkbenchEditorService, @IWorkbenchEditorService private _editorService: IWorkbenchEditorService,
@IConnectionManagementService private _connectionService: IConnectionManagementService, @IConnectionManagementService private _connectionService: IConnectionManagementService,
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService @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> { 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 { export class ConnectionConfig implements IConnectionConfig {
private _providerCapabilitiesMap: { [providerName: string]: sqlops.DataProtocolServerCapabilities };
/** /**
* Constructor. * Constructor.
*/ */
public constructor( public constructor(
private _configurationEditService: ConfigurationEditingService, private _configurationEditService: ConfigurationEditingService,
private _workspaceConfigurationService: IWorkspaceConfigurationService, private _workspaceConfigurationService: IWorkspaceConfigurationService,
private _capabilitiesService: ICapabilitiesService, 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);
});
}
}
/** /**
* Returns connection groups from user and workspace settings. * Returns connection groups from user and workspace settings.
@@ -81,44 +63,6 @@ export class ConnectionConfig implements IConnectionConfig {
return allGroups; 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. * Add a new connection to the connection config.
*/ */
@@ -131,14 +75,12 @@ export class ConnectionConfig implements IConnectionConfig {
profiles = []; profiles = [];
} }
let providerCapabilities = this.getCapabilities(profile.providerName); let connectionProfile = this.getConnectionProfileInstance(profile, groupId);
let connectionProfile = this.getConnectionProfileInstance(profile, groupId, providerCapabilities); let newProfile = ConnectionProfile.convertToProfileStore(this._capabilitiesService, connectionProfile);
let newProfile = ConnectionProfile.convertToProfileStore(providerCapabilities, connectionProfile);
// Remove the profile if already set // Remove the profile if already set
var sameProfileInList = profiles.find(value => { var sameProfileInList = profiles.find(value => {
let providerCapabilities = this.getCapabilities(value.providerName); let providerConnectionProfile = ConnectionProfile.createFromStoredProfile(value, this._capabilitiesService);
let providerConnectionProfile = ConnectionProfile.createFromStoredProfile(value, providerCapabilities);
return providerConnectionProfile.matches(connectionProfile); return providerConnectionProfile.matches(connectionProfile);
}); });
if (sameProfileInList) { 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; let connectionProfile = profile as ConnectionProfile;
if (connectionProfile === undefined) { if (connectionProfile === undefined) {
connectionProfile = new ConnectionProfile(providerCapabilities, profile); connectionProfile = new ConnectionProfile(this._capabilitiesService, profile);
} }
connectionProfile.groupId = groupId; connectionProfile.groupId = groupId;
return connectionProfile; return connectionProfile;
@@ -286,15 +228,7 @@ export class ConnectionConfig implements IConnectionConfig {
} }
let connectionProfiles = profiles.map(p => { let connectionProfiles = profiles.map(p => {
let capabilitiesForProvider = this.getCapabilities(p.providerName); return ConnectionProfile.createFromStoredProfile(p, this._capabilitiesService);
let providerConnectionProfile = ConnectionProfile.createFromStoredProfile(p, capabilitiesForProvider);
providerConnectionProfile.setServerCapabilities(capabilitiesForProvider);
this._capabilitiesService.onProviderRegisteredEvent((serverCapabilities) => {
providerConnectionProfile.onProviderRegistered(serverCapabilities);
});
return providerConnectionProfile;
}); });
return connectionProfiles; return connectionProfiles;
@@ -308,8 +242,7 @@ export class ConnectionConfig implements IConnectionConfig {
let profiles = this._workspaceConfigurationService.inspect<IConnectionProfileStore[]>(Constants.connectionsArrayName).user; let profiles = this._workspaceConfigurationService.inspect<IConnectionProfileStore[]>(Constants.connectionsArrayName).user;
// Remove the profile from the connections // Remove the profile from the connections
profiles = profiles.filter(value => { profiles = profiles.filter(value => {
let providerCapabilities = this.getCapabilities(value.providerName); let providerConnectionProfile = ConnectionProfile.createFromStoredProfile(value, this._capabilitiesService);
let providerConnectionProfile = ConnectionProfile.createFromStoredProfile(value, providerCapabilities);
return providerConnectionProfile.getOptionsKey() !== profile.getOptionsKey(); return providerConnectionProfile.getOptionsKey() !== profile.getOptionsKey();
}); });
@@ -330,8 +263,7 @@ export class ConnectionConfig implements IConnectionConfig {
let profiles = this._workspaceConfigurationService.inspect<IConnectionProfileStore[]>(Constants.connectionsArrayName).user; let profiles = this._workspaceConfigurationService.inspect<IConnectionProfileStore[]>(Constants.connectionsArrayName).user;
// Remove the profiles from the connections // Remove the profiles from the connections
profiles = profiles.filter(value => { profiles = profiles.filter(value => {
let providerCapabilities = this.getCapabilities(value.providerName); let providerConnectionProfile = ConnectionProfile.createFromStoredProfile(value, this._capabilitiesService);
let providerConnectionProfile = ConnectionProfile.createFromStoredProfile(value, providerCapabilities);
return !connections.some((val) => val.getOptionsKey() === providerConnectionProfile.getOptionsKey()); 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 : let profiles = target === ConfigurationTarget.USER ? this._workspaceConfigurationService.inspect<IConnectionProfileStore[]>(Constants.connectionsArrayName).user :
this._workspaceConfigurationService.inspect<IConnectionProfileStore[]>(Constants.connectionsArrayName).workspace; this._workspaceConfigurationService.inspect<IConnectionProfileStore[]>(Constants.connectionsArrayName).workspace;
if (profiles) { if (profiles) {
let providerCapabilities = this.getCapabilities(profile.providerName);
if (profile.parent && profile.parent.id === Constants.unsavedGroupId) { if (profile.parent && profile.parent.id === Constants.unsavedGroupId) {
profile.groupId = newGroupID; profile.groupId = newGroupID;
profiles.push(ConnectionProfile.convertToProfileStore(providerCapabilities, profile)); profiles.push(ConnectionProfile.convertToProfileStore(this._capabilitiesService, profile));
} else { } else {
profiles.forEach((value) => { profiles.forEach((value) => {
let configProf = ConnectionProfile.createFromStoredProfile(value, providerCapabilities); let configProf = ConnectionProfile.createFromStoredProfile(value, this._capabilitiesService);
if (configProf.getOptionsKey() === profile.getOptionsKey()) { if (configProf.getOptionsKey() === profile.getOptionsKey()) {
value.groupId = newGroupID; value.groupId = newGroupID;
} }

View File

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

View File

@@ -137,9 +137,9 @@ export class ConnectionManagementService implements IConnectionManagementService
100 /* High Priority */ 100 /* High Priority */
)); ));
if (_capabilitiesService && _capabilitiesService.onProviderRegisteredEvent) { if (_capabilitiesService) {
_capabilitiesService.onProviderRegisteredEvent((capabilities => { _capabilitiesService.onCapabilitiesRegistered((p => {
if (capabilities.providerName === 'MSSQL') { if (p === 'MSSQL') {
if (!this.hasRegisteredServers()) { if (!this.hasRegisteredServers()) {
// prompt the user for a new connection on startup if no profiles are registered // prompt the user for a new connection on startup if no profiles are registered
this.showConnectionDialog(); this.showConnectionDialog();
@@ -679,21 +679,13 @@ export class ConnectionManagementService implements IConnectionManagementService
return Object.keys(this._providers); 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[] { public getAdvancedProperties(): sqlops.ConnectionOption[] {
let capabilities = this._capabilitiesService.getCapabilities(); let providers = this._capabilitiesService.providers;
if (capabilities !== undefined && capabilities.length > 0) { if (providers !== undefined && providers.length > 0) {
// just grab the first registered provider for now, this needs to change // just grab the first registered provider for now, this needs to change
// to lookup based on currently select provider // to lookup based on currently select provider
let providerCapabilities = capabilities[0]; let providerCapabilities = this._capabilitiesService.getCapabilities(providers[0]);
if (!!providerCapabilities.connectionProvider) { if (!!providerCapabilities.connectionProvider) {
return providerCapabilities.connectionProvider.options; return providerCapabilities.connectionProvider.options;
} }
@@ -1362,7 +1354,7 @@ export class ConnectionManagementService implements IConnectionManagementService
} }
// Find the password option for the connection provider // 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); option => option.specialValueType === ConnectionOptionSpecialType.password);
if (!passwordOption) { if (!passwordOption) {
return undefined; 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 { equalsIgnoreCase } from 'vs/base/common/strings';
import { generateUuid } from 'vs/base/common/uuid'; import { generateUuid } from 'vs/base/common/uuid';
import * as objects from 'sql/base/common/objects'; 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 // Concrete implementation of the IConnectionProfile interface
@@ -28,9 +30,13 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
public saveProfile: boolean; public saveProfile: boolean;
public isDisconnecting: boolean = false; public isDisconnecting: boolean = false;
public constructor(serverCapabilities?: sqlops.DataProtocolServerCapabilities, model?: interfaces.IConnectionProfile) {
super(serverCapabilities, model); public constructor(
if (model) { capabilitiesService: ICapabilitiesService,
model: string | interfaces.IConnectionProfile
) {
super(capabilitiesService, model);
if (model && !isString(model)) {
this.groupId = model.groupId; this.groupId = model.groupId;
this.groupFullName = model.groupFullName; this.groupFullName = model.groupFullName;
this.savePassword = model.savePassword; this.savePassword = model.savePassword;
@@ -91,7 +97,7 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
} }
public clone(): ConnectionProfile { public clone(): ConnectionProfile {
let instance = new ConnectionProfile(this._serverCapabilities, this); let instance = new ConnectionProfile(this.capabilitiesService, this);
return instance; return instance;
} }
@@ -137,12 +143,6 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
return super.getOptionsKey(); return super.getOptionsKey();
} }
public onProviderRegistered(serverCapabilities: sqlops.DataProtocolServerCapabilities): void {
if (serverCapabilities.providerName === this.providerName) {
this.setServerCapabilities(serverCapabilities);
}
}
public toIConnectionProfile(): interfaces.IConnectionProfile { public toIConnectionProfile(): interfaces.IConnectionProfile {
let result: interfaces.IConnectionProfile = { let result: interfaces.IConnectionProfile = {
serverName: this.serverName, serverName: this.serverName,
@@ -170,8 +170,19 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
}; };
} }
public static createFromStoredProfile(profile: interfaces.IConnectionProfileStore, serverCapabilities: sqlops.DataProtocolServerCapabilities): ConnectionProfile { public static fromIConnectionProfile(capabilitiesService: ICapabilitiesService, profile: interfaces.IConnectionProfile) {
let connectionInfo = new ConnectionProfile(serverCapabilities, undefined); 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; connectionInfo.options = profile.options;
// append group ID and original display name to build unique OE session ID // 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; 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( public static convertToProfileStore(
serverCapabilities: sqlops.DataProtocolServerCapabilities, capabilitiesService: ICapabilitiesService,
connectionProfile: interfaces.IConnectionProfile): interfaces.IConnectionProfileStore { connectionProfile: interfaces.IConnectionProfile): interfaces.IConnectionProfileStore {
if (connectionProfile) { if (connectionProfile) {
let connectionInfo = ConnectionProfile.convertToConnectionProfile(serverCapabilities, connectionProfile); let connectionInfo = ConnectionProfile.fromIConnectionProfile(capabilitiesService, connectionProfile);
let profile: interfaces.IConnectionProfileStore = { let profile: interfaces.IConnectionProfileStore = {
options: {}, options: {},
groupId: connectionProfile.groupId, groupId: connectionProfile.groupId,
@@ -224,5 +218,4 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
return undefined; return undefined;
} }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -453,7 +453,6 @@ export class ConnectionDialogWidget extends Modal {
public updateProvider(displayName: string) { public updateProvider(displayName: string) {
this._providerTypeSelectBox.selectWithOptionName(displayName); this._providerTypeSelectBox.selectWithOptionName(displayName);
this.onProviderTypeSelected(displayName);
} }
public set databaseDropdownExpanded(val: boolean) { 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( this._register(toDisposableSubscription(this._bootstrap.metadataService.databaseNames.subscribe(
data => { data => {
let profileData = data.map(d => { let profileData = data.map(d => {
let profile = new ConnectionProfile(currentProfile.serverCapabilities, currentProfile); let profile = new ConnectionProfile(this._bootstrap.capabilitiesService, currentProfile);
profile.databaseName = d; profile.databaseName = d;
return profile; 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 { TPromise } from 'vs/base/common/winjs.base';
import * as ConnectionUtils from 'sql/parts/connection/common/utils'; import * as ConnectionUtils from 'sql/parts/connection/common/utils';
import { ProviderConnectionInfo } from 'sql/parts/connection/common/providerConnectionInfo'; import { ProviderConnectionInfo } from 'sql/parts/connection/common/providerConnectionInfo';
import { ServiceOption } from 'sqlops';
export class BackupService implements IBackupService { export class BackupService implements IBackupService {
@@ -88,7 +89,6 @@ export class BackupUiService implements IBackupUiService {
public _serviceBrand: any; public _serviceBrand: any;
private _backupDialogs: { [providerName: string]: BackupDialog | OptionsDialog } = {}; private _backupDialogs: { [providerName: string]: BackupDialog | OptionsDialog } = {};
private _currentProvider: string; private _currentProvider: string;
private _optionsMap: { [providerName: string]: sqlops.ServiceOption[] } = {};
private _optionValues: { [optionName: string]: any } = {}; private _optionValues: { [optionName: string]: any } = {};
private _connectionUri: string; private _connectionUri: string;
private static _connectionUniqueId: number = 0; 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> { public showBackupDialog(connection: IConnectionProfile): TPromise<void> {
let self = this; let self = this;
self._connectionUri = ConnectionUtils.generateUri(connection); self._connectionUri = ConnectionUtils.generateUri(connection);
self._currentProvider = connection.providerName; self._currentProvider = connection.providerName;
let backupDialog = self._backupDialogs[self._currentProvider]; let backupDialog = self._backupDialogs[self._currentProvider];
if (!backupDialog) { if (!backupDialog) {
let capabilitiesList = this._capabilitiesService.getCapabilities(); let backupOptions = this.getOptions(this._currentProvider);
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];
if (backupOptions) { if (backupOptions) {
backupDialog = self._instantiationService ? self._instantiationService.createInstance( backupDialog = self._instantiationService ? self._instantiationService.createInstance(
OptionsDialog, 'Backup database - ' + connection.serverName + ':' + connection.databaseName, 'BackupOptions', undefined) : undefined; OptionsDialog, 'Backup database - ' + connection.serverName + ':' + connection.databaseName, 'BackupOptions', undefined) : undefined;
@@ -141,7 +143,7 @@ export class BackupUiService implements IBackupUiService {
self._backupDialogs[self._currentProvider] = backupDialog; self._backupDialogs[self._currentProvider] = backupDialog;
} }
let backupOptions = this._optionsMap[self._currentProvider]; let backupOptions = this.getOptions(this._currentProvider);
return new TPromise<void>(() => { return new TPromise<void>(() => {
if (backupOptions) { if (backupOptions) {
(backupDialog as OptionsDialog).open(backupOptions, self._optionValues); (backupDialog as OptionsDialog).open(backupOptions, self._optionValues);

View File

@@ -139,7 +139,7 @@ export class RestoreDialogController implements IRestoreDialogController {
private _sessionId: string; private _sessionId: string;
private readonly _restoreFeature = 'Restore'; private readonly _restoreFeature = 'Restore';
private readonly _restoreTaskName: string = 'Restore Database'; private readonly _restoreTaskName: string = 'Restore Database';
private readonly _restoreCompleted : string = 'Completed'; private readonly _restoreCompleted: string = 'Completed';
private _optionValues: { [optionName: string]: any } = {}; private _optionValues: { [optionName: string]: any } = {};
constructor( constructor(
@@ -266,7 +266,7 @@ export class RestoreDialogController implements IRestoreDialogController {
private getRestoreOption(): sqlops.ServiceOption[] { private getRestoreOption(): sqlops.ServiceOption[] {
let options: sqlops.ServiceOption[] = []; let options: sqlops.ServiceOption[] = [];
let providerId: string = this.getCurrentProviderId(); let providerId: string = this.getCurrentProviderId();
let providerCapabilities = this._capabilitiesService.getCapabilities().find(c => c.providerName === providerId); let providerCapabilities = this._capabilitiesService.getCapabilities(providerId);
if (providerCapabilities) { if (providerCapabilities) {
let restoreMetadataProvider = providerCapabilities.features.find(f => f.featureName === this._restoreFeature); 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 { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { ICommandService } from 'vs/platform/commands/common/commands'; import { ICommandService } from 'vs/platform/commands/common/commands';
import { MenuRegistry, ExecuteCommandAction } from 'vs/platform/actions/common/actions'; import { MenuRegistry, ExecuteCommandAction } from 'vs/platform/actions/common/actions';
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
const labelDisplay = nls.localize("insights.item", "Item"); const labelDisplay = nls.localize("insights.item", "Item");
const valueDisplay = nls.localize("insights.value", "Value"); const valueDisplay = nls.localize("insights.value", "Value");
@@ -129,7 +130,8 @@ export class InsightsDialogView extends Modal {
@IContextMenuService private _contextMenuService: IContextMenuService, @IContextMenuService private _contextMenuService: IContextMenuService,
@ITelemetryService telemetryService: ITelemetryService, @ITelemetryService telemetryService: ITelemetryService,
@IContextKeyService contextKeyService: IContextKeyService, @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); super(nls.localize("InsightsDialogTitle", "Insights"), TelemetryKeys.Insights, partService, telemetryService, contextKeyService);
this._model.onDataChange(e => this.build()); this._model.onDataChange(e => this.build());
@@ -388,7 +390,7 @@ export class InsightsDialogView extends Modal {
} }
let currentProfile = this._connectionProfile as ConnectionProfile; let currentProfile = this._connectionProfile as ConnectionProfile;
let profile = new ConnectionProfile(currentProfile.serverCapabilities, currentProfile); let profile = new ConnectionProfile(this._capabilitiesService, currentProfile);
profile.databaseName = database; profile.databaseName = database;
profile.serverName = server; profile.serverName = server;
profile.userName = user; 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 { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { warn, error } from 'sql/base/common/log'; import { warn, error } from 'sql/base/common/log';
import { ServerTreeView } from 'sql/parts/registeredServer/viewlet/serverTreeView'; import { ServerTreeView } from 'sql/parts/registeredServer/viewlet/serverTreeView';
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
export const SERVICE_ID = 'ObjectExplorerService'; export const SERVICE_ID = 'ObjectExplorerService';
@@ -102,7 +103,8 @@ export class ObjectExplorerService implements IObjectExplorerService {
constructor( constructor(
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService, @IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@ITelemetryService private _telemetryService: ITelemetryService @ITelemetryService private _telemetryService: ITelemetryService,
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService
) { ) {
this._onUpdateObjectExplorerNodes = new Emitter<ObjectExplorerNodeEventArgs>(); this._onUpdateObjectExplorerNodes = new Emitter<ObjectExplorerNodeEventArgs>();
this._activeObjectExplorerNodes = {}; this._activeObjectExplorerNodes = {};
@@ -124,8 +126,7 @@ export class ObjectExplorerService implements IObjectExplorerService {
public updateObjectExplorerNodes(connection: IConnectionProfile): Promise<void> { public updateObjectExplorerNodes(connection: IConnectionProfile): Promise<void> {
return this._connectionManagementService.addSavedPassword(connection).then(withPassword => { return this._connectionManagementService.addSavedPassword(connection).then(withPassword => {
let connectionProfile = ConnectionProfile.convertToConnectionProfile( let connectionProfile = ConnectionProfile.fromIConnectionProfile(this._capabilitiesService, withPassword);
this._connectionManagementService.getCapabilities(connection.providerName), withPassword);
return this.updateNewObjectExplorerNode(connectionProfile); return this.updateNewObjectExplorerNode(connectionProfile);
}); });
} }

View File

@@ -7,19 +7,32 @@
import { ConnectionManagementInfo } from 'sql/parts/connection/common/connectionManagementInfo'; import { ConnectionManagementInfo } from 'sql/parts/connection/common/connectionManagementInfo';
import * as Constants from 'sql/common/constants'; import * as Constants from 'sql/common/constants';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Deferred } from 'sql/base/common/promise';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import * as sqlops from 'sqlops'; import * as sqlops from 'sqlops';
import Event, { Emitter } from 'vs/base/common/event'; import Event, { Emitter } from 'vs/base/common/event';
import { IAction } from 'vs/base/common/actions'; import { IAction } from 'vs/base/common/actions';
import { Deferred } from 'sql/base/common/promise';
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IExtensionManagementService, ILocalExtension, IExtensionEnablementService, LocalExtensionType } from 'vs/platform/extensionManagement/common/extensionManagement'; 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 SERVICE_ID = 'capabilitiesService';
export const HOST_NAME = 'sqlops'; export const HOST_NAME = 'sqlops';
export const HOST_VERSION = '1.0'; 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); export const ICapabilitiesService = createDecorator<ICapabilitiesService>(SERVICE_ID);
/** /**
@@ -31,7 +44,7 @@ export interface ICapabilitiesService {
/** /**
* Retrieve a list of registered capabilities providers * Retrieve a list of registered capabilities providers
*/ */
getCapabilities(): sqlops.DataProtocolServerCapabilities[]; getCapabilities(provider: string): sqlops.DataProtocolServerCapabilities;
/** /**
* Register a capabilities provider * Register a capabilities provider
@@ -43,43 +56,38 @@ export interface ICapabilitiesService {
*/ */
isFeatureAvailable(action: IAction, connectionManagementInfo: ConnectionManagementInfo): boolean; isFeatureAvailable(action: IAction, connectionManagementInfo: ConnectionManagementInfo): boolean;
/**
* Event raised when a provider is registered
*/
onProviderRegisteredEvent: Event<sqlops.DataProtocolServerCapabilities>;
/** /**
* Promise fulfilled when Capabilities are ready * Promise fulfilled when Capabilities are ready
*/ */
onCapabilitiesReady(): Promise<void>; 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 * Capabilities service implementation class. This class provides the ability
* to discover the DMP capabilties that a DMP provider offers. * 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; public _serviceBrand: any;
private _momento = new Memento('capabilitiesCache');
private static DATA_PROVIDER_CATEGORY: string = 'Data Provider'; 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 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 // Setting this to 1 by default as we have MS SQL provider by default and then we increament
// this number based on extensions installed. // this number based on extensions installed.
@@ -89,12 +97,15 @@ export class CapabilitiesService implements ICapabilitiesService {
private _registeredCapabilities: number = 0; private _registeredCapabilities: number = 0;
constructor( @IExtensionManagementService private extensionManagementService: IExtensionManagementService, private _onCapabilitiesRegistered = this._register(new Emitter<string>());
@IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService) { public readonly onCapabilitiesRegistered = this._onCapabilitiesRegistered.event;
this._onProviderRegistered = new Emitter<sqlops.DataProtocolServerCapabilities>(); constructor(
this.disposables.push(this._onProviderRegistered); @IExtensionManagementService private extensionManagementService: IExtensionManagementService,
this._onCapabilitiesReady = new Deferred(); @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService,
@IStorageService private _storageService: IStorageService
) {
super();
// Get extensions and filter where the category has 'Data Provider' in it // Get extensions and filter where the category has 'Data Provider' in it
this.extensionManagementService.getInstalled(LocalExtensionType.User).then((extensions: ILocalExtension[]) => { this.extensionManagementService.getInstalled(LocalExtensionType.User).then((extensions: ILocalExtension[]) => {
@@ -140,8 +151,16 @@ export class CapabilitiesService implements ICapabilitiesService {
/** /**
* Retrieve a list of registered server capabilities * Retrieve a list of registered server capabilities
*/ */
public getCapabilities(): sqlops.DataProtocolServerCapabilities[] { public getCapabilities(provider: string): sqlops.DataProtocolServerCapabilities {
return this._capabilities; 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 * @param provider
*/ */
public registerProvider(provider: sqlops.CapabilitiesProvider): void { public registerProvider(provider: sqlops.CapabilitiesProvider): void {
this._providers.push(provider);
// request the capabilities from server // request the capabilities from server
provider.getServerCapabilities(this._clientCapabilties).then(serverCapabilities => { provider.getServerCapabilities(clientCapabilities).then(serverCapabilities => {
this._capabilities.push(serverCapabilities); this.capabilities[serverCapabilities.providerName] = serverCapabilities;
this._onProviderRegistered.fire(serverCapabilities); this._momento.saveMemento();
this._onCapabilitiesRegistered.fire(serverCapabilities.providerName);
this._registeredCapabilities++; this._registeredCapabilities++;
this.resolveCapabilitiesIfReady(); 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 { public getSerializationFeatureMetadataProvider(ownerUri: string): sqlops.FeatureMetadataProvider {
let providerId: string = this._connectionService.getProviderIdFromUri(ownerUri); 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) { if (providerCapabilities) {
return providerCapabilities.features.find(f => f.featureName === SERVICE_ID); return providerCapabilities.features.find(f => f.featureName === SERVICE_ID);

View File

@@ -11,9 +11,11 @@ import { IConnectionProfile, IConnectionProfileStore } from 'sql/parts/connectio
import * as sqlops from 'sqlops'; import * as sqlops from 'sqlops';
import * as assert from 'assert'; import * as assert from 'assert';
import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes'; import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes';
import { CapabilitiesTestService } from 'sqltest/stubs/capabilitiesTestService';
suite('SQL ConnectionProfileInfo tests', () => { suite('SQL ConnectionProfileInfo tests', () => {
let msSQLCapabilities: sqlops.DataProtocolServerCapabilities; let msSQLCapabilities: sqlops.DataProtocolServerCapabilities;
let capabilitiesService: CapabilitiesTestService;
let connectionProfile: IConnectionProfile = { let connectionProfile: IConnectionProfile = {
serverName: 'new server', serverName: 'new server',
@@ -121,10 +123,12 @@ suite('SQL ConnectionProfileInfo tests', () => {
features: undefined features: undefined
}; };
capabilities.push(msSQLCapabilities); capabilities.push(msSQLCapabilities);
capabilitiesService = new CapabilitiesTestService();
capabilitiesService.capabilities['MSSQL'] = msSQLCapabilities;
}); });
test('set properties should set the values correctly', () => { test('set properties should set the values correctly', () => {
let conn = new ConnectionProfile(msSQLCapabilities, undefined); let conn = new ConnectionProfile(capabilitiesService, undefined);
assert.equal(conn.serverName, undefined); assert.equal(conn.serverName, undefined);
conn.serverName = connectionProfile.serverName; conn.serverName = connectionProfile.serverName;
conn.databaseName = connectionProfile.databaseName; conn.databaseName = connectionProfile.databaseName;
@@ -145,7 +149,7 @@ suite('SQL ConnectionProfileInfo tests', () => {
}); });
test('constructor should initialize the options given a valid model', () => { test('constructor should initialize the options given a valid model', () => {
let conn = new ConnectionProfile(msSQLCapabilities, connectionProfile); let conn = new ConnectionProfile(capabilitiesService, connectionProfile);
assert.equal(conn.serverName, connectionProfile.serverName); assert.equal(conn.serverName, connectionProfile.serverName);
assert.equal(conn.databaseName, connectionProfile.databaseName); assert.equal(conn.databaseName, connectionProfile.databaseName);
@@ -158,7 +162,7 @@ suite('SQL ConnectionProfileInfo tests', () => {
}); });
test('getOptionsKey should create a valid unique id', () => { test('getOptionsKey should create a valid unique id', () => {
let conn = new ConnectionProfile(msSQLCapabilities, connectionProfile); let conn = new ConnectionProfile(capabilitiesService, connectionProfile);
let expectedId = 'providerName:MSSQL|authenticationType:|databaseName:database|serverName:new server|userName:user|databaseDisplayName:database|group:group id'; let expectedId = 'providerName:MSSQL|authenticationType:|databaseName:database|serverName:new server|userName:user|databaseDisplayName:database|group:group id';
let id = conn.getOptionsKey(); let id = conn.getOptionsKey();
assert.equal(id, expectedId); assert.equal(id, expectedId);
@@ -166,7 +170,7 @@ suite('SQL ConnectionProfileInfo tests', () => {
test('createFromStoredProfile should create connection profile from stored profile', () => { test('createFromStoredProfile should create connection profile from stored profile', () => {
let savedProfile = storedProfile; let savedProfile = storedProfile;
let connectionProfile = ConnectionProfile.createFromStoredProfile(savedProfile, msSQLCapabilities); let connectionProfile = ConnectionProfile.createFromStoredProfile(savedProfile, capabilitiesService);
assert.equal(savedProfile.groupId, connectionProfile.groupId); assert.equal(savedProfile.groupId, connectionProfile.groupId);
assert.deepEqual(savedProfile.providerName, connectionProfile.providerName); assert.deepEqual(savedProfile.providerName, connectionProfile.providerName);
assert.deepEqual(savedProfile.savePassword, connectionProfile.savePassword); assert.deepEqual(savedProfile.savePassword, connectionProfile.savePassword);
@@ -175,7 +179,7 @@ suite('SQL ConnectionProfileInfo tests', () => {
test('createFromStoredProfile should set the id to new guid if not set in stored profile', () => { test('createFromStoredProfile should set the id to new guid if not set in stored profile', () => {
let savedProfile = Object.assign({}, storedProfile, { id: undefined }); let savedProfile = Object.assign({}, storedProfile, { id: undefined });
let connectionProfile = ConnectionProfile.createFromStoredProfile(savedProfile, msSQLCapabilities); let connectionProfile = ConnectionProfile.createFromStoredProfile(savedProfile, capabilitiesService);
assert.equal(savedProfile.groupId, connectionProfile.groupId); assert.equal(savedProfile.groupId, connectionProfile.groupId);
assert.deepEqual(savedProfile.providerName, connectionProfile.providerName); assert.deepEqual(savedProfile.providerName, connectionProfile.providerName);
assert.equal(savedProfile.savePassword, connectionProfile.savePassword); assert.equal(savedProfile.savePassword, connectionProfile.savePassword);
@@ -184,20 +188,20 @@ suite('SQL ConnectionProfileInfo tests', () => {
}); });
test('withoutPassword should create a new instance without password', () => { test('withoutPassword should create a new instance without password', () => {
let conn = new ConnectionProfile(msSQLCapabilities, connectionProfile); let conn = new ConnectionProfile(capabilitiesService, connectionProfile);
assert.notEqual(conn.password, ''); assert.notEqual(conn.password, '');
let withoutPassword = conn.withoutPassword(); let withoutPassword = conn.withoutPassword();
assert.equal(withoutPassword.password, ''); assert.equal(withoutPassword.password, '');
}); });
test('unique id should not include password', () => { test('unique id should not include password', () => {
let conn = new ConnectionProfile(msSQLCapabilities, connectionProfile); let conn = new ConnectionProfile(capabilitiesService, connectionProfile);
let withoutPassword = conn.withoutPassword(); let withoutPassword = conn.withoutPassword();
assert.equal(withoutPassword.getOptionsKey(), conn.getOptionsKey()); assert.equal(withoutPassword.getOptionsKey(), conn.getOptionsKey());
}); });
test('cloneWithDatabase should create new profile with new id', () => { test('cloneWithDatabase should create new profile with new id', () => {
let conn = new ConnectionProfile(msSQLCapabilities, connectionProfile); let conn = new ConnectionProfile(capabilitiesService, connectionProfile);
let newProfile = conn.cloneWithDatabase('new db'); let newProfile = conn.cloneWithDatabase('new db');
assert.notEqual(newProfile.id, conn.id); assert.notEqual(newProfile.id, conn.id);
assert.equal(newProfile.databaseName, 'new db'); assert.equal(newProfile.databaseName, 'new db');

View File

@@ -72,8 +72,7 @@ let connection3Id: string;
suite('SQL ConnectionStatusManager tests', () => { suite('SQL ConnectionStatusManager tests', () => {
setup(() => { setup(() => {
capabilitiesService = new CapabilitiesTestService(); capabilitiesService = new CapabilitiesTestService();
connectionProfileObject = new ConnectionProfile(capabilitiesService.getCapabilities().find(x => x.providerName === 'MSSQL') connectionProfileObject = new ConnectionProfile(capabilitiesService, connectionProfile);
, connectionProfile);
connections = new ConnectionStatusManager(capabilitiesService); connections = new ConnectionStatusManager(capabilitiesService);
connection1Id = Utils.generateUri(connectionProfile); connection1Id = Utils.generateUri(connectionProfile);
connection2Id = 'connection2Id'; connection2Id = 'connection2Id';
@@ -94,7 +93,7 @@ suite('SQL ConnectionStatusManager tests', () => {
let id: string = connection1Id; let id: string = connection1Id;
let expected = connectionProfileObject; let expected = connectionProfileObject;
let actual = connections.findConnection(id); let actual = connections.findConnection(id);
assert.deepEqual(actual.connectionProfile, expected); assert.equal(connectionProfileObject.matches(actual.connectionProfile), true);
}); });
test('getConnectionProfile should return undefined given invalid id', () => { test('getConnectionProfile should return undefined given invalid id', () => {
@@ -108,7 +107,7 @@ suite('SQL ConnectionStatusManager tests', () => {
let id: string = connection1Id; let id: string = connection1Id;
let expected = connectionProfileObject; let expected = connectionProfileObject;
let actual = connections.getConnectionProfile(id); let actual = connections.getConnectionProfile(id);
assert.deepEqual(actual, expected); assert.equal(connectionProfileObject.matches(actual), true);
}); });
test('hasConnection should return false given invalid id', () => { test('hasConnection should return false given invalid id', () => {

View File

@@ -20,6 +20,7 @@ import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile
import { Emitter } from 'vs/base/common/event'; import { Emitter } from 'vs/base/common/event';
import { ConnectionProfileGroup, IConnectionProfileGroup } from 'sql/parts/connection/common/connectionProfileGroup'; import { ConnectionProfileGroup, IConnectionProfileGroup } from 'sql/parts/connection/common/connectionProfileGroup';
import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes'; import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes';
import { CapabilitiesTestService } from '../../stubs/capabilitiesTestService';
suite('SQL ConnectionStore tests', () => { suite('SQL ConnectionStore tests', () => {
let defaultNamedProfile: IConnectionProfile; let defaultNamedProfile: IConnectionProfile;
@@ -29,13 +30,11 @@ suite('SQL ConnectionStore tests', () => {
let connectionConfig: TypeMoq.Mock<ConnectionConfig>; let connectionConfig: TypeMoq.Mock<ConnectionConfig>;
let workspaceConfigurationServiceMock: TypeMoq.Mock<WorkspaceConfigurationTestService>; let workspaceConfigurationServiceMock: TypeMoq.Mock<WorkspaceConfigurationTestService>;
let storageServiceMock: TypeMoq.Mock<StorageTestService>; let storageServiceMock: TypeMoq.Mock<StorageTestService>;
let capabilitiesService: TypeMoq.Mock<CapabilitiesService>; let capabilitiesService: CapabilitiesTestService;
let mementoArray: any = []; let mementoArray: any = [];
let maxRecent = 5; let maxRecent = 5;
let msSQLCapabilities: sqlops.DataProtocolServerCapabilities; let msSQLCapabilities: sqlops.DataProtocolServerCapabilities;
let defaultNamedConnectionProfile: ConnectionProfile; let defaultNamedConnectionProfile: ConnectionProfile;
let onProviderRegistered = new Emitter<sqlops.DataProtocolServerCapabilities>();
setup(() => { setup(() => {
defaultNamedProfile = Object.assign({}, { defaultNamedProfile = Object.assign({}, {
@@ -96,8 +95,8 @@ suite('SQL ConnectionStore tests', () => {
} }
}; };
capabilitiesService = TypeMoq.Mock.ofType(CapabilitiesService, TypeMoq.MockBehavior.Loose, extensionManagementServiceMock, {}); capabilitiesService = new CapabilitiesTestService();
let capabilities: sqlops.DataProtocolServerCapabilities[] = []; let capabilities: { [id: string]: sqlops.DataProtocolServerCapabilities } = {};
let connectionProvider: sqlops.ConnectionProviderOptions = { let connectionProvider: sqlops.ConnectionProviderOptions = {
options: [ options: [
{ {
@@ -170,10 +169,8 @@ suite('SQL ConnectionStore tests', () => {
adminServicesProvider: undefined, adminServicesProvider: undefined,
features: undefined features: undefined
}; };
capabilities.push(msSQLCapabilities); capabilities['MSSQL'] = msSQLCapabilities;
capabilitiesService.setup(x => x.getCapabilities()).returns(() => capabilities); capabilitiesService.capabilities['MSSQL'] = msSQLCapabilities;
capabilitiesService.setup(x => x.onProviderRegisteredEvent).returns(() => onProviderRegistered.event);
connectionConfig.setup(x => x.getCapabilities('MSSQL')).returns(() => msSQLCapabilities);
let groups: IConnectionProfileGroup[] = [ let groups: IConnectionProfileGroup[] = [
{ {
id: 'root', id: 'root',
@@ -192,7 +189,7 @@ suite('SQL ConnectionStore tests', () => {
]; ];
connectionConfig.setup(x => x.getAllGroups()).returns(() => groups); connectionConfig.setup(x => x.getAllGroups()).returns(() => groups);
defaultNamedConnectionProfile = new ConnectionProfile(msSQLCapabilities, defaultNamedProfile); defaultNamedConnectionProfile = new ConnectionProfile(capabilitiesService, defaultNamedProfile);
}); });
test('addActiveConnection should limit recent connection saves to the MaxRecentConnections amount', (done) => { test('addActiveConnection should limit recent connection saves to the MaxRecentConnections amount', (done) => {
@@ -206,11 +203,11 @@ suite('SQL ConnectionStore tests', () => {
// When saving 4 connections // When saving 4 connections
// Expect all of them to be saved even if size is limited to 3 // Expect all of them to be saved even if size is limited to 3
let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object,
credentialStore.object, capabilitiesService.object, connectionConfig.object); credentialStore.object, capabilitiesService, connectionConfig.object);
let promise = Promise.resolve(); let promise = Promise.resolve();
for (let i = 0; i < numCreds; i++) { for (let i = 0; i < numCreds; i++) {
let cred = Object.assign({}, defaultNamedProfile, { serverName: defaultNamedProfile.serverName + i }); let cred = Object.assign({}, defaultNamedProfile, { serverName: defaultNamedProfile.serverName + i });
let connectionProfile = new ConnectionProfile(msSQLCapabilities, cred); let connectionProfile = new ConnectionProfile(capabilitiesService, cred);
promise = promise.then(() => { promise = promise.then(() => {
return connectionStore.addActiveConnection(connectionProfile); return connectionStore.addActiveConnection(connectionProfile);
}).then(() => { }).then(() => {
@@ -243,12 +240,12 @@ suite('SQL ConnectionStore tests', () => {
// Given we save the same connection twice // Given we save the same connection twice
// Then expect the only 1 instance of that connection to be listed in the MRU // Then expect the only 1 instance of that connection to be listed in the MRU
let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object,
credentialStore.object, capabilitiesService.object, connectionConfig.object); credentialStore.object, capabilitiesService, connectionConfig.object);
connectionStore.clearActiveConnections(); connectionStore.clearActiveConnections();
connectionStore.clearRecentlyUsed(); connectionStore.clearRecentlyUsed();
let promise = Promise.resolve(); let promise = Promise.resolve();
let cred = Object.assign({}, defaultNamedProfile, { serverName: defaultNamedProfile.serverName + 1 }); let cred = Object.assign({}, defaultNamedProfile, { serverName: defaultNamedProfile.serverName + 1 });
let connectionProfile = new ConnectionProfile(msSQLCapabilities, cred); let connectionProfile = new ConnectionProfile(capabilitiesService, cred);
promise = promise.then(() => { promise = promise.then(() => {
return connectionStore.addActiveConnection(defaultNamedConnectionProfile); return connectionStore.addActiveConnection(defaultNamedConnectionProfile);
}).then(() => { }).then(() => {
@@ -278,7 +275,7 @@ suite('SQL ConnectionStore tests', () => {
// Given we save 1 connection with password and multiple other connections without // Given we save 1 connection with password and multiple other connections without
let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object,
credentialStore.object, capabilitiesService.object, connectionConfig.object); credentialStore.object, capabilitiesService, connectionConfig.object);
connectionStore.clearActiveConnections(); connectionStore.clearActiveConnections();
connectionStore.clearRecentlyUsed(); connectionStore.clearRecentlyUsed();
let integratedCred = Object.assign({}, defaultNamedProfile, { let integratedCred = Object.assign({}, defaultNamedProfile, {
@@ -291,7 +288,7 @@ suite('SQL ConnectionStore tests', () => {
serverName: defaultNamedProfile.serverName + 'NoPwd', serverName: defaultNamedProfile.serverName + 'NoPwd',
password: '' password: ''
}); });
let connectionProfile = new ConnectionProfile(msSQLCapabilities, defaultNamedProfile); let connectionProfile = new ConnectionProfile(capabilitiesService, defaultNamedProfile);
let expectedCredCount = 0; let expectedCredCount = 0;
let promise = Promise.resolve(); let promise = Promise.resolve();
@@ -309,7 +306,7 @@ suite('SQL ConnectionStore tests', () => {
}).then(() => { }).then(() => {
// When add integrated auth connection // When add integrated auth connection
expectedCredCount++; expectedCredCount++;
let integratedCredConnectionProfile = new ConnectionProfile(msSQLCapabilities, integratedCred); let integratedCredConnectionProfile = new ConnectionProfile(capabilitiesService, integratedCred);
return connectionStore.addActiveConnection(integratedCredConnectionProfile); return connectionStore.addActiveConnection(integratedCredConnectionProfile);
}).then(() => { }).then(() => {
let current = connectionStore.getRecentlyUsedConnections(); let current = connectionStore.getRecentlyUsedConnections();
@@ -319,7 +316,7 @@ suite('SQL ConnectionStore tests', () => {
}).then(() => { }).then(() => {
// When add connection without password // When add connection without password
expectedCredCount++; expectedCredCount++;
let noPwdCredConnectionProfile = new ConnectionProfile(msSQLCapabilities, noPwdCred); let noPwdCredConnectionProfile = new ConnectionProfile(capabilitiesService, noPwdCred);
return connectionStore.addActiveConnection(noPwdCredConnectionProfile); return connectionStore.addActiveConnection(noPwdCredConnectionProfile);
}).then(() => { }).then(() => {
let current = connectionStore.getRecentlyUsedConnections(); let current = connectionStore.getRecentlyUsedConnections();
@@ -333,7 +330,7 @@ suite('SQL ConnectionStore tests', () => {
connectionConfig.setup(x => x.getConnections(TypeMoq.It.isAny())).returns(() => []); connectionConfig.setup(x => x.getConnections(TypeMoq.It.isAny())).returns(() => []);
let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object,
credentialStore.object, capabilitiesService.object, connectionConfig.object); credentialStore.object, capabilitiesService, connectionConfig.object);
// When we clear the connections list and get the list of available connection items // When we clear the connections list and get the list of available connection items
connectionStore.clearActiveConnections(); connectionStore.clearActiveConnections();
@@ -351,7 +348,7 @@ suite('SQL ConnectionStore tests', () => {
test('isPasswordRequired should return true for MSSQL SqlLogin', () => { test('isPasswordRequired should return true for MSSQL SqlLogin', () => {
let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object,
credentialStore.object, capabilitiesService.object, connectionConfig.object); credentialStore.object, capabilitiesService, connectionConfig.object);
let expected: boolean = true; let expected: boolean = true;
let actual = connectionStore.isPasswordRequired(defaultNamedProfile); let actual = connectionStore.isPasswordRequired(defaultNamedProfile);
@@ -361,8 +358,8 @@ suite('SQL ConnectionStore tests', () => {
test('isPasswordRequired should return true for MSSQL SqlLogin for connection profile object', () => { test('isPasswordRequired should return true for MSSQL SqlLogin for connection profile object', () => {
let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object,
credentialStore.object, capabilitiesService.object, connectionConfig.object); credentialStore.object, capabilitiesService, connectionConfig.object);
let connectionProfile = new ConnectionProfile(msSQLCapabilities, defaultNamedProfile); let connectionProfile = new ConnectionProfile(capabilitiesService, defaultNamedProfile);
let expected: boolean = true; let expected: boolean = true;
let actual = connectionStore.isPasswordRequired(connectionProfile); let actual = connectionStore.isPasswordRequired(connectionProfile);
@@ -387,10 +384,11 @@ suite('SQL ConnectionStore tests', () => {
adminServicesProvider: undefined, adminServicesProvider: undefined,
features: undefined features: undefined
}; };
connectionConfig.setup(x => x.getCapabilities(providerName)).returns(() => providerCapabilities);
capabilitiesService.capabilities[providerName] = providerCapabilities;
let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object,
credentialStore.object, capabilitiesService.object, connectionConfig.object); credentialStore.object, capabilitiesService, connectionConfig.object);
let connectionProfile: IConnectionProfile = Object.assign({}, defaultNamedProfile, { providerName: providerName }); let connectionProfile: IConnectionProfile = Object.assign({}, defaultNamedProfile, { providerName: providerName });
let expected: boolean = false; let expected: boolean = false;
let actual = connectionStore.isPasswordRequired(connectionProfile); let actual = connectionStore.isPasswordRequired(connectionProfile);
@@ -407,7 +405,7 @@ suite('SQL ConnectionStore tests', () => {
credentialStore.setup(x => x.saveCredential(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(true)); credentialStore.setup(x => x.saveCredential(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(true));
let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object,
credentialStore.object, capabilitiesService.object, connectionConfig.object); credentialStore.object, capabilitiesService, connectionConfig.object);
connectionStore.saveProfile(connectionProfile).then(profile => { connectionStore.saveProfile(connectionProfile).then(profile => {
// add connection should be called with a profile without password // add connection should be called with a profile without password
@@ -424,7 +422,7 @@ suite('SQL ConnectionStore tests', () => {
test('addConnectionToMemento should not add duplicate items', () => { test('addConnectionToMemento should not add duplicate items', () => {
let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object,
credentialStore.object, capabilitiesService.object, connectionConfig.object); credentialStore.object, capabilitiesService, connectionConfig.object);
let mementoKey = 'RECENT_CONNECTIONS2'; let mementoKey = 'RECENT_CONNECTIONS2';
connectionStore.clearFromMemento(mementoKey); connectionStore.clearFromMemento(mementoKey);
let connectionProfile: IConnectionProfile = Object.assign({}, defaultNamedProfile); let connectionProfile: IConnectionProfile = Object.assign({}, defaultNamedProfile);
@@ -466,7 +464,7 @@ suite('SQL ConnectionStore tests', () => {
test('getGroupFromId returns undefined when there is no group with the given ID', () => { test('getGroupFromId returns undefined when there is no group with the given ID', () => {
let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object,
credentialStore.object, capabilitiesService.object, connectionConfig.object); credentialStore.object, capabilitiesService, connectionConfig.object);
let group = connectionStore.getGroupFromId('invalidId'); let group = connectionStore.getGroupFromId('invalidId');
assert.equal(group, undefined, 'Returned group was not undefined when there was no group with the given ID'); assert.equal(group, undefined, 'Returned group was not undefined when there was no group with the given ID');
}); });
@@ -482,7 +480,7 @@ suite('SQL ConnectionStore tests', () => {
let newConnectionConfig = TypeMoq.Mock.ofType(ConnectionConfig); let newConnectionConfig = TypeMoq.Mock.ofType(ConnectionConfig);
newConnectionConfig.setup(x => x.getAllGroups()).returns(() => groups); newConnectionConfig.setup(x => x.getAllGroups()).returns(() => groups);
let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object,
credentialStore.object, capabilitiesService.object, newConnectionConfig.object); credentialStore.object, capabilitiesService, newConnectionConfig.object);
// If I look up the parent group using its ID, then I get back the correct group // If I look up the parent group using its ID, then I get back the correct group
let actualGroup = connectionStore.getGroupFromId(parentGroupId); let actualGroup = connectionStore.getGroupFromId(parentGroupId);
@@ -495,14 +493,14 @@ suite('SQL ConnectionStore tests', () => {
test('getProfileWithoutPassword can return the profile without credentials in the password property or options dictionary', () => { test('getProfileWithoutPassword can return the profile without credentials in the password property or options dictionary', () => {
let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object,
credentialStore.object, capabilitiesService.object, connectionConfig.object); credentialStore.object, capabilitiesService, connectionConfig.object);
let profile = Object.assign({}, defaultNamedProfile); let profile = Object.assign({}, defaultNamedProfile);
profile.options['password'] = profile.password; profile.options['password'] = profile.password;
profile.id = 'testId'; profile.id = 'testId';
let expectedProfile = Object.assign({}, profile); let expectedProfile = Object.assign({}, profile);
expectedProfile.password = ''; expectedProfile.password = '';
expectedProfile.options['password'] = ''; expectedProfile.options['password'] = '';
expectedProfile = ConnectionProfile.convertToConnectionProfile(msSQLCapabilities, expectedProfile).toIConnectionProfile(); expectedProfile = ConnectionProfile.fromIConnectionProfile(capabilitiesService, expectedProfile).toIConnectionProfile();
let profileWithoutCredentials = connectionStore.getProfileWithoutPassword(profile); let profileWithoutCredentials = connectionStore.getProfileWithoutPassword(profile);
assert.deepEqual(profileWithoutCredentials.toIConnectionProfile(), expectedProfile); assert.deepEqual(profileWithoutCredentials.toIConnectionProfile(), expectedProfile);
}); });

View File

@@ -33,6 +33,7 @@ import Severity from 'vs/base/common/severity';
import { ObjectExplorerActionsContext, ManageConnectionAction } from 'sql/parts/registeredServer/viewlet/objectExplorerActions'; import { ObjectExplorerActionsContext, ManageConnectionAction } from 'sql/parts/registeredServer/viewlet/objectExplorerActions';
import { IConnectionResult, IConnectionParams } from 'sql/parts/connection/common/connectionManagement'; import { IConnectionResult, IConnectionParams } from 'sql/parts/connection/common/connectionManagement';
import { TreeSelectionHandler } from 'sql/parts/registeredServer/viewlet/treeSelectionHandler'; import { TreeSelectionHandler } from 'sql/parts/registeredServer/viewlet/treeSelectionHandler';
import { CapabilitiesTestService } from 'sqltest/stubs/capabilitiesTestService';
suite('SQL Connection Tree Action tests', () => { suite('SQL Connection Tree Action tests', () => {
let errorMessageService: TypeMoq.Mock<ErrorMessageServiceStub>; let errorMessageService: TypeMoq.Mock<ErrorMessageServiceStub>;
@@ -42,6 +43,7 @@ suite('SQL Connection Tree Action tests', () => {
errorCode: undefined, errorCode: undefined,
callStack: undefined callStack: undefined
}; };
let capabilitiesService = new CapabilitiesTestService();
setup(() => { setup(() => {
errorMessageService = TypeMoq.Mock.ofType(ErrorMessageServiceStub, TypeMoq.MockBehavior.Loose); errorMessageService = TypeMoq.Mock.ofType(ErrorMessageServiceStub, TypeMoq.MockBehavior.Loose);
let nothing: void; let nothing: void;
@@ -91,7 +93,7 @@ suite('SQL Connection Tree Action tests', () => {
let manageConnectionAction: ManageConnectionAction = new ManageConnectionAction(ManageConnectionAction.ID, let manageConnectionAction: ManageConnectionAction = new ManageConnectionAction(ManageConnectionAction.ID,
ManageConnectionAction.LABEL, connectionManagementService.object, instantiationService.object, objectExplorerService.object); ManageConnectionAction.LABEL, connectionManagementService.object, instantiationService.object, objectExplorerService.object);
let connection: ConnectionProfile = new ConnectionProfile(undefined, { let connection: ConnectionProfile = new ConnectionProfile(capabilitiesService, {
savePassword: false, savePassword: false,
groupFullName: 'testGroup', groupFullName: 'testGroup',
serverName: 'testServerName', serverName: 'testServerName',
@@ -126,7 +128,7 @@ suite('SQL Connection Tree Action tests', () => {
let manageConnectionAction: ManageConnectionAction = new ManageConnectionAction(ManageConnectionAction.ID, let manageConnectionAction: ManageConnectionAction = new ManageConnectionAction(ManageConnectionAction.ID,
ManageConnectionAction.LABEL, connectionManagementService.object, instantiationService.object, objectExplorerService.object); ManageConnectionAction.LABEL, connectionManagementService.object, instantiationService.object, objectExplorerService.object);
let connection: ConnectionProfile = new ConnectionProfile(undefined, { let connection: ConnectionProfile = new ConnectionProfile(capabilitiesService, {
savePassword: false, savePassword: false,
groupFullName: 'testGroup', groupFullName: 'testGroup',
serverName: 'testServerName', serverName: 'testServerName',
@@ -158,7 +160,7 @@ suite('SQL Connection Tree Action tests', () => {
let objectExplorerService = createObjectExplorerService(connectionManagementService.object); let objectExplorerService = createObjectExplorerService(connectionManagementService.object);
let changeConnectionAction: DisconnectConnectionAction = new DisconnectConnectionAction(DisconnectConnectionAction.ID, DisconnectConnectionAction.LABEL, connectionManagementService.object, objectExplorerService.object, errorMessageService.object); let changeConnectionAction: DisconnectConnectionAction = new DisconnectConnectionAction(DisconnectConnectionAction.ID, DisconnectConnectionAction.LABEL, connectionManagementService.object, objectExplorerService.object, errorMessageService.object);
let connection: ConnectionProfile = new ConnectionProfile(undefined, { let connection: ConnectionProfile = new ConnectionProfile(capabilitiesService, {
savePassword: false, savePassword: false,
groupFullName: 'testGroup', groupFullName: 'testGroup',
serverName: 'testServerName', serverName: 'testServerName',
@@ -265,7 +267,7 @@ suite('SQL Connection Tree Action tests', () => {
test('DeleteConnectionAction - test delete connection', (done) => { test('DeleteConnectionAction - test delete connection', (done) => {
let connectionManagementService = createConnectionManagementService(true); let connectionManagementService = createConnectionManagementService(true);
let connection: ConnectionProfile = new ConnectionProfile(undefined, { let connection: ConnectionProfile = new ConnectionProfile(capabilitiesService, {
savePassword: false, savePassword: false,
groupFullName: 'testGroup', groupFullName: 'testGroup',
serverName: 'testServerName', serverName: 'testServerName',
@@ -311,7 +313,7 @@ suite('SQL Connection Tree Action tests', () => {
let isConnectedReturnValue: boolean = false; let isConnectedReturnValue: boolean = false;
let connectionManagementService = createConnectionManagementService(isConnectedReturnValue); let connectionManagementService = createConnectionManagementService(isConnectedReturnValue);
let connection: ConnectionProfile = new ConnectionProfile(undefined, { let connection: ConnectionProfile = new ConnectionProfile(capabilitiesService, {
savePassword: false, savePassword: false,
groupFullName: 'testGroup', groupFullName: 'testGroup',
serverName: 'testServerName', serverName: 'testServerName',
@@ -348,7 +350,9 @@ suite('SQL Connection Tree Action tests', () => {
features: undefined features: undefined
}; };
var connection = new ConnectionProfile(sqlProvider, { capabilitiesService.capabilities['MSSQL'] = sqlProvider;
var connection = new ConnectionProfile(capabilitiesService, {
savePassword: false, savePassword: false,
groupFullName: 'testGroup', groupFullName: 'testGroup',
serverName: 'testServerName', serverName: 'testServerName',
@@ -437,7 +441,9 @@ suite('SQL Connection Tree Action tests', () => {
features: undefined features: undefined
}; };
var connection = new ConnectionProfile(sqlProvider, { capabilitiesService.capabilities['MSSQL'] = sqlProvider;
var connection = new ConnectionProfile(capabilitiesService, {
savePassword: false, savePassword: false,
groupFullName: 'testGroup', groupFullName: 'testGroup',
serverName: 'testServerName', serverName: 'testServerName',

View File

@@ -18,7 +18,9 @@ import * as TypeMoq from 'typemoq';
import * as assert from 'assert'; import * as assert from 'assert';
import { ServerTreeView } from 'sql/parts/registeredServer/viewlet/serverTreeView'; import { ServerTreeView } from 'sql/parts/registeredServer/viewlet/serverTreeView';
import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes'; import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes';
import Event from 'vs/base/common/event'; import Event, { Emitter } from 'vs/base/common/event';
import { CapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
import { CapabilitiesTestService } from 'sqltest/stubs/capabilitiesTestService';
suite('SQL Object Explorer Service tests', () => { suite('SQL Object Explorer Service tests', () => {
var sqlOEProvider: TypeMoq.Mock<ObjectExplorerProviderTestService>; var sqlOEProvider: TypeMoq.Mock<ObjectExplorerProviderTestService>;
@@ -122,6 +124,7 @@ suite('SQL Object Explorer Service tests', () => {
sqlOEProvider = TypeMoq.Mock.ofType(ObjectExplorerProviderTestService, TypeMoq.MockBehavior.Loose); sqlOEProvider = TypeMoq.Mock.ofType(ObjectExplorerProviderTestService, TypeMoq.MockBehavior.Loose);
sqlOEProvider.callBase = true; sqlOEProvider.callBase = true;
let onCapabilitiesRegistered = new Emitter<string>();
let sqlProvider = { let sqlProvider = {
protocolVersion: '1', protocolVersion: '1',
@@ -206,7 +209,10 @@ suite('SQL Object Explorer Service tests', () => {
features: undefined features: undefined
}; };
connection = new ConnectionProfile(sqlProvider, { let capabilitiesService = new CapabilitiesTestService();
capabilitiesService.capabilities['MSSQL'] = sqlProvider;
connection = new ConnectionProfile(capabilitiesService, {
savePassword: false, savePassword: false,
groupFullName: 'testGroup', groupFullName: 'testGroup',
serverName: 'testServerName', serverName: 'testServerName',
@@ -224,7 +230,7 @@ suite('SQL Object Explorer Service tests', () => {
}); });
conProfGroup = new ConnectionProfileGroup('testGroup', undefined, 'testGroup', undefined, undefined); conProfGroup = new ConnectionProfileGroup('testGroup', undefined, 'testGroup', undefined, undefined);
connectionToFail = new ConnectionProfile(sqlProvider, { connectionToFail = new ConnectionProfile(capabilitiesService, {
savePassword: false, savePassword: false,
groupFullName: 'testGroup', groupFullName: 'testGroup',
serverName: 'testServerName2', serverName: 'testServerName2',
@@ -251,7 +257,13 @@ suite('SQL Object Explorer Service tests', () => {
connectionManagementService.setup(x => x.getCapabilities('MSSQL')).returns(() => undefined); connectionManagementService.setup(x => x.getCapabilities('MSSQL')).returns(() => undefined);
objectExplorerService = new ObjectExplorerService(connectionManagementService.object, undefined); let extensionManagementServiceMock = {
getInstalled: () => {
return Promise.resolve([]);
}
};
objectExplorerService = new ObjectExplorerService(connectionManagementService.object, undefined, capabilitiesService);
objectExplorerService.registerProvider('MSSQL', sqlOEProvider.object); objectExplorerService.registerProvider('MSSQL', sqlOEProvider.object);
sqlOEProvider.setup(x => x.createNewSession(TypeMoq.It.is<sqlops.ConnectionInfo>(x => x.options['serverName'] === connection.serverName))).returns(() => new Promise<any>((resolve) => { sqlOEProvider.setup(x => x.createNewSession(TypeMoq.It.is<sqlops.ConnectionInfo>(x => x.options['serverName'] === connection.serverName))).returns(() => new Promise<any>((resolve) => {
resolve(response); resolve(response);

View File

@@ -11,9 +11,12 @@ import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import * as sqlops from 'sqlops'; import * as sqlops from 'sqlops';
import * as assert from 'assert'; import * as assert from 'assert';
import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes'; import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes';
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
import { CapabilitiesTestService } from 'sqltest/stubs/capabilitiesTestService';
suite('SQL ProviderConnectionInfo tests', () => { suite('SQL ProviderConnectionInfo tests', () => {
let msSQLCapabilities: sqlops.DataProtocolServerCapabilities; let msSQLCapabilities: sqlops.DataProtocolServerCapabilities;
let capabilitiesService: CapabilitiesTestService;
let connectionProfile: IConnectionProfile = { let connectionProfile: IConnectionProfile = {
serverName: 'new server', serverName: 'new server',
@@ -119,6 +122,8 @@ suite('SQL ProviderConnectionInfo tests', () => {
features: undefined features: undefined
}; };
capabilities.push(msSQLCapabilities); capabilities.push(msSQLCapabilities);
capabilitiesService = new CapabilitiesTestService();
capabilitiesService.capabilities['MSSQL'] = msSQLCapabilities;
}); });
test('constructor should accept undefined parameters', () => { test('constructor should accept undefined parameters', () => {
@@ -127,7 +132,7 @@ suite('SQL ProviderConnectionInfo tests', () => {
}); });
test('set properties should set the values correctly', () => { test('set properties should set the values correctly', () => {
let conn = new ProviderConnectionInfo(msSQLCapabilities, undefined); let conn = new ProviderConnectionInfo(capabilitiesService, 'MSSQL');
assert.equal(conn.serverName, undefined); assert.equal(conn.serverName, undefined);
conn.serverName = connectionProfile.serverName; conn.serverName = connectionProfile.serverName;
conn.databaseName = connectionProfile.databaseName; conn.databaseName = connectionProfile.databaseName;
@@ -142,7 +147,7 @@ suite('SQL ProviderConnectionInfo tests', () => {
}); });
test('set properties should store the values in the options', () => { test('set properties should store the values in the options', () => {
let conn = new ProviderConnectionInfo(msSQLCapabilities, undefined); let conn = new ProviderConnectionInfo(capabilitiesService, 'MSSQL');
assert.equal(conn.serverName, undefined); assert.equal(conn.serverName, undefined);
conn.serverName = connectionProfile.serverName; conn.serverName = connectionProfile.serverName;
conn.databaseName = connectionProfile.databaseName; conn.databaseName = connectionProfile.databaseName;
@@ -157,7 +162,7 @@ suite('SQL ProviderConnectionInfo tests', () => {
}); });
test('constructor should initialize the options given a valid model', () => { test('constructor should initialize the options given a valid model', () => {
let conn = new ProviderConnectionInfo(msSQLCapabilities, connectionProfile); let conn = new ProviderConnectionInfo(capabilitiesService, connectionProfile);
assert.equal(conn.serverName, connectionProfile.serverName); assert.equal(conn.serverName, connectionProfile.serverName);
assert.equal(conn.databaseName, connectionProfile.databaseName); assert.equal(conn.databaseName, connectionProfile.databaseName);
@@ -167,7 +172,7 @@ suite('SQL ProviderConnectionInfo tests', () => {
}); });
test('clone should create a new instance that equals the old one', () => { test('clone should create a new instance that equals the old one', () => {
let conn = new ProviderConnectionInfo(msSQLCapabilities, connectionProfile); let conn = new ProviderConnectionInfo(capabilitiesService, connectionProfile);
let conn2 = conn.clone(); let conn2 = conn.clone();
assert.equal(conn.serverName, conn2.serverName); assert.equal(conn.serverName, conn2.serverName);
@@ -178,7 +183,7 @@ suite('SQL ProviderConnectionInfo tests', () => {
}); });
test('Changing the cloned object should not change the original one', () => { test('Changing the cloned object should not change the original one', () => {
let conn = new ProviderConnectionInfo(msSQLCapabilities, connectionProfile); let conn = new ProviderConnectionInfo(capabilitiesService, connectionProfile);
let conn2 = conn.clone(); let conn2 = conn.clone();
conn2.serverName = conn.serverName + '1'; conn2.serverName = conn.serverName + '1';
@@ -189,7 +194,7 @@ suite('SQL ProviderConnectionInfo tests', () => {
let options = {}; let options = {};
options['encrypt'] = 'test value'; options['encrypt'] = 'test value';
let conn2 = Object.assign({}, connectionProfile, { options: options }); let conn2 = Object.assign({}, connectionProfile, { options: options });
let conn = new ProviderConnectionInfo(msSQLCapabilities, conn2); let conn = new ProviderConnectionInfo(capabilitiesService, conn2);
assert.equal(conn.serverName, conn2.serverName); assert.equal(conn.serverName, conn2.serverName);
assert.equal(conn.databaseName, conn2.databaseName); assert.equal(conn.databaseName, conn2.databaseName);
@@ -200,21 +205,21 @@ suite('SQL ProviderConnectionInfo tests', () => {
}); });
test('getOptionsKey should create a valid unique id', () => { test('getOptionsKey should create a valid unique id', () => {
let conn = new ProviderConnectionInfo(msSQLCapabilities, connectionProfile); let conn = new ProviderConnectionInfo(capabilitiesService, connectionProfile);
let expectedId = 'providerName:MSSQL|authenticationType:|databaseName:database|serverName:new server|userName:user'; let expectedId = 'providerName:MSSQL|authenticationType:|databaseName:database|serverName:new server|userName:user';
let id = conn.getOptionsKey(); let id = conn.getOptionsKey();
assert.equal(id, expectedId); assert.equal(id, expectedId);
}); });
test('getOptionsKey should create different id for different server names', () => { test('getOptionsKey should create different id for different server names', () => {
let conn = new ProviderConnectionInfo(msSQLCapabilities, connectionProfile); let conn = new ProviderConnectionInfo(capabilitiesService, connectionProfile);
let conn2 = new ProviderConnectionInfo(msSQLCapabilities, Object.assign({}, connectionProfile, { serverName: connectionProfile.serverName + '1' })); let conn2 = new ProviderConnectionInfo(capabilitiesService, Object.assign({}, connectionProfile, { serverName: connectionProfile.serverName + '1' }));
assert.notEqual(conn.getOptionsKey(), conn2.getOptionsKey()); assert.notEqual(conn.getOptionsKey(), conn2.getOptionsKey());
}); });
test('titleParts should return server, database and auth type as first items', () => { test('titleParts should return server, database and auth type as first items', () => {
let conn = new ProviderConnectionInfo(msSQLCapabilities, connectionProfile); let conn = new ProviderConnectionInfo(capabilitiesService, connectionProfile);
let titleParts = conn.titleParts; let titleParts = conn.titleParts;
assert.equal(titleParts.length, 4); assert.equal(titleParts.length, 4);
assert.equal(titleParts[0], connectionProfile.serverName); assert.equal(titleParts[0], connectionProfile.serverName);

View File

@@ -6,11 +6,11 @@
'use strict'; 'use strict';
import * as sqlops from 'sqlops'; import * as sqlops from 'sqlops';
import { ConnectionManagementInfo } from 'sql/parts/connection/common/connectionManagementInfo'; import { ConnectionManagementInfo } from 'sql/parts/connection/common/connectionManagementInfo';
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService'; import { ICapabilitiesService, clientCapabilities } from 'sql/services/capabilities/capabilitiesService';
import Event from 'vs/base/common/event';
import { Action } from 'vs/base/common/actions';
import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes'; import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes';
import Event, { Emitter } from 'vs/base/common/event';
import { Action } from 'vs/base/common/actions';
export class CapabilitiesTestService implements ICapabilitiesService { export class CapabilitiesTestService implements ICapabilitiesService {
@@ -18,8 +18,7 @@ export class CapabilitiesTestService implements ICapabilitiesService {
private _providers: sqlops.CapabilitiesProvider[] = []; private _providers: sqlops.CapabilitiesProvider[] = [];
private _capabilities: sqlops.DataProtocolServerCapabilities[] = []; public capabilities: { [id: string]: sqlops.DataProtocolServerCapabilities } = {};
constructor() { constructor() {
@@ -95,15 +94,19 @@ export class CapabilitiesTestService implements ICapabilitiesService {
adminServicesProvider: undefined, adminServicesProvider: undefined,
features: undefined features: undefined
}; };
this._capabilities.push(msSQLCapabilities); this.capabilities['MSSQL'] = msSQLCapabilities;
} }
/** /**
* Retrieve a list of registered server capabilities * Retrieve a list of registered server capabilities
*/ */
public getCapabilities(): sqlops.DataProtocolServerCapabilities[] { public getCapabilities(provider: string): sqlops.DataProtocolServerCapabilities {
return this._capabilities; return this.capabilities[provider];
}
public get providers(): string[] {
return Object.keys(this.capabilities);
} }
/** /**
@@ -125,5 +128,8 @@ export class CapabilitiesTestService implements ICapabilitiesService {
public onCapabilitiesReady(): Promise<void> { public onCapabilitiesReady(): Promise<void> {
return Promise.resolve(null); return Promise.resolve(null);
} }
private _onCapabilitiesRegistered = new Emitter<string>();
public readonly onCapabilitiesRegistered = this._onCapabilitiesRegistered.event;
} }