mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Update SQL Bindings API (#18748)
* refactor addSqlBindingQuickpick so they can be called using sql-bindings api
This commit is contained in:
@@ -4,10 +4,12 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as utils from './utils';
|
import * as utils from './utils';
|
||||||
import * as constants from './constants';
|
import * as constants from './constants';
|
||||||
|
import { BindingType } from 'sql-bindings';
|
||||||
|
import * as path from 'path';
|
||||||
|
import { ConnectionDetails, IConnectionInfo } from 'vscode-mssql';
|
||||||
// https://github.com/microsoft/vscode-azurefunctions/blob/main/src/vscode-azurefunctions.api.d.ts
|
// https://github.com/microsoft/vscode-azurefunctions/blob/main/src/vscode-azurefunctions.api.d.ts
|
||||||
import { AzureFunctionsExtensionApi } from '../typings/vscode-azurefunctions.api';
|
import { AzureFunctionsExtensionApi } from '../typings/vscode-azurefunctions.api';
|
||||||
// https://github.com/microsoft/vscode-azuretools/blob/main/ui/api.d.ts
|
// https://github.com/microsoft/vscode-azuretools/blob/main/ui/api.d.ts
|
||||||
@@ -307,3 +309,218 @@ export async function getAFProjectContainingFile(fileUri: vscode.Uri): Promise<v
|
|||||||
export async function isFunctionProject(folderPath: string): Promise<boolean> {
|
export async function isFunctionProject(folderPath: string): Promise<boolean> {
|
||||||
return fs.existsSync(path.join(folderPath, constants.hostFileName));
|
return fs.existsSync(path.join(folderPath, constants.hostFileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompts the user to select type of binding and returns result
|
||||||
|
*/
|
||||||
|
export async function promptForBindingType(): Promise<(vscode.QuickPickItem & { type: BindingType }) | undefined> {
|
||||||
|
const inputOutputItems: (vscode.QuickPickItem & { type: BindingType })[] = [
|
||||||
|
{
|
||||||
|
label: constants.input,
|
||||||
|
type: BindingType.input
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: constants.output,
|
||||||
|
type: BindingType.output
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const selectedBinding = (await vscode.window.showQuickPick(inputOutputItems, {
|
||||||
|
canPickMany: false,
|
||||||
|
title: constants.selectBindingType,
|
||||||
|
ignoreFocusOut: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
return selectedBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompts the user to enter object name for the SQL query
|
||||||
|
* @param bindingType Type of SQL Binding
|
||||||
|
*/
|
||||||
|
export async function promptForObjectName(bindingType: BindingType): Promise<string | undefined> {
|
||||||
|
return vscode.window.showInputBox({
|
||||||
|
prompt: bindingType === BindingType.input ? constants.sqlTableOrViewToQuery : constants.sqlTableToUpsert,
|
||||||
|
placeHolder: constants.placeHolderObject,
|
||||||
|
validateInput: input => input ? undefined : constants.nameMustNotBeEmpty,
|
||||||
|
ignoreFocusOut: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompts the user to enter connection setting and updates it from AF project
|
||||||
|
* @param projectUri Azure Function project uri
|
||||||
|
*/
|
||||||
|
export async function promptAndUpdateConnectionStringSetting(projectUri: vscode.Uri | undefined): Promise<string | undefined> {
|
||||||
|
let connectionStringSettingName: string | undefined;
|
||||||
|
const vscodeMssqlApi = await utils.getVscodeMssqlApi();
|
||||||
|
|
||||||
|
// show the settings from project's local.settings.json if there's an AF functions project
|
||||||
|
if (projectUri) {
|
||||||
|
let settings;
|
||||||
|
try {
|
||||||
|
settings = await getLocalSettingsJson(path.join(path.dirname(projectUri.fsPath!), constants.azureFunctionLocalSettingsFileName));
|
||||||
|
} catch (e) {
|
||||||
|
void vscode.window.showErrorMessage(utils.getErrorMessage(e));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let existingSettings: (vscode.QuickPickItem)[] = [];
|
||||||
|
if (settings?.Values) {
|
||||||
|
existingSettings = Object.keys(settings.Values).map(setting => {
|
||||||
|
return {
|
||||||
|
label: setting
|
||||||
|
} as vscode.QuickPickItem;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
existingSettings.unshift({ label: constants.createNewLocalAppSettingWithIcon });
|
||||||
|
let sqlConnectionStringSettingExists = existingSettings.find(s => s.label === constants.sqlConnectionStringSetting);
|
||||||
|
|
||||||
|
while (!connectionStringSettingName) {
|
||||||
|
const selectedSetting = await vscode.window.showQuickPick(existingSettings, {
|
||||||
|
canPickMany: false,
|
||||||
|
title: constants.selectSetting,
|
||||||
|
ignoreFocusOut: true
|
||||||
|
});
|
||||||
|
if (!selectedSetting) {
|
||||||
|
// User cancelled
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedSetting.label === constants.createNewLocalAppSettingWithIcon) {
|
||||||
|
const newConnectionStringSettingName = await vscode.window.showInputBox(
|
||||||
|
{
|
||||||
|
title: constants.enterConnectionStringSettingName,
|
||||||
|
ignoreFocusOut: true,
|
||||||
|
value: sqlConnectionStringSettingExists ? '' : constants.sqlConnectionStringSetting,
|
||||||
|
validateInput: input => input ? undefined : constants.nameMustNotBeEmpty
|
||||||
|
}
|
||||||
|
) ?? '';
|
||||||
|
|
||||||
|
if (!newConnectionStringSettingName) {
|
||||||
|
// go back to select setting quickpick if user escapes from inputting the setting name in case they changed their mind
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// show the connection string methods (user input and connection profile options)
|
||||||
|
const listOfConnectionStringMethods = [constants.connectionProfile, constants.userConnectionString];
|
||||||
|
while (true) {
|
||||||
|
const selectedConnectionStringMethod = await vscode.window.showQuickPick(listOfConnectionStringMethods, {
|
||||||
|
canPickMany: false,
|
||||||
|
title: constants.selectConnectionString,
|
||||||
|
ignoreFocusOut: true
|
||||||
|
});
|
||||||
|
if (!selectedConnectionStringMethod) {
|
||||||
|
// User cancelled
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let connectionString: string = '';
|
||||||
|
let includePassword: string | undefined;
|
||||||
|
let connectionInfo: IConnectionInfo | undefined;
|
||||||
|
let connectionDetails: ConnectionDetails;
|
||||||
|
if (selectedConnectionStringMethod === constants.userConnectionString) {
|
||||||
|
// User chooses to enter connection string manually
|
||||||
|
connectionString = await vscode.window.showInputBox(
|
||||||
|
{
|
||||||
|
title: constants.enterConnectionString,
|
||||||
|
ignoreFocusOut: true,
|
||||||
|
value: 'Server=localhost;Initial Catalog={db_name};User ID=sa;Password={your_password};Persist Security Info=False',
|
||||||
|
validateInput: input => input ? undefined : constants.valueMustNotBeEmpty
|
||||||
|
}
|
||||||
|
) ?? '';
|
||||||
|
} else {
|
||||||
|
// Let user choose from existing connections to create connection string from
|
||||||
|
connectionInfo = await vscodeMssqlApi.promptForConnection(true);
|
||||||
|
if (!connectionInfo) {
|
||||||
|
// User cancelled return to selectedConnectionStringMethod prompt
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
connectionDetails = { options: connectionInfo };
|
||||||
|
try {
|
||||||
|
// Prompt to include password in connection string if authentication type is SqlLogin and connection has password saved
|
||||||
|
if (connectionInfo.authenticationType === 'SqlLogin' && connectionInfo.password) {
|
||||||
|
includePassword = await vscode.window.showQuickPick([constants.yesString, constants.noString], {
|
||||||
|
title: constants.includePassword,
|
||||||
|
canPickMany: false,
|
||||||
|
ignoreFocusOut: true
|
||||||
|
});
|
||||||
|
if (includePassword === constants.yesString) {
|
||||||
|
// set connection string to include password
|
||||||
|
connectionString = await vscodeMssqlApi.getConnectionString(connectionDetails, true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// set connection string to not include the password if connection info does not include password, or user chooses to not include password, or authentication type is not sql login
|
||||||
|
if (includePassword !== constants.yesString) {
|
||||||
|
connectionString = await vscodeMssqlApi.getConnectionString(connectionDetails, false, false);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// failed to get connection string for selected connection and will go back to prompt for connection string methods
|
||||||
|
console.warn(e);
|
||||||
|
void vscode.window.showErrorMessage(constants.failedToGetConnectionString);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (connectionString) {
|
||||||
|
try {
|
||||||
|
const projectFolder: string = path.dirname(projectUri.fsPath);
|
||||||
|
const localSettingsPath: string = path.join(projectFolder, constants.azureFunctionLocalSettingsFileName);
|
||||||
|
let userPassword: string | undefined;
|
||||||
|
// Ask user to enter password if auth type is sql login and password is not saved
|
||||||
|
if (connectionInfo?.authenticationType === 'SqlLogin' && !connectionInfo?.password) {
|
||||||
|
userPassword = await vscode.window.showInputBox({
|
||||||
|
prompt: constants.enterPasswordPrompt,
|
||||||
|
placeHolder: constants.enterPasswordManually,
|
||||||
|
ignoreFocusOut: true,
|
||||||
|
password: true,
|
||||||
|
validateInput: input => input ? undefined : constants.valueMustNotBeEmpty
|
||||||
|
});
|
||||||
|
if (userPassword) {
|
||||||
|
// if user enters password replace password placeholder with user entered password
|
||||||
|
connectionString = connectionString.replace(constants.passwordPlaceholder, userPassword);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (includePassword !== constants.yesString && !userPassword && connectionInfo?.authenticationType === 'SqlLogin') {
|
||||||
|
// if user does not want to include password or user does not enter password, show warning message that they will have to enter it manually later in local.settings.json
|
||||||
|
void vscode.window.showWarningMessage(constants.userPasswordLater, constants.openFile, constants.closeButton).then(async (result) => {
|
||||||
|
if (result === constants.openFile) {
|
||||||
|
// open local.settings.json file
|
||||||
|
void vscode.commands.executeCommand(constants.vscodeOpenCommand, vscode.Uri.file(localSettingsPath));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const success = await setLocalAppSetting(projectFolder, newConnectionStringSettingName, connectionString);
|
||||||
|
if (success) {
|
||||||
|
// exit both loops and insert binding
|
||||||
|
connectionStringSettingName = newConnectionStringSettingName;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
void vscode.window.showErrorMessage(constants.selectConnectionError());
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// display error message and show select setting quickpick again
|
||||||
|
void vscode.window.showErrorMessage(constants.selectConnectionError(e));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If user cancels out of this or doesn't want to overwrite an existing setting
|
||||||
|
// just return them to the select setting quickpick in case they changed their mind
|
||||||
|
connectionStringSettingName = selectedSetting.label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add sql extension package reference to project. If the reference is already there, it doesn't get added again
|
||||||
|
await addNugetReferenceToProjectFile(projectUri.fsPath);
|
||||||
|
} else {
|
||||||
|
// if no AF project was found or there's more than one AF functions project in the workspace,
|
||||||
|
// ask for the user to input the setting name
|
||||||
|
connectionStringSettingName = await vscode.window.showInputBox({
|
||||||
|
prompt: constants.connectionStringSetting,
|
||||||
|
placeHolder: constants.connectionStringSettingPlaceholder,
|
||||||
|
ignoreFocusOut: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return connectionStringSettingName;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,19 +4,13 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as path from 'path';
|
|
||||||
import { ConnectionDetails, IConnectionInfo } from 'vscode-mssql';
|
|
||||||
import * as constants from '../common/constants';
|
import * as constants from '../common/constants';
|
||||||
import * as utils from '../common/utils';
|
import * as utils from '../common/utils';
|
||||||
import * as azureFunctionsUtils from '../common/azureFunctionsUtils';
|
import * as azureFunctionsUtils from '../common/azureFunctionsUtils';
|
||||||
import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry';
|
import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry';
|
||||||
import { BindingType } from 'sql-bindings';
|
|
||||||
|
|
||||||
export async function launchAddSqlBindingQuickpick(uri: vscode.Uri | undefined): Promise<void> {
|
export async function launchAddSqlBindingQuickpick(uri: vscode.Uri | undefined): Promise<void> {
|
||||||
TelemetryReporter.sendActionEvent(TelemetryViews.SqlBindingsQuickPick, TelemetryActions.startAddSqlBinding);
|
TelemetryReporter.sendActionEvent(TelemetryViews.SqlBindingsQuickPick, TelemetryActions.startAddSqlBinding);
|
||||||
|
|
||||||
const vscodeMssqlApi = await utils.getVscodeMssqlApi();
|
|
||||||
|
|
||||||
if (!uri) {
|
if (!uri) {
|
||||||
// this command only shows in the command palette when the active editor is a .cs file, so we can safely assume that's the scenario
|
// this command only shows in the command palette when the active editor is a .cs file, so we can safely assume that's the scenario
|
||||||
// when this is called without a uri
|
// when this is called without a uri
|
||||||
@@ -62,34 +56,14 @@ export async function launchAddSqlBindingQuickpick(uri: vscode.Uri | undefined):
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. select input or output binding
|
// 2. select input or output binding
|
||||||
const inputOutputItems: (vscode.QuickPickItem & { type: BindingType })[] = [
|
const selectedBinding = await azureFunctionsUtils.promptForBindingType();
|
||||||
{
|
|
||||||
label: constants.input,
|
|
||||||
type: BindingType.input
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: constants.output,
|
|
||||||
type: BindingType.output
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const selectedBinding = (await vscode.window.showQuickPick(inputOutputItems, {
|
|
||||||
canPickMany: false,
|
|
||||||
title: constants.selectBindingType,
|
|
||||||
ignoreFocusOut: true
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (!selectedBinding) {
|
if (!selectedBinding) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. ask for object name for the binding
|
// 3. ask for object name for the binding
|
||||||
const objectName = await vscode.window.showInputBox({
|
const objectName = await azureFunctionsUtils.promptForObjectName(selectedBinding.type);
|
||||||
prompt: selectedBinding.type === BindingType.input ? constants.sqlTableOrViewToQuery : constants.sqlTableToUpsert,
|
|
||||||
placeHolder: constants.placeHolderObject,
|
|
||||||
validateInput: input => input ? undefined : constants.nameMustNotBeEmpty,
|
|
||||||
ignoreFocusOut: true
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!objectName) {
|
if (!objectName) {
|
||||||
return;
|
return;
|
||||||
@@ -103,176 +77,7 @@ export async function launchAddSqlBindingQuickpick(uri: vscode.Uri | undefined):
|
|||||||
// continue even if there's no AF project found. The binding should still be able to be added as long as there was an azure function found in the file earlier
|
// continue even if there's no AF project found. The binding should still be able to be added as long as there was an azure function found in the file earlier
|
||||||
}
|
}
|
||||||
|
|
||||||
let connectionStringSettingName;
|
let connectionStringSettingName = await azureFunctionsUtils.promptAndUpdateConnectionStringSetting(projectUri);
|
||||||
|
|
||||||
// show the settings from project's local.settings.json if there's an AF functions project
|
|
||||||
if (projectUri) {
|
|
||||||
let settings;
|
|
||||||
try {
|
|
||||||
settings = await azureFunctionsUtils.getLocalSettingsJson(path.join(path.dirname(projectUri.fsPath!), constants.azureFunctionLocalSettingsFileName));
|
|
||||||
} catch (e) {
|
|
||||||
void vscode.window.showErrorMessage(utils.getErrorMessage(e));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let existingSettings: (vscode.QuickPickItem)[] = [];
|
|
||||||
if (settings?.Values) {
|
|
||||||
existingSettings = Object.keys(settings.Values).map(setting => {
|
|
||||||
return {
|
|
||||||
label: setting
|
|
||||||
} as vscode.QuickPickItem;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
existingSettings.unshift({ label: constants.createNewLocalAppSettingWithIcon });
|
|
||||||
let sqlConnectionStringSettingExists = existingSettings.find(s => s.label === constants.sqlConnectionStringSetting);
|
|
||||||
|
|
||||||
while (!connectionStringSettingName) {
|
|
||||||
const selectedSetting = await vscode.window.showQuickPick(existingSettings, {
|
|
||||||
canPickMany: false,
|
|
||||||
title: constants.selectSetting,
|
|
||||||
ignoreFocusOut: true
|
|
||||||
});
|
|
||||||
if (!selectedSetting) {
|
|
||||||
// User cancelled
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedSetting.label === constants.createNewLocalAppSettingWithIcon) {
|
|
||||||
const newConnectionStringSettingName = await vscode.window.showInputBox(
|
|
||||||
{
|
|
||||||
title: constants.enterConnectionStringSettingName,
|
|
||||||
ignoreFocusOut: true,
|
|
||||||
value: sqlConnectionStringSettingExists ? '' : constants.sqlConnectionStringSetting,
|
|
||||||
validateInput: input => input ? undefined : constants.nameMustNotBeEmpty
|
|
||||||
}
|
|
||||||
) ?? '';
|
|
||||||
|
|
||||||
if (!newConnectionStringSettingName) {
|
|
||||||
// go back to select setting quickpick if user escapes from inputting the setting name in case they changed their mind
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// show the connection string methods (user input and connection profile options)
|
|
||||||
const listOfConnectionStringMethods = [constants.connectionProfile, constants.userConnectionString];
|
|
||||||
while (true) {
|
|
||||||
const selectedConnectionStringMethod = await vscode.window.showQuickPick(listOfConnectionStringMethods, {
|
|
||||||
canPickMany: false,
|
|
||||||
title: constants.selectConnectionString,
|
|
||||||
ignoreFocusOut: true
|
|
||||||
});
|
|
||||||
if (!selectedConnectionStringMethod) {
|
|
||||||
// User cancelled
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let connectionString: string = '';
|
|
||||||
let includePassword: string | undefined;
|
|
||||||
let connectionInfo: IConnectionInfo | undefined;
|
|
||||||
let connectionDetails: ConnectionDetails;
|
|
||||||
if (selectedConnectionStringMethod === constants.userConnectionString) {
|
|
||||||
// User chooses to enter connection string manually
|
|
||||||
connectionString = await vscode.window.showInputBox(
|
|
||||||
{
|
|
||||||
title: constants.enterConnectionString,
|
|
||||||
ignoreFocusOut: true,
|
|
||||||
value: 'Server=localhost;Initial Catalog={db_name};User ID=sa;Password={your_password};Persist Security Info=False',
|
|
||||||
validateInput: input => input ? undefined : constants.valueMustNotBeEmpty
|
|
||||||
}
|
|
||||||
) ?? '';
|
|
||||||
} else {
|
|
||||||
// Let user choose from existing connections to create connection string from
|
|
||||||
connectionInfo = await vscodeMssqlApi.promptForConnection(true);
|
|
||||||
if (!connectionInfo) {
|
|
||||||
// User cancelled return to selectedConnectionStringMethod prompt
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
connectionDetails = { options: connectionInfo };
|
|
||||||
try {
|
|
||||||
// Prompt to include password in connection string if authentication type is SqlLogin and connection has password saved
|
|
||||||
if (connectionInfo.authenticationType === 'SqlLogin' && connectionInfo.password) {
|
|
||||||
includePassword = await vscode.window.showQuickPick([constants.yesString, constants.noString], {
|
|
||||||
title: constants.includePassword,
|
|
||||||
canPickMany: false,
|
|
||||||
ignoreFocusOut: true
|
|
||||||
});
|
|
||||||
if (includePassword === constants.yesString) {
|
|
||||||
// set connection string to include password
|
|
||||||
connectionString = await vscodeMssqlApi.getConnectionString(connectionDetails, true, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// set connection string to not include the password if connection info does not include password, or user chooses to not include password, or authentication type is not sql login
|
|
||||||
if (includePassword !== constants.yesString) {
|
|
||||||
connectionString = await vscodeMssqlApi.getConnectionString(connectionDetails, false, false);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// failed to get connection string for selected connection and will go back to prompt for connection string methods
|
|
||||||
console.warn(e);
|
|
||||||
void vscode.window.showErrorMessage(constants.failedToGetConnectionString);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (connectionString) {
|
|
||||||
try {
|
|
||||||
const projectFolder: string = path.dirname(projectUri.fsPath);
|
|
||||||
const localSettingsPath: string = path.join(projectFolder, constants.azureFunctionLocalSettingsFileName);
|
|
||||||
let userPassword: string | undefined;
|
|
||||||
// Ask user to enter password if auth type is sql login and password is not saved
|
|
||||||
if (connectionInfo?.authenticationType === 'SqlLogin' && !connectionInfo?.password) {
|
|
||||||
userPassword = await vscode.window.showInputBox({
|
|
||||||
prompt: constants.enterPasswordPrompt,
|
|
||||||
placeHolder: constants.enterPasswordManually,
|
|
||||||
ignoreFocusOut: true,
|
|
||||||
password: true,
|
|
||||||
validateInput: input => input ? undefined : constants.valueMustNotBeEmpty
|
|
||||||
});
|
|
||||||
if (userPassword) {
|
|
||||||
// if user enters password replace password placeholder with user entered password
|
|
||||||
connectionString = connectionString.replace(constants.passwordPlaceholder, userPassword);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (includePassword !== constants.yesString && !userPassword && connectionInfo?.authenticationType === 'SqlLogin') {
|
|
||||||
// if user does not want to include password or user does not enter password, show warning message that they will have to enter it manually later in local.settings.json
|
|
||||||
void vscode.window.showWarningMessage(constants.userPasswordLater, constants.openFile, constants.closeButton).then(async (result) => {
|
|
||||||
if (result === constants.openFile) {
|
|
||||||
// open local.settings.json file
|
|
||||||
void vscode.commands.executeCommand(constants.vscodeOpenCommand, vscode.Uri.file(localSettingsPath));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const success = await azureFunctionsUtils.setLocalAppSetting(projectFolder, newConnectionStringSettingName, connectionString);
|
|
||||||
if (success) {
|
|
||||||
// exit both loops and insert binding
|
|
||||||
connectionStringSettingName = newConnectionStringSettingName;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
void vscode.window.showErrorMessage(constants.selectConnectionError());
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// display error message and show select setting quickpick again
|
|
||||||
void vscode.window.showErrorMessage(constants.selectConnectionError(e));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If user cancels out of this or doesn't want to overwrite an existing setting
|
|
||||||
// just return them to the select setting quickpick in case they changed their mind
|
|
||||||
connectionStringSettingName = selectedSetting.label;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Add sql extension package reference to project. If the reference is already there, it doesn't get added again
|
|
||||||
await azureFunctionsUtils.addNugetReferenceToProjectFile(projectUri.fsPath);
|
|
||||||
} else {
|
|
||||||
// if no AF project was found or there's more than one AF functions project in the workspace,
|
|
||||||
// ask for the user to input the setting name
|
|
||||||
connectionStringSettingName = await vscode.window.showInputBox({
|
|
||||||
prompt: constants.connectionStringSetting,
|
|
||||||
placeHolder: constants.connectionStringSettingPlaceholder,
|
|
||||||
ignoreFocusOut: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!connectionStringSettingName) {
|
if (!connectionStringSettingName) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ import * as vscode from 'vscode';
|
|||||||
import { ITreeNodeInfo } from 'vscode-mssql';
|
import { ITreeNodeInfo } from 'vscode-mssql';
|
||||||
import { IExtension, BindingType } from 'sql-bindings';
|
import { IExtension, BindingType } from 'sql-bindings';
|
||||||
import { getAzdataApi, getVscodeMssqlApi } from './common/utils';
|
import { getAzdataApi, getVscodeMssqlApi } from './common/utils';
|
||||||
import { launchAddSqlBindingQuickpick } from './dialogs/addSqlBindingQuickpick';
|
|
||||||
import { addSqlBinding, createAzureFunction, getAzureFunctions } from './services/azureFunctionsService';
|
import { addSqlBinding, createAzureFunction, getAzureFunctions } from './services/azureFunctionsService';
|
||||||
|
import { launchAddSqlBindingQuickpick } from './dialogs/addSqlBindingQuickpick';
|
||||||
|
import { promptForBindingType, promptAndUpdateConnectionStringSetting, promptForObjectName } from './common/azureFunctionsUtils';
|
||||||
|
|
||||||
export async function activate(context: vscode.ExtensionContext): Promise<IExtension> {
|
export async function activate(context: vscode.ExtensionContext): Promise<IExtension> {
|
||||||
const vscodeMssqlApi = await getVscodeMssqlApi();
|
const vscodeMssqlApi = await getVscodeMssqlApi();
|
||||||
|
|
||||||
void vscode.commands.executeCommand('setContext', 'azdataAvailable', !!getAzdataApi());
|
void vscode.commands.executeCommand('setContext', 'azdataAvailable', !!getAzdataApi());
|
||||||
// register the add sql binding command
|
// register the add sql binding command
|
||||||
context.subscriptions.push(vscode.commands.registerCommand('sqlBindings.addSqlBinding', async (uri: vscode.Uri | undefined) => { return launchAddSqlBindingQuickpick(uri); }));
|
context.subscriptions.push(vscode.commands.registerCommand('sqlBindings.addSqlBinding', async (uri: vscode.Uri | undefined) => { return launchAddSqlBindingQuickpick(uri); }));
|
||||||
@@ -37,6 +37,15 @@ export async function activate(context: vscode.ExtensionContext): Promise<IExten
|
|||||||
addSqlBinding: async (bindingType: BindingType, filePath: string, functionName: string, objectName: string, connectionStringSetting: string) => {
|
addSqlBinding: async (bindingType: BindingType, filePath: string, functionName: string, objectName: string, connectionStringSetting: string) => {
|
||||||
return addSqlBinding(bindingType, filePath, functionName, objectName, connectionStringSetting);
|
return addSqlBinding(bindingType, filePath, functionName, objectName, connectionStringSetting);
|
||||||
},
|
},
|
||||||
|
promptForBindingType: async () => {
|
||||||
|
return promptForBindingType();
|
||||||
|
},
|
||||||
|
promptForObjectName: async (bindingType: BindingType) => {
|
||||||
|
return promptForObjectName(bindingType);
|
||||||
|
},
|
||||||
|
promptAndUpdateConnectionStringSetting: async (projectUri: vscode.Uri | undefined) => {
|
||||||
|
return promptAndUpdateConnectionStringSetting(projectUri);
|
||||||
|
},
|
||||||
getAzureFunctions: async (filePath: string) => {
|
getAzureFunctions: async (filePath: string) => {
|
||||||
return getAzureFunctions(filePath);
|
return getAzureFunctions(filePath);
|
||||||
}
|
}
|
||||||
|
|||||||
25
extensions/sql-bindings/src/sql-bindings.d.ts
vendored
25
extensions/sql-bindings/src/sql-bindings.d.ts
vendored
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
declare module 'sql-bindings' {
|
declare module 'sql-bindings' {
|
||||||
|
|
||||||
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
export const enum extension {
|
export const enum extension {
|
||||||
name = 'Microsoft.sql-bindings',
|
name = 'Microsoft.sql-bindings',
|
||||||
vsCodeName = 'ms-mssql.sql-bindings-vscode'
|
vsCodeName = 'ms-mssql.sql-bindings-vscode'
|
||||||
@@ -25,12 +27,29 @@ declare module 'sql-bindings' {
|
|||||||
*/
|
*/
|
||||||
addSqlBinding(bindingType: BindingType, filePath: string, functionName: string, objectName: string, connectionStringSetting: string): Promise<ResultStatus>;
|
addSqlBinding(bindingType: BindingType, filePath: string, functionName: string, objectName: string, connectionStringSetting: string): Promise<ResultStatus>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompts the user to select type of binding and returns result
|
||||||
|
*/
|
||||||
|
promptForBindingType(): Promise<(vscode.QuickPickItem & { type: BindingType }) | undefined>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompts the user to enter object name for the SQL query
|
||||||
|
* @param bindingType Type of SQL Binding
|
||||||
|
*/
|
||||||
|
promptForObjectName(bindingType: BindingType): Promise<string | undefined>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompts the user to enter connection setting and updates it from AF project
|
||||||
|
* @param projectUri Azure Function project uri
|
||||||
|
*/
|
||||||
|
promptAndUpdateConnectionStringSetting(projectUri: vscode.Uri | undefined): Promise<string | undefined>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the names of the Azure Functions in the file
|
* Gets the names of the Azure Functions in the file
|
||||||
* @param filePath Path of the file to get the Azure Functions
|
* @param filePath Path of the file to get the Azure Functions
|
||||||
* @returns array of names of Azure Functions in the file
|
* @returns array of names of Azure Functions in the file
|
||||||
*/
|
*/
|
||||||
getAzureFunctions(filePath: string): Promise<GetAzureFunctionsResult>;
|
getAzureFunctions(filePath: string): Promise<GetAzureFunctionsResult>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,7 +101,7 @@ declare module 'sql-bindings' {
|
|||||||
/**
|
/**
|
||||||
* Parameters for getting the names of the Azure Functions in a file
|
* Parameters for getting the names of the Azure Functions in a file
|
||||||
*/
|
*/
|
||||||
export interface GetAzureFunctionsParams {
|
export interface GetAzureFunctionsParams {
|
||||||
/**
|
/**
|
||||||
* Absolute file path of file to get Azure Functions
|
* Absolute file path of file to get Azure Functions
|
||||||
*/
|
*/
|
||||||
@@ -92,7 +111,7 @@ declare module 'sql-bindings' {
|
|||||||
/**
|
/**
|
||||||
* Result from a get Azure Functions request
|
* Result from a get Azure Functions request
|
||||||
*/
|
*/
|
||||||
export interface GetAzureFunctionsResult extends ResultStatus {
|
export interface GetAzureFunctionsResult extends ResultStatus {
|
||||||
/**
|
/**
|
||||||
* Array of names of Azure Functions in the file
|
* Array of names of Azure Functions in the file
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user