diff --git a/extensions/sql-database-projects/resources/templates/newSqlProjectTemplate.xml b/extensions/sql-database-projects/resources/templates/newSqlProjectTemplate.xml index 6b8dc0d1ee..1227f5647f 100644 --- a/extensions/sql-database-projects/resources/templates/newSqlProjectTemplate.xml +++ b/extensions/sql-database-projects/resources/templates/newSqlProjectTemplate.xml @@ -7,7 +7,7 @@ 2.0 4.1 {@@PROJECT_GUID@@} - Microsoft.Data.Tools.Schema.Sql.Sql150DatabaseSchemaProvider + Microsoft.Data.Tools.Schema.Sql.Sql@@PROJECT_DSP@@DatabaseSchemaProvider Database diff --git a/extensions/sql-database-projects/src/common/constants.ts b/extensions/sql-database-projects/src/common/constants.ts index 0fefb2a341..362b843c23 100644 --- a/extensions/sql-database-projects/src/common/constants.ts +++ b/extensions/sql-database-projects/src/common/constants.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vscode-nls'; +import { SqlTargetPlatform } from 'sqldbproj'; const localize = nls.loadMessageBundle(); @@ -345,31 +346,28 @@ export const sameDatabaseExampleUsage = 'SELECT * FROM [Schema1].[Table1]'; export function differentDbSameServerExampleUsage(db: string) { return `SELECT * FROM [${db}].[Schema1].[Table1]`; } export function differentDbDifferentServerExampleUsage(server: string, db: string) { return `SELECT * FROM [${server}].[${db}].[Schema1].[Table1]`; } -export const sqlServer2005 = 'SQL Server 2005'; -export const sqlServer2008 = 'SQL Server 2008'; -export const sqlServer2012 = 'SQL Server 2012'; -export const sqlServer2014 = 'SQL Server 2014'; -export const sqlServer2016 = 'SQL Server 2016'; -export const sqlServer2017 = 'SQL Server 2017'; -export const sqlServer2019 = 'SQL Server 2019'; -export const sqlAzure = 'Microsoft Azure SQL Database'; -export const sqlDW = 'Microsoft Azure SQL Data Warehouse'; - export const targetPlatformToVersion: Map = new Map([ - [sqlServer2005, '90'], - [sqlServer2008, '100'], - [sqlServer2012, '110'], - [sqlServer2014, '120'], - [sqlServer2016, '130'], - [sqlServer2017, '140'], - [sqlServer2019, '150'], - [sqlAzure, 'AzureV12'], - [sqlDW, 'Dw'] + [SqlTargetPlatform.sqlServer2005, '90'], + [SqlTargetPlatform.sqlServer2008, '100'], + [SqlTargetPlatform.sqlServer2012, '110'], + [SqlTargetPlatform.sqlServer2014, '120'], + [SqlTargetPlatform.sqlServer2016, '130'], + [SqlTargetPlatform.sqlServer2017, '140'], + [SqlTargetPlatform.sqlServer2019, '150'], + [SqlTargetPlatform.sqlAzure, 'AzureV12'], + [SqlTargetPlatform.sqlDW, 'Dw'] ]); // DW is special since the system dacpac folder has a different name from the target platform export const AzureDwFolder = 'AzureDw'; +export const defaultDSP = targetPlatformToVersion.get(SqlTargetPlatform.sqlServer2019)!; + +/** + * Returns the name of the target platform of the version of sql + * @param version version of sql + * @returns target platform name + */ export function getTargetPlatformFromVersion(version: string): string { return Array.from(targetPlatformToVersion.keys()).filter(k => targetPlatformToVersion.get(k) === version)[0]; } diff --git a/extensions/sql-database-projects/src/controllers/projectController.ts b/extensions/sql-database-projects/src/controllers/projectController.ts index dede788cbe..c1ea0c84ae 100644 --- a/extensions/sql-database-projects/src/controllers/projectController.ts +++ b/extensions/sql-database-projects/src/controllers/projectController.ts @@ -34,6 +34,7 @@ import { CreateProjectFromDatabaseDialog } from '../dialogs/createProjectFromDat import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry'; import { IconPathHelper } from '../common/iconHelper'; import { DashboardData, PublishData, Status } from '../models/dashboardData/dashboardData'; +import { SqlTargetPlatform } from 'sqldbproj'; import { launchPublishDatabaseQuickpick } from '../dialogs/publishDatabaseQuickpick'; const maxTableLength = 10; @@ -137,7 +138,8 @@ export class ProjectsController { const macroDict: Record = { 'PROJECT_NAME': creationParams.newProjName, - 'PROJECT_GUID': creationParams.projectGuid ?? UUID.generateUuid().toUpperCase() + 'PROJECT_GUID': creationParams.projectGuid ?? UUID.generateUuid().toUpperCase(), + 'PROJECT_DSP': creationParams.targetPlatform ? constants.targetPlatformToVersion.get(creationParams.targetPlatform)! : constants.defaultDSP }; let newProjFileContents = templates.macroExpansion(templates.newSqlProjectTemplate, macroDict); @@ -990,4 +992,5 @@ export interface NewProjectParams { folderUri: vscode.Uri; projectTypeId: string; projectGuid?: string; + targetPlatform?: SqlTargetPlatform; } diff --git a/extensions/sql-database-projects/src/models/project.ts b/extensions/sql-database-projects/src/models/project.ts index ba7ae1ebd2..48ce59f352 100644 --- a/extensions/sql-database-projects/src/models/project.ts +++ b/extensions/sql-database-projects/src/models/project.ts @@ -12,7 +12,7 @@ import * as os from 'os'; import * as templates from '../templates/templates'; import { Uri, window } from 'vscode'; -import { IFileProjectEntry, ISqlProject } from 'sqldbproj'; +import { IFileProjectEntry, ISqlProject, SqlTargetPlatform } from 'sqldbproj'; import { promises as fs } from 'fs'; import { DataSource } from './dataSources/dataSources'; import { ISystemDatabaseReferenceSettings, IDacpacReferenceSettings, IProjectReferenceSettings } from './IDatabaseReferenceSettings'; @@ -512,9 +512,12 @@ export class Project implements ISqlProject { // DW is special because the target version is DW, but the folder name for system dacpacs is AzureDW in SSDT // the other target versions have the same version name and folder name - return version === constants.targetPlatformToVersion.get(constants.sqlDW) ? constants.AzureDwFolder : version; + return version === constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlDW) ? constants.AzureDwFolder : version; } + /** + * Gets the project target version specified in the DSP property in the sqlproj + */ public getProjectTargetVersion(): string { let dsp: string | undefined; diff --git a/extensions/sql-database-projects/src/projectProvider/projectProvider.ts b/extensions/sql-database-projects/src/projectProvider/projectProvider.ts index d7469461ba..94a5f6ca66 100644 --- a/extensions/sql-database-projects/src/projectProvider/projectProvider.ts +++ b/extensions/sql-database-projects/src/projectProvider/projectProvider.ts @@ -57,11 +57,12 @@ export class SqlDatabaseProjectProvider implements dataworkspace.IProjectProvide * @param projectTypeId the ID of the project/template * @returns Uri of the newly created project file */ - async createProject(name: string, location: vscode.Uri, projectTypeId: string): Promise { + async createProject(name: string, location: vscode.Uri, projectTypeId: string, targetPlatform?: sqldbproj.SqlTargetPlatform): Promise { const projectFile = await this.projectController.createNewProject({ newProjName: name, folderUri: location, - projectTypeId: projectTypeId + projectTypeId: projectTypeId, + targetPlatform: targetPlatform }); return vscode.Uri.file(projectFile); diff --git a/extensions/sql-database-projects/src/sqldbproj.d.ts b/extensions/sql-database-projects/src/sqldbproj.d.ts index 595d35466f..d4e6b62f24 100644 --- a/extensions/sql-database-projects/src/sqldbproj.d.ts +++ b/extensions/sql-database-projects/src/sqldbproj.d.ts @@ -18,9 +18,10 @@ declare module 'sqldbproj' { * @param name name of the project * @param location the parent directory * @param projectTypeId the ID of the project/template + * @param targetPlatform the target platform for the project. Default is SQL Server 2019 * @returns Uri of the newly created project file */ - createProject(name: string, location: vscode.Uri, projectTypeId: string): Promise; + createProject(name: string, location: vscode.Uri, projectTypeId: string, targetPlatform: SqlTargetPlatform): Promise; /** * Opens and loads a .sqlproj file @@ -130,4 +131,19 @@ declare module 'sqldbproj' { fsUri: vscode.Uri; relativePath: string; } + + /** + * Target platforms for a sql project + */ + export const enum SqlTargetPlatform { + sqlServer2005 = 'SQL Server 2005', + sqlServer2008 = 'SQL Server 2008', + sqlServer2012 = 'SQL Server 2012', + sqlServer2014 = 'SQL Server 2014', + sqlServer2016 = 'SQL Server 2016', + sqlServer2017 = 'SQL Server 2017', + sqlServer2019 = 'SQL Server 2019', + sqlAzure = 'Microsoft Azure SQL Database', + sqlDW = 'Microsoft Azure SQL Data Warehouse' + } } diff --git a/extensions/sql-database-projects/src/test/project.test.ts b/extensions/sql-database-projects/src/test/project.test.ts index be799ed325..adb533873d 100644 --- a/extensions/sql-database-projects/src/test/project.test.ts +++ b/extensions/sql-database-projects/src/test/project.test.ts @@ -16,6 +16,7 @@ import { Project, EntryType, SystemDatabase, SystemDatabaseReferenceProjectEntry import { exists, convertSlashesForSqlProj, trimChars, trimUri } from '../common/utils'; import { Uri, window } from 'vscode'; import { IDacpacReferenceSettings, IProjectReferenceSettings, ISystemDatabaseReferenceSettings } from '../models/IDatabaseReferenceSettings'; +import { SqlTargetPlatform } from 'sqldbproj'; let projFilePath: string; @@ -155,19 +156,19 @@ describe('Project: sqlproj content operations', function (): void { should.equal(uri.fsPath, Uri.parse(path.join('$(NETCoreTargetsPath)', 'SystemDacpacs', '150', constants.masterDacpac)).fsPath); should.equal(ssdtUri.fsPath, Uri.parse(path.join('$(DacPacRootPath)', 'Extensions', 'Microsoft', 'SQLDB', 'Extensions', 'SqlServer', '150', 'SqlSchemas', constants.masterDacpac)).fsPath); - await project.changeTargetPlatform(constants.targetPlatformToVersion.get(constants.sqlServer2016)!); + await project.changeTargetPlatform(constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlServer2016)!); uri = project.getSystemDacpacUri(constants.masterDacpac); ssdtUri = project.getSystemDacpacSsdtUri(constants.masterDacpac); should.equal(uri.fsPath, Uri.parse(path.join('$(NETCoreTargetsPath)', 'SystemDacpacs', '130', constants.masterDacpac)).fsPath); should.equal(ssdtUri.fsPath, Uri.parse(path.join('$(DacPacRootPath)', 'Extensions', 'Microsoft', 'SQLDB', 'Extensions', 'SqlServer', '130', 'SqlSchemas', constants.masterDacpac)).fsPath); - await project.changeTargetPlatform(constants.targetPlatformToVersion.get(constants.sqlAzure)!); + await project.changeTargetPlatform(constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlAzure)!); uri = project.getSystemDacpacUri(constants.masterDacpac); ssdtUri = project.getSystemDacpacSsdtUri(constants.masterDacpac); should.equal(uri.fsPath, Uri.parse(path.join('$(NETCoreTargetsPath)', 'SystemDacpacs', 'AzureV12', constants.masterDacpac)).fsPath); should.equal(ssdtUri.fsPath, Uri.parse(path.join('$(DacPacRootPath)', 'Extensions', 'Microsoft', 'SQLDB', 'Extensions', 'SqlServer', 'AzureV12', 'SqlSchemas', constants.masterDacpac)).fsPath); - await project.changeTargetPlatform(constants.targetPlatformToVersion.get(constants.sqlDW)!); + await project.changeTargetPlatform(constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlDW)!); uri = project.getSystemDacpacUri(constants.masterDacpac); ssdtUri = project.getSystemDacpacSsdtUri(constants.masterDacpac); should.equal(uri.fsPath, Uri.parse(path.join('$(NETCoreTargetsPath)', 'SystemDacpacs', 'AzureDw', constants.masterDacpac)).fsPath); @@ -189,17 +190,17 @@ describe('Project: sqlproj content operations', function (): void { should(projFileText.includes(convertSlashesForSqlProj(Uri.file(path.join('$(NETCoreTargetsPath)', 'SystemDacpacs', '150', constants.masterDacpac)).fsPath.substring(1)))).be.true('System db reference path should be 150'); should(projFileText.includes(convertSlashesForSqlProj(Uri.file(path.join('$(DacPacRootPath)', 'Extensions', 'Microsoft', 'SQLDB', 'Extensions', 'SqlServer', '150', 'SqlSchemas', constants.masterDacpac)).fsPath.substring(1)))).be.true('System db SSDT reference path should be 150'); - await project.changeTargetPlatform(constants.targetPlatformToVersion.get(constants.sqlServer2016)!); + await project.changeTargetPlatform(constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlServer2016)!); projFileText = await fs.readFile(projFilePath); should(projFileText.includes(convertSlashesForSqlProj(Uri.file(path.join('$(NETCoreTargetsPath)', 'SystemDacpacs', '130', constants.masterDacpac)).fsPath.substring(1)))).be.true('System db reference path should have been updated to 130'); should(projFileText.includes(convertSlashesForSqlProj(Uri.file(path.join('$(DacPacRootPath)', 'Extensions', 'Microsoft', 'SQLDB', 'Extensions', 'SqlServer', '130', 'SqlSchemas', constants.masterDacpac)).fsPath.substring(1)))).be.true('System db SSDT reference path should be 130'); - await project.changeTargetPlatform(constants.targetPlatformToVersion.get(constants.sqlAzure)!); + await project.changeTargetPlatform(constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlAzure)!); projFileText = await fs.readFile(projFilePath); should(projFileText.includes(convertSlashesForSqlProj(Uri.file(path.join('$(NETCoreTargetsPath)', 'SystemDacpacs', 'AzureV12', constants.masterDacpac)).fsPath.substring(1)))).be.true('System db reference path should have been updated to AzureV12'); should(projFileText.includes(convertSlashesForSqlProj(Uri.file(path.join('$(DacPacRootPath)', 'Extensions', 'Microsoft', 'SQLDB', 'Extensions', 'SqlServer', 'AzureV12', 'SqlSchemas', constants.masterDacpac)).fsPath.substring(1)))).be.true('System db SSDT reference path should be AzureV12'); - await project.changeTargetPlatform(constants.targetPlatformToVersion.get(constants.sqlDW)!); + await project.changeTargetPlatform(constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlDW)!); projFileText = await fs.readFile(projFilePath); should(projFileText.includes(convertSlashesForSqlProj(Uri.file(path.join('$(NETCoreTargetsPath)', 'SystemDacpacs', 'AzureDw', constants.masterDacpac)).fsPath.substring(1)))).be.true('System db reference path should have been updated to AzureDw'); should(projFileText.includes(convertSlashesForSqlProj(Uri.file(path.join('$(DacPacRootPath)', 'Extensions', 'Microsoft', 'SQLDB', 'Extensions', 'SqlServer', 'AzureDw', 'SqlSchemas', constants.masterDacpac)).fsPath.substring(1)))).be.true('System db SSDT reference path should be AzureDw'); @@ -214,7 +215,7 @@ describe('Project: sqlproj content operations', function (): void { should.equal(uri.fsPath, Uri.parse(path.join('$(NETCoreTargetsPath)', 'SystemDacpacs', '150', constants.msdbDacpac)).fsPath); should.equal(ssdtUri.fsPath, Uri.parse(path.join('$(DacPacRootPath)', 'Extensions', 'Microsoft', 'SQLDB', 'Extensions', 'SqlServer', '150', 'SqlSchemas', constants.msdbDacpac)).fsPath); - await project.changeTargetPlatform(constants.targetPlatformToVersion.get(constants.sqlServer2016)!); + await project.changeTargetPlatform(constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlServer2016)!); uri = project.getSystemDacpacUri(constants.msdbDacpac); ssdtUri = project.getSystemDacpacSsdtUri(constants.msdbDacpac); should.equal(uri.fsPath, Uri.parse(path.join('$(NETCoreTargetsPath)', 'SystemDacpacs', '130', constants.msdbDacpac)).fsPath); diff --git a/extensions/sql-database-projects/src/test/projectController.test.ts b/extensions/sql-database-projects/src/test/projectController.test.ts index 2ea4f93d33..7628f773ff 100644 --- a/extensions/sql-database-projects/src/test/projectController.test.ts +++ b/extensions/sql-database-projects/src/test/projectController.test.ts @@ -31,6 +31,7 @@ import { AddDatabaseReferenceDialog } from '../dialogs/addDatabaseReferenceDialo import { IDacpacReferenceSettings } from '../models/IDatabaseReferenceSettings'; import { CreateProjectFromDatabaseDialog } from '../dialogs/createProjectFromDatabaseDialog'; import { ImportDataModel } from '../models/api/import'; +import { SqlTargetPlatform } from 'sqldbproj'; let testContext: TestContext; @@ -66,6 +67,25 @@ describe('ProjectsController', function (): void { should(projFileText).equal(baselines.newProjectFileBaseline); }); + it('Should create new sqlproj file with correct specified target platform', async function (): Promise { + const projController = new ProjectsController(); + const projFileDir = path.join(os.tmpdir(), `TestProject_${new Date().getTime()}`); + const projTargetPlatform = SqlTargetPlatform.sqlAzure; // default is SQL Server 2019 + + const projFilePath = await projController.createNewProject({ + newProjName: 'TestProjectName', + folderUri: vscode.Uri.file(projFileDir), + projectTypeId: constants.emptySqlDatabaseProjectTypeId, + projectGuid: 'BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575', + targetPlatform: projTargetPlatform + }); + + const project = await Project.openProject(projFilePath); + const projTargetVersion = project.getProjectTargetVersion(); + should(constants.getTargetPlatformFromVersion(projTargetVersion)).equal(projTargetPlatform); + }); + + it('Should return silently when no SQL object name provided in prompts', async function (): Promise { for (const name of ['', ' ', undefined]) { const showInputBoxStub = sinon.stub(vscode.window, 'showInputBox').resolves(name); @@ -316,21 +336,21 @@ describe('ProjectsController', function (): void { }); it('Should change target platform', async function (): Promise { - sinon.stub(vscode.window, 'showQuickPick').resolves({ label: constants.sqlAzure }); + sinon.stub(vscode.window, 'showQuickPick').resolves({ label: SqlTargetPlatform.sqlAzure }); const projController = new ProjectsController(); const sqlProjPath = await testUtils.createTestSqlProjFile(baselines.openProjectFileBaseline); const project = await Project.openProject(sqlProjPath); - should(project.getProjectTargetVersion()).equal(constants.targetPlatformToVersion.get(constants.sqlServer2019)); + should(project.getProjectTargetVersion()).equal(constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlServer2019)); should(project.databaseReferences.length).equal(1, 'Project should have one database reference to master'); - should(project.databaseReferences[0].fsUri.fsPath).containEql(constants.targetPlatformToVersion.get(constants.sqlServer2019)); - should((project.databaseReferences[0]).ssdtUri.fsPath).containEql(constants.targetPlatformToVersion.get(constants.sqlServer2019)); + should(project.databaseReferences[0].fsUri.fsPath).containEql(constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlServer2019)); + should((project.databaseReferences[0]).ssdtUri.fsPath).containEql(constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlServer2019)); await projController.changeTargetPlatform(project); - should(project.getProjectTargetVersion()).equal(constants.targetPlatformToVersion.get(constants.sqlAzure)); + should(project.getProjectTargetVersion()).equal(constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlAzure)); // verify system db reference got updated too - should(project.databaseReferences[0].fsUri.fsPath).containEql(constants.targetPlatformToVersion.get(constants.sqlAzure)); - should((project.databaseReferences[0]).ssdtUri.fsPath).containEql(constants.targetPlatformToVersion.get(constants.sqlAzure)); + should(project.databaseReferences[0].fsUri.fsPath).containEql(constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlAzure)); + should((project.databaseReferences[0]).ssdtUri.fsPath).containEql(constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlAzure)); }); });