Add support for System database package references for SDK-style sql projects (#23309)

* add package reference type for system db references

* Add radio buttons

* hookup

* add test

* handle changing reference type radio buttons

* cleanup

* update strings

* change style to type

* change more places with style to type

* blank lines
This commit is contained in:
Kim Santiago
2023-06-13 13:06:12 -10:00
committed by GitHub
parent 398a91456d
commit 1ff0a07217
12 changed files with 136 additions and 24 deletions

View File

@@ -291,7 +291,7 @@ export function retryMessage(name: string, error: string) { return localize('ret
//#region Add Database Reference dialog strings
export const addDatabaseReferenceDialogName = localize('addDatabaseReferencedialogName', "Add database reference");
export const addDatabaseReferenceOkButtonText = localize('addDatabaseReferenceOkButtonText', "Add reference");
export const referenceRadioButtonsGroupTitle = localize('referenceRadioButtonsGroupTitle', "Type");
export const referenceRadioButtonsGroupTitle = localize('referenceRadioButtonsGroupTitle', "Referenced Database Type");
export const projectLabel = localize('projectLocString', "Project");
export const systemDatabase = localize('systemDatabase', "System database");
export const dacpacText = localize('dacpacText', "Data-tier application (.dacpac)");
@@ -323,6 +323,9 @@ export const referencedDatabaseType = localize('referencedDatabaseType', "Refere
export const excludeFolderNotSupported = localize('excludeFolderNotSupported', "Excluding folders is not yet supported");
export const unhandledDeleteType = (itemType: string): string => { return localize('unhandledDeleteType', "Unhandled item type during delete: '{0}", itemType); }
export const unhandledExcludeType = (itemType: string): string => { return localize('unhandledDeleteType', "Unhandled item type during exclude: '{0}", itemType); }
export const artifactReference = localize('artifactReference', "Artifact Reference");
export const packageReference = localize('packageReference', "Package Reference");
export const referenceTypeRadioButtonsGroupTitle = localize('referenceTypeRadioButtonsGroupTitle', "Reference Type");
//#endregion

View File

@@ -9,4 +9,5 @@ import * as vscodeMssql from 'vscode-mssql';
export type ProjectType = mssql.ProjectType | vscodeMssql.ProjectType;
export type GetScriptsResult = mssql.GetScriptsResult | vscodeMssql.GetScriptsResult;
export type GetFoldersResult = mssql.GetFoldersResult | vscodeMssql.GetFoldersResult;
export type SystemDatabase = mssql.SystemDatabase | vscodeMssql.SystemDatabase;
export type SystemDatabase = mssql.SystemDatabase | vscodeMssql.SystemDatabase;
export type SystemDbReferenceType = mssql.SystemDbReferenceType | vscodeMssql.SystemDbReferenceType;

View File

@@ -16,7 +16,7 @@ import { ISystemDatabaseReferenceSettings, IDacpacReferenceSettings, IProjectRef
import { Deferred } from '../common/promise';
import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry';
import { DbServerValues, ensureSetOrDefined, populateResultWithVars } from './utils';
import { ProjectType } from 'mssql';
import { ProjectType, SystemDbReferenceType } from 'mssql';
export enum ReferencedDatabaseType {
project,
@@ -48,7 +48,10 @@ export class AddDatabaseReferenceDialog {
public exampleUsage: azdataType.TextComponent | undefined;
private projectRadioButton: azdataType.RadioButtonComponent | undefined;
private systemDatabaseRadioButton: azdataType.RadioButtonComponent | undefined;
private systemDatabaseArtifactRefRadioButton: azdataType.RadioButtonComponent | undefined;
private systemDatabasePackageRefRadioButton: azdataType.RadioButtonComponent | undefined;
private systemDbRefRadioButtonsComponent: azdataType.FormComponent | undefined;
private systemDbRefType: SystemDbReferenceType = SystemDbReferenceType.ArtifactReference;
public currentReferencedDatabaseType: ReferencedDatabaseType | undefined;
private toDispose: vscode.Disposable[] = [];
@@ -107,12 +110,14 @@ export class AddDatabaseReferenceDialog {
this.addDatabaseReferenceTab.registerContent(async view => {
this.view = view;
this.projectFormComponent = await this.createProjectDropdown();
const radioButtonGroup = this.createRadioButtons();
const radioButtonGroup = this.createReferenceTypeRadioButtons();
this.systemDatabaseFormComponent = this.createSystemDatabaseDropdown();
this.dacpacFormComponent = this.createDacpacTextbox();
this.nupkgFormComponent = this.createNupkgFormComponentGroup();
const locationDropdown = this.createLocationDropdown();
const variableSection = this.createVariableSection();
this.systemDbRefRadioButtonsComponent = this.createSystemDbReferenceTypeRadioButtons();
this.suppressMissingDependenciesErrorsCheckbox = view.modelBuilder.checkBox().withProps({
label: constants.suppressMissingDependenciesErrors
}).component();
@@ -148,6 +153,8 @@ export class AddDatabaseReferenceDialog {
await this.projectRadioButton?.focus();
} else {
await this.systemDatabaseRadioButton?.focus();
this.insertSystemDatabaseReferenceTypeComponent();
}
this.initDialogComplete.resolve();
@@ -161,7 +168,8 @@ export class AddDatabaseReferenceDialog {
const systemDbRef: ISystemDatabaseReferenceSettings = {
databaseVariableLiteralValue: <string>this.databaseNameTextbox?.value,
systemDb: utils.getSystemDatabase(<string>this.systemDatabaseDropdown?.value),
suppressMissingDependenciesErrors: <boolean>this.suppressMissingDependenciesErrorsCheckbox?.checked
suppressMissingDependenciesErrors: <boolean>this.suppressMissingDependenciesErrorsCheckbox?.checked,
systemDbReferenceType: this.systemDbRefType
};
referenceSettings = systemDbRef;
@@ -212,7 +220,7 @@ export class AddDatabaseReferenceDialog {
this.dispose();
}
private createRadioButtons(): azdataType.FormComponent {
private createReferenceTypeRadioButtons(): azdataType.FormComponent {
this.projectRadioButton = this.view!.modelBuilder.radioButton()
.withProps({
name: 'referencedDatabaseType',
@@ -291,10 +299,61 @@ export class AddDatabaseReferenceDialog {
};
}
private createSystemDbReferenceTypeRadioButtons(): azdataType.FormComponent {
this.systemDatabasePackageRefRadioButton = this.view!.modelBuilder.radioButton()
.withProps({
name: 'systemDbRefType',
label: constants.packageReference
}).component();
this.systemDatabasePackageRefRadioButton.onDidChangeCheckedState((checked) => {
if (checked) {
this.systemDbRefType = SystemDbReferenceType.PackageReference;
}
});
this.systemDatabaseArtifactRefRadioButton = this.view!.modelBuilder.radioButton()
.withProps({
name: 'systemDbRefType',
label: constants.artifactReference
}).component();
this.systemDatabaseArtifactRefRadioButton.onDidChangeCheckedState((checked) => {
if (checked) {
this.systemDbRefType = SystemDbReferenceType.ArtifactReference;
}
});
const radioButtons = [this.systemDatabasePackageRefRadioButton!, this.systemDatabaseArtifactRefRadioButton!];
const flexRadioButtonsModel: azdataType.FlexContainer = this.view!.modelBuilder.flexContainer()
.withLayout({ flexFlow: 'column' })
.withItems(radioButtons)
.withProps({ ariaRole: 'radiogroup', ariaLabel: constants.referenceTypeRadioButtonsGroupTitle })
.component();
// default to PackageReference for SDK-style projects
this.systemDatabasePackageRefRadioButton!.checked = true;
return {
component: flexRadioButtonsModel,
title: constants.referenceTypeRadioButtonsGroupTitle
};
}
private insertSystemDatabaseReferenceTypeComponent(): void {
// add the radio buttons to choose ArtifactReference or PackageReference if it's an SDK-syle project
if (this.project.sqlProjStyle === ProjectType.SdkStyle) {
this.formBuilder!.insertFormItem(this.systemDbRefRadioButtonsComponent!, 3);
this.systemDbRefType = SystemDbReferenceType.PackageReference;
}
}
public projectRadioButtonClick(): void {
this.formBuilder!.removeFormItem(<azdataType.FormComponent>this.dacpacFormComponent);
this.formBuilder!.removeFormItem(<azdataType.FormComponent>this.systemDatabaseFormComponent);
this.formBuilder!.removeFormItem(<azdataType.FormComponentGroup>this.nupkgFormComponent);
this.formBuilder!.removeFormItem(<azdataType.FormComponent>this.systemDbRefRadioButtonsComponent);
this.formBuilder!.insertFormItem(<azdataType.FormComponent>this.projectFormComponent, 2);
this.locationDropdown!.values = constants.locationDropdownValues;
@@ -310,6 +369,7 @@ export class AddDatabaseReferenceDialog {
this.formBuilder!.removeFormItem(<azdataType.FormComponent>this.projectFormComponent);
this.formBuilder!.removeFormItem(<azdataType.FormComponentGroup>this.nupkgFormComponent);
this.formBuilder!.insertFormItem(<azdataType.FormComponent>this.systemDatabaseFormComponent, 2);
this.insertSystemDatabaseReferenceTypeComponent();
// update dropdown values because only different database, same server is a valid location for system db references
this.locationDropdown!.values = constants.systemDbLocationDropdownValues;
@@ -325,6 +385,7 @@ export class AddDatabaseReferenceDialog {
this.formBuilder!.removeFormItem(<azdataType.FormComponent>this.systemDatabaseFormComponent);
this.formBuilder!.removeFormItem(<azdataType.FormComponent>this.projectFormComponent);
this.formBuilder!.removeFormItem(<azdataType.FormComponentGroup>this.nupkgFormComponent);
this.formBuilder!.removeFormItem(<azdataType.FormComponent>this.systemDbRefRadioButtonsComponent);
this.formBuilder!.insertFormItem(<azdataType.FormComponent>this.dacpacFormComponent, 2);
this.locationDropdown!.values = constants.locationDropdownValues;
@@ -339,6 +400,7 @@ export class AddDatabaseReferenceDialog {
this.formBuilder!.removeFormItem(<azdataType.FormComponent>this.systemDatabaseFormComponent);
this.formBuilder!.removeFormItem(<azdataType.FormComponent>this.projectFormComponent);
this.formBuilder!.removeFormItem(<azdataType.FormComponent>this.dacpacFormComponent);
this.formBuilder!.removeFormItem(<azdataType.FormComponent>this.systemDbRefRadioButtonsComponent);
this.formBuilder!.insertFormItem(<azdataType.FormComponentGroup>this.nupkgFormComponent, 2);
this.locationDropdown!.values = constants.locationDropdownValues;

View File

@@ -13,9 +13,7 @@ import { IDacpacReferenceSettings, INugetPackageReferenceSettings, IProjectRefer
import { Project } from '../models/project';
import { getSystemDbOptions, promptDacpacLocation } from './addDatabaseReferenceDialog';
import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry';
import { ProjectType } from 'mssql';
import { ProjectType, SystemDbReferenceType } from 'vscode-mssql';
/**
* Create flow for adding a database reference using only VS Code-native APIs such as QuickPick
@@ -137,7 +135,8 @@ async function addSystemDatabaseReference(project: Project): Promise<ISystemData
return {
databaseVariableLiteralValue: dbName,
systemDb: getSystemDatabase(selectedSystemDb),
suppressMissingDependenciesErrors: suppressErrors
suppressMissingDependenciesErrors: suppressErrors,
systemDbReferenceType: SystemDbReferenceType.ArtifactReference
};
}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Uri } from 'vscode';
import { SystemDatabase } from '../common/typeHelper';
import { SystemDatabase, SystemDbReferenceType } from '../common/typeHelper';
export interface IDatabaseReferenceSettings {
databaseVariableLiteralValue?: string;
@@ -13,6 +13,7 @@ export interface IDatabaseReferenceSettings {
export interface ISystemDatabaseReferenceSettings extends IDatabaseReferenceSettings {
systemDb: SystemDatabase;
systemDbReferenceType: SystemDbReferenceType;
}
export interface IUserDatabaseReferenceSettings extends IDatabaseReferenceSettings {

View File

@@ -830,13 +830,12 @@ export class Project implements ISqlProject {
throw new Error(constants.databaseReferenceAlreadyExists);
}
let systemDb;
let result;
let sqlProjService;
let systemDb, referenceType, result, sqlProjService;
if (utils.getAzdataApi()) {
systemDb = <unknown>settings.systemDb as mssql.SystemDatabase;
referenceType = settings.systemDbReferenceType as mssql.SystemDbReferenceType;
sqlProjService = this.sqlProjService as mssql.ISqlProjectsService;
result = await sqlProjService.addSystemDatabaseReference(this.projectFilePath, systemDb, settings.suppressMissingDependenciesErrors, settings.databaseVariableLiteralValue);
result = await sqlProjService.addSystemDatabaseReference(this.projectFilePath, systemDb, settings.suppressMissingDependenciesErrors, referenceType, settings.databaseVariableLiteralValue);
} else {
systemDb = <unknown>settings.systemDb as vscodeMssql.SystemDatabase;
sqlProjService = this.sqlProjService as vscodeMssql.ISqlProjectsService;

View File

@@ -17,7 +17,7 @@ import { Uri, window } from 'vscode';
import { IDacpacReferenceSettings, INugetPackageReferenceSettings, IProjectReferenceSettings, ISystemDatabaseReferenceSettings } from '../models/IDatabaseReferenceSettings';
import { ItemType } from 'sqldbproj';
import { SystemDatabaseReferenceProjectEntry, SqlProjectReferenceProjectEntry, DacpacReferenceProjectEntry } from '../models/projectEntry';
import { ProjectType, SystemDatabase } from 'mssql';
import { ProjectType, SystemDatabase, SystemDbReferenceType } from 'mssql';
describe('Project: sqlproj content operations', function (): void {
before(async function (): Promise<void> {
@@ -551,15 +551,40 @@ describe('Project: database references', function (): void {
should(ref).equal(undefined, 'msdb reference should be deleted');
});
it('Should add system database reference correctly', async function (): Promise<void> {
it('Should add system database artifact reference correctly', async function (): Promise<void> {
let project = await testUtils.createTestSqlProject(this.test);
const msdbRefSettings: ISystemDatabaseReferenceSettings = { databaseVariableLiteralValue: systemDatabaseToString(SystemDatabase.MSDB), systemDb: SystemDatabase.MSDB, suppressMissingDependenciesErrors: true };
const msdbRefSettings: ISystemDatabaseReferenceSettings = {
databaseVariableLiteralValue: systemDatabaseToString(SystemDatabase.MSDB),
systemDb: SystemDatabase.MSDB,
suppressMissingDependenciesErrors: true,
systemDbReferenceType: SystemDbReferenceType.ArtifactReference
};
await project.addSystemDatabaseReference(msdbRefSettings);
(project.databaseReferences.length).should.equal(1, 'There should be one database reference after adding a reference to msdb');
(project.databaseReferences[0].referenceName).should.equal(msdbRefSettings.databaseVariableLiteralValue, 'databaseName');
(project.databaseReferences[0].suppressMissingDependenciesErrors).should.equal(msdbRefSettings.suppressMissingDependenciesErrors, 'suppressMissingDependenciesErrors');
const projFileText = (await fs.readFile(project.projectFilePath)).toString();
(projFileText).should.containEql('<ArtifactReference Include="$(SystemDacpacsLocation)');
});
it('Should add system database package reference correctly', async function (): Promise<void> {
let project = await testUtils.createTestSqlProject(this.test);
const msdbRefSettings: ISystemDatabaseReferenceSettings = {
databaseVariableLiteralValue: systemDatabaseToString(SystemDatabase.MSDB),
systemDb: SystemDatabase.MSDB,
suppressMissingDependenciesErrors: true,
systemDbReferenceType: SystemDbReferenceType.PackageReference
};
await project.addSystemDatabaseReference(msdbRefSettings);
(project.databaseReferences.length).should.equal(1, 'There should be one database reference after adding a reference to msdb');
(project.databaseReferences[0].referenceName).should.equal(msdbRefSettings.databaseVariableLiteralValue, 'databaseName');
(project.databaseReferences[0].suppressMissingDependenciesErrors).should.equal(msdbRefSettings.suppressMissingDependenciesErrors, 'suppressMissingDependenciesErrors');
const projFileText = (await fs.readFile(project.projectFilePath)).toString();
(projFileText).should.containEql('Include="Microsoft.SqlServer.Dacpacs.Msdb">');
});
it('Should add a dacpac reference to the same database correctly', async function (): Promise<void> {
@@ -783,7 +808,12 @@ describe('Project: database references', function (): void {
should(project.databaseReferences.length).equal(0, 'There should be no database references to start with');
const systemDbReference: ISystemDatabaseReferenceSettings = { databaseVariableLiteralValue: systemDatabaseToString(SystemDatabase.Master), systemDb: SystemDatabase.Master, suppressMissingDependenciesErrors: false };
const systemDbReference: ISystemDatabaseReferenceSettings = {
databaseVariableLiteralValue: systemDatabaseToString(SystemDatabase.Master),
systemDb: SystemDatabase.Master,
suppressMissingDependenciesErrors: false,
systemDbReferenceType: SystemDbReferenceType.ArtifactReference
};
await project.addSystemDatabaseReference(systemDbReference);
project = await Project.openProject(projFilePath);
should(project.databaseReferences.length).equal(1, 'There should be one database reference after adding a reference to master');

View File

@@ -686,7 +686,7 @@ describe('ProjectsController', function (): void {
addDbReferenceDialog.callBase = true;
addDbReferenceDialog.setup(x => x.addReferenceClick()).returns(() => {
return projController.object.addDatabaseReferenceCallback(proj,
{ systemDb: SystemDatabase.Master, databaseName: 'master', suppressMissingDependenciesErrors: false },
{ systemDb: SystemDatabase.Master, databaseName: 'master', suppressMissingDependenciesErrors: false, systemDbReferenceType: mssql.SystemDbReferenceType.ArtifactReference },
{ treeDataProvider: new SqlDatabaseProjectTreeViewProvider(), element: undefined });
});
addDbReferenceDialog.setup(x => x.openDialog()).returns(() => Promise.resolve());