mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-13 11:38:36 -05:00
getConnections API (#5651)
* getConnections * update * fix the condition check * pr feedback * fix test cases * add test for the new method * address comments
This commit is contained in:
10
src/sql/azdata.d.ts
vendored
10
src/sql/azdata.d.ts
vendored
@@ -26,13 +26,21 @@ declare module 'azdata' {
|
||||
groupId: string;
|
||||
saveProfile: boolean;
|
||||
azureTenantId?: string;
|
||||
options: { [name: string]: any };
|
||||
|
||||
static createFrom(options: any[]): ConnectionProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current connection based on the active editor or Object Explorer selection
|
||||
*/
|
||||
*/
|
||||
export function getCurrentConnection(): Thenable<ConnectionProfile>;
|
||||
|
||||
/**
|
||||
* Get known connection profiles including active connections, recent connections and saved connections.
|
||||
* @param activeConnectionsOnly Indicates whether only get the active connections, default value is false.
|
||||
* @returns array of connections
|
||||
*/
|
||||
export function getConnections(activeConnectionsOnly?: boolean): Thenable<ConnectionProfile[]>;
|
||||
}
|
||||
}
|
||||
@@ -282,6 +282,13 @@ export interface IConnectionManagementService {
|
||||
getProviderProperties(providerName: string): ConnectionProviderProperties;
|
||||
|
||||
getConnectionIconId(connectionId: string): string;
|
||||
|
||||
/**
|
||||
* Get known connection profiles including active connections, recent connections and saved connections.
|
||||
* @param activeConnectionsOnly Indicates whether only get the active connections, default value is false.
|
||||
* @returns array of connections
|
||||
*/
|
||||
getConnections(activeConnectionsOnly?: boolean): ConnectionProfile[];
|
||||
}
|
||||
|
||||
export enum RunQueryOnConnectionMode {
|
||||
|
||||
@@ -60,11 +60,7 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
|
||||
private _providers = new Map<string, { onReady: Thenable<azdata.ConnectionProvider>, properties: ConnectionProviderProperties }>();
|
||||
private _iconProviders = new Map<string, azdata.IconProvider>();
|
||||
|
||||
private _uriToProvider: { [uri: string]: string; } = Object.create(null);
|
||||
|
||||
private _connectionStatusManager = new ConnectionStatusManager(this._capabilitiesService, this._logService, this._environmentService, this._notificationService);
|
||||
|
||||
private _onAddConnectionProfile = new Emitter<IConnectionProfile>();
|
||||
private _onDeleteConnectionProfile = new Emitter<void>();
|
||||
private _onConnect = new Emitter<IConnectionParams>();
|
||||
@@ -80,6 +76,7 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
|
||||
constructor(
|
||||
private _connectionStore: ConnectionStore,
|
||||
private _connectionStatusManager: ConnectionStatusManager,
|
||||
@IConnectionDialogService private _connectionDialogService: IConnectionDialogService,
|
||||
@IServerGroupController private _serverGroupController: IServerGroupController,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@@ -102,6 +99,9 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
if (!this._connectionStore) {
|
||||
this._connectionStore = _instantiationService.createInstance(ConnectionStore);
|
||||
}
|
||||
if (!this._connectionStatusManager) {
|
||||
this._connectionStatusManager = new ConnectionStatusManager(this._capabilitiesService, this._logService, this._environmentService, this._notificationService);
|
||||
}
|
||||
|
||||
if (this._storageService) {
|
||||
this._mementoContext = new Memento(ConnectionManagementService.CONNECTION_MEMENTO, this._storageService);
|
||||
@@ -1432,4 +1432,54 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
let connectionProvider = this._providers.get(providerName);
|
||||
return connectionProvider && connectionProvider.properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get known connection profiles including active connections, recent connections and saved connections.
|
||||
* @param activeConnectionsOnly Indicates whether only get the active connections, default value is false.
|
||||
* @returns array of connections
|
||||
**/
|
||||
public getConnections(activeConnectionsOnly?: boolean): ConnectionProfile[] {
|
||||
|
||||
// 1. Active Connections
|
||||
const connections = this.getActiveConnections();
|
||||
|
||||
const connectionExists: (conn: ConnectionProfile) => boolean = (conn) => {
|
||||
return connections.find(existingConnection => existingConnection.id === conn.id) !== undefined;
|
||||
};
|
||||
|
||||
if (!activeConnectionsOnly) {
|
||||
// 2. Recent Connections
|
||||
this.getRecentConnections().forEach(connection => {
|
||||
if (!connectionExists(connection)) {
|
||||
connections.push(connection);
|
||||
}
|
||||
});
|
||||
|
||||
// 3. Saved Connections
|
||||
const groups = this.getConnectionGroups();
|
||||
if (groups && groups.length > 0) {
|
||||
groups.forEach(group => {
|
||||
this.getConnectionsInGroup(group).forEach(savedConnection => {
|
||||
if (!connectionExists(savedConnection)) {
|
||||
connections.push(savedConnection);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
return connections;
|
||||
}
|
||||
|
||||
private getConnectionsInGroup(group: ConnectionProfileGroup): ConnectionProfile[] {
|
||||
const connections = [];
|
||||
if (group) {
|
||||
if (group.connections && group.connections.length > 0) {
|
||||
connections.push(...group.connections);
|
||||
}
|
||||
if (group.children && group.children.length > 0) {
|
||||
group.children.forEach(child => connections.push(...this.getConnectionsInGroup(child)));
|
||||
}
|
||||
}
|
||||
return connections;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,6 +544,7 @@ export class ConnectionProfile {
|
||||
groupId: string;
|
||||
saveProfile: boolean;
|
||||
azureTenantId?: string;
|
||||
options: { [name: string]: any };
|
||||
|
||||
static createFrom(options: any[]): ConnectionProfile {
|
||||
// create from options
|
||||
|
||||
@@ -26,6 +26,10 @@ export class ExtHostConnectionManagement extends ExtHostConnectionManagementShap
|
||||
return connection;
|
||||
}
|
||||
|
||||
public $getConnections(activeConnectionsOnly?: boolean): Thenable<azdata.connection.ConnectionProfile[]> {
|
||||
return this._proxy.$getConnections(activeConnectionsOnly);
|
||||
}
|
||||
|
||||
// "sqlops" back-compat connection APIs
|
||||
public $getActiveConnections(): Thenable<azdata.connection.Connection[]> {
|
||||
return this._proxy.$getActiveConnections();
|
||||
|
||||
@@ -18,6 +18,7 @@ import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||
import { IConnectionDialogService } from 'sql/workbench/services/connection/common/connectionDialogService';
|
||||
import { deepClone } from 'vs/base/common/objects';
|
||||
|
||||
@extHostNamedCustomer(SqlMainContext.MainThreadConnectionManagement)
|
||||
export class MainThreadConnectionManagement implements MainThreadConnectionManagementShape {
|
||||
@@ -43,6 +44,10 @@ export class MainThreadConnectionManagement implements MainThreadConnectionManag
|
||||
this._toDispose = dispose(this._toDispose);
|
||||
}
|
||||
|
||||
public $getConnections(activeConnectionsOnly?: boolean): Thenable<azdata.connection.ConnectionProfile[]> {
|
||||
return Promise.resolve(this._connectionManagementService.getConnections(activeConnectionsOnly).map(profile => this.convertToConnectionProfile(profile)));
|
||||
}
|
||||
|
||||
public $getActiveConnections(): Thenable<azdata.connection.Connection[]> {
|
||||
return Promise.resolve(this._connectionManagementService.getActiveConnections().map(profile => this.convertConnection(profile)));
|
||||
}
|
||||
@@ -117,6 +122,30 @@ export class MainThreadConnectionManagement implements MainThreadConnectionManag
|
||||
return connection;
|
||||
}
|
||||
|
||||
private convertToConnectionProfile(profile: IConnectionProfile): azdata.connection.ConnectionProfile {
|
||||
if (!profile) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
profile = this._connectionManagementService.removeConnectionProfileCredentials(profile);
|
||||
let connection: azdata.connection.ConnectionProfile = {
|
||||
providerId: profile.providerName,
|
||||
connectionId: profile.id,
|
||||
options: deepClone(profile.options),
|
||||
connectionName: profile.connectionName,
|
||||
serverName: profile.serverName,
|
||||
databaseName: profile.databaseName,
|
||||
userName: profile.userName,
|
||||
password: profile.password,
|
||||
authenticationType: profile.authenticationType,
|
||||
savePassword: profile.savePassword,
|
||||
groupFullName: profile.groupFullName,
|
||||
groupId: profile.groupId,
|
||||
saveProfile: profile.saveProfile
|
||||
};
|
||||
return connection;
|
||||
}
|
||||
|
||||
public $connect(connectionProfile: IConnectionProfile, saveConnection: boolean = true, showDashboard: boolean = true): Thenable<azdata.ConnectionResult> {
|
||||
let profile = new ConnectionProfile(this._capabilitiesService, connectionProfile);
|
||||
profile.id = generateUuid();
|
||||
|
||||
@@ -99,9 +99,13 @@ export function createApiFactory(
|
||||
getCurrentConnection(): Thenable<azdata.connection.ConnectionProfile> {
|
||||
return extHostConnectionManagement.$getCurrentConnection();
|
||||
},
|
||||
getConnections(activeConnectionsOnly?: boolean): Thenable<azdata.connection.ConnectionProfile[]> {
|
||||
return extHostConnectionManagement.$getConnections(activeConnectionsOnly);
|
||||
},
|
||||
|
||||
// "sqlops" back-compat APIs
|
||||
getActiveConnections(): Thenable<azdata.connection.Connection[]> {
|
||||
console.warn('the method azdata.connection.getActiveConnections has been deprecated, replace it with azdata.connection.getConnections');
|
||||
return extHostConnectionManagement.$getActiveConnections();
|
||||
},
|
||||
getCredentials(connectionId: string): Thenable<{ [name: string]: string }> {
|
||||
|
||||
@@ -589,6 +589,7 @@ export interface MainThreadDataProtocolShape extends IDisposable {
|
||||
}
|
||||
|
||||
export interface MainThreadConnectionManagementShape extends IDisposable {
|
||||
$getConnections(activeConnectionsOnly?: boolean): Thenable<azdata.connection.ConnectionProfile[]>;
|
||||
$getActiveConnections(): Thenable<azdata.connection.Connection[]>;
|
||||
$getCurrentConnection(): Thenable<azdata.connection.Connection>;
|
||||
$getCredentials(connectionId: string): Thenable<{ [name: string]: string }>;
|
||||
|
||||
@@ -151,6 +151,7 @@ suite('SQL ConnectionManagementService tests', () => {
|
||||
function createConnectionManagementService(): ConnectionManagementService {
|
||||
let connectionManagementService = new ConnectionManagementService(
|
||||
connectionStore.object,
|
||||
undefined,
|
||||
connectionDialogService.object,
|
||||
undefined, // IServerGroupController
|
||||
undefined, // IInstantiationService
|
||||
|
||||
@@ -126,7 +126,7 @@ suite('SQL QueryAction Tests', () => {
|
||||
.returns(() => Promise.resolve(none));
|
||||
|
||||
// ... Mock "isConnected" in ConnectionManagementService
|
||||
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, connectionDialogService.object);
|
||||
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, undefined, connectionDialogService.object);
|
||||
connectionManagementService.callBase = true;
|
||||
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
|
||||
|
||||
@@ -260,7 +260,7 @@ suite('SQL QueryAction Tests', () => {
|
||||
});
|
||||
|
||||
// ... Mock "isConnected" in ConnectionManagementService
|
||||
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, connectionDialogService.object);
|
||||
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, undefined, connectionDialogService.object);
|
||||
connectionManagementService.callBase = true;
|
||||
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
|
||||
|
||||
@@ -396,7 +396,7 @@ suite('SQL QueryAction Tests', () => {
|
||||
.returns(() => Promise.resolve(none));
|
||||
|
||||
// ... Mock "isConnected" in ConnectionManagementService
|
||||
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, connectionDialogService.object);
|
||||
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, undefined, connectionDialogService.object);
|
||||
connectionManagementService.callBase = true;
|
||||
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
|
||||
|
||||
@@ -442,7 +442,7 @@ suite('SQL QueryAction Tests', () => {
|
||||
.returns(() => Promise.resolve(none));
|
||||
|
||||
// ... Mock "isConnected" in ConnectionManagementService
|
||||
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, connectionDialogService.object);
|
||||
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, undefined, connectionDialogService.object);
|
||||
connectionManagementService.callBase = true;
|
||||
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import { ConnectionManagementService } from 'sql/platform/connection/common/connectionManagementService';
|
||||
import { ConnectionStatusManager } from 'sql/platform/connection/common/connectionStatusManager';
|
||||
import { ConnectionStore } from 'sql/platform/connection/common/connectionStore';
|
||||
import { TestStorageService } from 'vs/workbench/test/workbenchTestServices';
|
||||
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||
import { CapabilitiesTestService } from 'sqltest/stubs/capabilitiesTestService';
|
||||
import { ConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup';
|
||||
import { integrated, mssqlProviderName } from 'sql/platform/connection/common/constants';
|
||||
|
||||
const capabilitiesService = new CapabilitiesTestService();
|
||||
|
||||
suite('ConnectionManagementService Tests:', () => {
|
||||
test('getConnections test', () => {
|
||||
const connectionStatusManagerMock = TypeMoq.Mock.ofType(ConnectionStatusManager, TypeMoq.MockBehavior.Loose);
|
||||
const connectionStoreMock = TypeMoq.Mock.ofType(ConnectionStore, TypeMoq.MockBehavior.Loose, new TestStorageService());
|
||||
|
||||
connectionStatusManagerMock.setup(x => x.getActiveConnectionProfiles(undefined)).returns(() => {
|
||||
return [createConnectionProfile('1'), createConnectionProfile('2')];
|
||||
});
|
||||
connectionStoreMock.setup(x => x.getRecentlyUsedConnections(undefined)).returns(() => {
|
||||
return [createConnectionProfile('1'), createConnectionProfile('3')];
|
||||
});
|
||||
|
||||
const group1 = createConnectionGroup('group1');
|
||||
const group2 = createConnectionGroup('group2');
|
||||
group1.connections = [createConnectionProfile('1'), createConnectionProfile('4')];
|
||||
group1.children = [group2];
|
||||
group2.connections = [createConnectionProfile('5'), createConnectionProfile('6')];
|
||||
connectionStoreMock.setup(x => x.getConnectionProfileGroups(TypeMoq.It.isAny(), undefined)).returns(() => {
|
||||
return [group1];
|
||||
});
|
||||
const connectionManagementService = new ConnectionManagementService(connectionStoreMock.object, connectionStatusManagerMock.object, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
||||
|
||||
// dupe connections have been seeded the numbers below already reflected the de-duped results
|
||||
|
||||
const verifyConnections = (actualConnections: ConnectionProfile[], expectedConnectionIds: string[], scenario: string) => {
|
||||
assert.equal(actualConnections.length, expectedConnectionIds.length, 'incorrect number of connections returned, ' + scenario);
|
||||
assert.deepEqual(actualConnections.map(conn => conn.id).sort(), expectedConnectionIds.sort(), 'connections do not match expectation, ' + scenario);
|
||||
};
|
||||
|
||||
// no parameter - default to false
|
||||
let connections = connectionManagementService.getConnections();
|
||||
verifyConnections(connections, ['1', '2', '3', '4', '5', '6'], 'no parameter provided');
|
||||
|
||||
// explicitly set to false
|
||||
connections = connectionManagementService.getConnections(false);
|
||||
verifyConnections(connections, ['1', '2', '3', '4', '5', '6'], 'parameter is false');
|
||||
|
||||
// active connections only
|
||||
connections = connectionManagementService.getConnections(true);
|
||||
verifyConnections(connections, ['1', '2'], 'parameter is true');
|
||||
});
|
||||
});
|
||||
|
||||
function createConnectionProfile(id: string): ConnectionProfile {
|
||||
|
||||
return new ConnectionProfile(capabilitiesService, {
|
||||
connectionName: 'newName',
|
||||
savePassword: false,
|
||||
groupFullName: 'testGroup',
|
||||
serverName: 'testServerName',
|
||||
databaseName: 'testDatabaseName',
|
||||
authenticationType: integrated,
|
||||
password: 'test',
|
||||
userName: 'testUsername',
|
||||
groupId: undefined,
|
||||
providerName: mssqlProviderName,
|
||||
options: {},
|
||||
saveProfile: true,
|
||||
id: id
|
||||
});
|
||||
}
|
||||
|
||||
function createConnectionGroup(id: string): ConnectionProfileGroup {
|
||||
return new ConnectionProfileGroup(id, undefined, id, undefined, undefined);
|
||||
}
|
||||
@@ -291,4 +291,8 @@ export class TestConnectionManagementService implements IConnectionManagementSer
|
||||
getDefaultProviderId(): string {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getConnections(activeConnectionsOnly?: boolean): ConnectionProfile[] {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user