SQL Project: Opening connection viewlet after deploying database (#19544)

This commit is contained in:
Leila Lali
2022-06-03 11:44:58 -07:00
committed by GitHub
parent de9d73c948
commit e8158d4374
5 changed files with 202 additions and 336 deletions

View File

@@ -0,0 +1,185 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as constants from '../../common/constants';
import * as utils from '../../common/utils';
import * as vscode from 'vscode';
import { ConnectionResult } from 'azdata';
import { IFireWallRuleError } from 'vscode-mssql';
export interface ISqlConnectionProperties {
tenantId?: string,
accountId?: string
serverName: string,
userName: string,
password: string,
port: number,
dbName: string,
profileName?: string,
connectionRetryTimeout?: number
}
/**
* Includes methods to open connections and interact with connection views
*/
export class ConnectionService {
constructor(private _outputChannel: vscode.OutputChannel) {
}
private defaultSqlRetryTimeoutInSec: number = 10;
private defaultSqlNumberOfRetries: number = 3;
/**
* Connects to a database
* @param profile connection profile
* @param saveConnectionAndPassword if true, connection will be saved in the connection view
* @param database database name
* @returns
*/
private async connectToDatabase(profile: ISqlConnectionProperties, saveConnectionAndPassword: boolean, database: string): Promise<ConnectionResult | string | undefined> {
const azdataApi = utils.getAzdataApi();
const vscodeMssqlApi = azdataApi ? undefined : await utils.getVscodeMssqlApi();
if (azdataApi) {
const connectionProfile = {
password: profile.password,
serverName: `${profile.serverName},${profile.port}`,
database: database,
savePassword: saveConnectionAndPassword,
userName: profile.userName,
providerName: 'MSSQL',
saveProfile: false,
id: '',
connectionName: profile.profileName,
options: [],
authenticationType: 'SqlLogin'
};
return await azdataApi.connection.connect(connectionProfile, saveConnectionAndPassword, false);
} else if (vscodeMssqlApi) {
const connectionProfile = {
password: profile.password,
server: `${profile.serverName}`,
port: profile.port,
database: database,
savePassword: saveConnectionAndPassword,
user: profile.userName,
authenticationType: 'SqlLogin',
encrypt: false,
connectTimeout: 30,
applicationName: 'SQL Database Project',
accountId: profile.accountId,
azureAccountToken: undefined,
applicationIntent: undefined,
attachDbFilename: undefined,
connectRetryCount: undefined,
connectRetryInterval: undefined,
connectionString: undefined,
currentLanguage: undefined,
email: undefined,
failoverPartner: undefined,
loadBalanceTimeout: undefined,
maxPoolSize: undefined,
minPoolSize: undefined,
multiSubnetFailover: undefined,
multipleActiveResultSets: undefined,
packetSize: undefined,
persistSecurityInfo: undefined,
pooling: undefined,
replication: undefined,
trustServerCertificate: undefined,
typeSystemVersion: undefined,
workstationId: undefined,
profileName: profile.profileName,
expiresOn: undefined,
tenantId: profile.tenantId
};
let connectionUrl = '';
try {
connectionUrl = await vscodeMssqlApi.connect(connectionProfile, saveConnectionAndPassword);
} catch (err) {
const firewallRuleError = <IFireWallRuleError>err;
if (firewallRuleError?.connectionUri) {
await vscodeMssqlApi.promptForFirewallRule(err.connectionUri, connectionProfile);
} else {
throw err;
}
}
// If connected successfully and saved the connection in the view, open the connection view
if (saveConnectionAndPassword && connectionUrl) {
await vscode.commands.executeCommand('objectExplorer.focus');
}
return connectionUrl;
} else {
return undefined;
}
}
/**
* Validates the connection result. If using azdata API, verifies connection was successful and connection id is returns
* If using vscode API, verifies the connection url is returns
* @param connection connection result or connection Id
* @returns validation result
*/
private async validateConnection(connection: ConnectionResult | string | undefined): Promise<utils.ValidationResult> {
const azdataApi = utils.getAzdataApi();
if (!connection) {
return { validated: false, errorMessage: constants.connectionFailedError('No result returned') };
} else if (azdataApi) {
const connectionResult = <ConnectionResult>connection;
if (connectionResult) {
const connected = connectionResult !== undefined && connectionResult.connected && connectionResult.connectionId !== undefined;
return { validated: connected, errorMessage: connected ? '' : constants.connectionFailedError(connectionResult?.errorMessage!) };
} else {
return { validated: false, errorMessage: constants.connectionFailedError('') };
}
} else {
return { validated: connection !== undefined, errorMessage: constants.connectionFailedError('') };
}
}
/**
* Formats connection result to string to be able to add to log
* @param connection connection result or connection Id
* @returns formatted connection result
*/
private async formatConnectionResult(connection: ConnectionResult | string | undefined): Promise<string> {
const azdataApi = utils.getAzdataApi();
const connectionResult = connection !== undefined && azdataApi ? <ConnectionResult>connection : undefined;
return connectionResult?.connected ? connectionResult.connectionId! : <string>connection;
}
/**
* Opens a connections and returns the connection id
* @param profile connection profile
* @param saveConnectionAndPassword is set to true the connection will be saved in the connection view
* @param database database name
* @returns connection id
*/
public async getConnection(profile: ISqlConnectionProperties, saveConnectionAndPassword: boolean, database: string): Promise<string | undefined> {
const azdataApi = utils.getAzdataApi();
let connection = await utils.retry(
constants.connectingToSqlServerMessage,
async () => {
return await this.connectToDatabase(profile, saveConnectionAndPassword, database);
},
this.validateConnection,
this.formatConnectionResult,
this._outputChannel,
this.defaultSqlNumberOfRetries, profile.connectionRetryTimeout || this.defaultSqlRetryTimeoutInSec);
if (connection) {
const connectionResult = <ConnectionResult>connection;
if (azdataApi) {
utils.throwIfNotConnected(connectionResult);
return azdataApi.connection.getUriForConnection(connectionResult.connectionId!);
} else {
return <string>connection;
}
}
return undefined;
}
}