diff --git a/extensions/sql-database-projects/images/sqlEdgeProject.svg b/extensions/sql-database-projects/images/sqlEdgeProject.svg
new file mode 100644
index 0000000000..19bc948f03
--- /dev/null
+++ b/extensions/sql-database-projects/images/sqlEdgeProject.svg
@@ -0,0 +1,47 @@
+
diff --git a/extensions/sql-database-projects/resources/templates/newTsqlDataSourceTemplate.sql b/extensions/sql-database-projects/resources/templates/newTsqlDataSourceTemplate.sql
new file mode 100644
index 0000000000..b40c679cea
--- /dev/null
+++ b/extensions/sql-database-projects/resources/templates/newTsqlDataSourceTemplate.sql
@@ -0,0 +1,4 @@
+CREATE EXTERNAL DATA SOURCE [@@OBJECT_NAME@@] WITH
+(
+ LOCATION = '@@LOCATION@@'
+)
diff --git a/extensions/sql-database-projects/resources/templates/newTsqlExternalStreamTemplate.sql b/extensions/sql-database-projects/resources/templates/newTsqlExternalStreamTemplate.sql
new file mode 100644
index 0000000000..94f0d2a011
--- /dev/null
+++ b/extensions/sql-database-projects/resources/templates/newTsqlExternalStreamTemplate.sql
@@ -0,0 +1,5 @@
+CREATE EXTERNAL STREAM [@@OBJECT_NAME@@] WITH
+(
+ DATA_SOURCE = [@@DATA_SOURCE_NAME@@],
+ LOCATION = N'@@LOCATION@@'@@OPTIONS@@
+)
diff --git a/extensions/sql-database-projects/resources/templates/newTsqlExternalStreamingJobTemplate.sql b/extensions/sql-database-projects/resources/templates/newTsqlExternalStreamingJobTemplate.sql
index 015ea4ae67..476425ad7b 100644
--- a/extensions/sql-database-projects/resources/templates/newTsqlExternalStreamingJobTemplate.sql
+++ b/extensions/sql-database-projects/resources/templates/newTsqlExternalStreamingJobTemplate.sql
@@ -5,6 +5,5 @@
EXEC sys.sp_create_streaming_job @NAME = '@@OBJECT_NAME@@', @STATEMENT = 'INSERT INTO SqlOutputStream SELECT
timeCreated,
- streamColumn1 as column1,
- streamColumn2 as column2
+ streamColumn1 as Id
FROM EdgeHubInputStream'
diff --git a/extensions/sql-database-projects/resources/templates/newTsqlFileFormatTemplate.sql b/extensions/sql-database-projects/resources/templates/newTsqlFileFormatTemplate.sql
new file mode 100644
index 0000000000..c1418c4af1
--- /dev/null
+++ b/extensions/sql-database-projects/resources/templates/newTsqlFileFormatTemplate.sql
@@ -0,0 +1,5 @@
+CREATE EXTERNAL FILE FORMAT [@@OBJECT_NAME@@] WITH
+(
+ FORMAT_TYPE = JSON,
+ DATA_COMPRESSION = 'org.apache.hadoop.io.compress.GzipCodec'
+)
diff --git a/extensions/sql-database-projects/src/common/constants.ts b/extensions/sql-database-projects/src/common/constants.ts
index abfc0f82d5..832b6111dd 100644
--- a/extensions/sql-database-projects/src/common/constants.ts
+++ b/extensions/sql-database-projects/src/common/constants.ts
@@ -23,9 +23,13 @@ export const MicrosoftDatatoolsSchemaSqlSql = 'Microsoft.Data.Tools.Schema.Sql.S
export const databaseSchemaProvider = 'DatabaseSchemaProvider';
// Project Provider
-export const sqlDatabaseProjectTypeId = 'sqldbproj';
-export const projectTypeDisplayName = localize('projectTypeDisplayName', "SQL Database");
-export const projectTypeDescription = localize('projectTypeDescription', "Design, edit, and publish schemas for SQL databases");
+export const emptySqlDatabaseProjectTypeId = 'EmptySqlDbProj';
+export const emptyProjectTypeDisplayName = localize('emptyProjectTypeDisplayName', "SQL Database");
+export const emptyProjectTypeDescription = localize('emptyProjectTypeDescription', "Develop and publish schemas for SQL databases starting from an empty project");
+
+export const edgeSqlDatabaseProjectTypeId = 'SqlDbEdgeProj';
+export const edgeProjectTypeDisplayName = localize('edgeProjectTypeDisplayName', "SQL Edge");
+export const edgeProjectTypeDescription = localize('edgeProjectTypeDescription', "Start with the core pieces to develop and publish schemas for SQL Edge");
// commands
export const revealFileInOsCommand = 'revealFileInOS';
@@ -196,6 +200,9 @@ export const scriptFriendlyName = localize('scriptFriendlyName', "Script");
export const tableFriendlyName = localize('tableFriendlyName', "Table");
export const viewFriendlyName = localize('viewFriendlyName', "View");
export const storedProcedureFriendlyName = localize('storedProcedureFriendlyName', "Stored Procedure");
+export const dataSourceFriendlyName = localize('dataSource', "Data Source");
+export const fileFormatFriendlyName = localize('fileFormat', "File Format");
+export const externalStreamFriendlyName = localize('externalStream', "External Stream");
export const externalStreamingJobFriendlyName = localize('externalStreamingJobFriendlyName', "External Streaming Job");
export const preDeployScriptFriendlyName = localize('preDeployScriptFriendlyName', "Script.PreDeployment");
export const postDeployScriptFriendlyName = localize('postDeployScriptFriendlyName', "Script.PostDeployment");
diff --git a/extensions/sql-database-projects/src/common/iconHelper.ts b/extensions/sql-database-projects/src/common/iconHelper.ts
index e048477661..5467b1f2d4 100644
--- a/extensions/sql-database-projects/src/common/iconHelper.ts
+++ b/extensions/sql-database-projects/src/common/iconHelper.ts
@@ -14,6 +14,7 @@ export class IconPathHelper {
private static extensionContext: vscode.ExtensionContext;
public static databaseProject: IconPath;
public static colorfulSqlProject: IconPath;
+ public static sqlEdgeProject: IconPath;
public static dataSourceGroup: IconPath;
public static dataSourceSql: IconPath;
@@ -33,6 +34,7 @@ export class IconPathHelper {
IconPathHelper.databaseProject = IconPathHelper.makeIcon('databaseProject');
IconPathHelper.colorfulSqlProject = IconPathHelper.makeIcon('colorfulSqlProject', true);
+ IconPathHelper.sqlEdgeProject = IconPathHelper.makeIcon('sqlEdgeProject', true);
IconPathHelper.dataSourceGroup = IconPathHelper.makeIcon('dataSourceGroup');
IconPathHelper.dataSourceSql = IconPathHelper.makeIcon('dataSource-sql');
diff --git a/extensions/sql-database-projects/src/controllers/projectController.ts b/extensions/sql-database-projects/src/controllers/projectController.ts
index 9982cd79e2..8d8c324acf 100644
--- a/extensions/sql-database-projects/src/controllers/projectController.ts
+++ b/extensions/sql-database-projects/src/controllers/projectController.ts
@@ -56,40 +56,35 @@ export class ProjectsController {
* @param folderUri
* @param projectGuid
*/
- public async createNewProject(newProjName: string, folderUri: vscode.Uri, makeOwnFolder: boolean, projectGuid?: string): Promise {
- if (projectGuid && !UUID.isUUID(projectGuid)) {
- throw new Error(`Specified GUID is invalid: '${projectGuid}'`);
+ public async createNewProject(creationParams: NewProjectParams): Promise {
+ if (creationParams.projectGuid && !UUID.isUUID(creationParams.projectGuid)) {
+ throw new Error(`Specified GUID is invalid: '${creationParams.projectGuid}'`);
}
const macroDict: Record = {
- 'PROJECT_NAME': newProjName,
- 'PROJECT_GUID': projectGuid ?? UUID.generateUuid().toUpperCase()
+ 'PROJECT_NAME': creationParams.newProjName,
+ 'PROJECT_GUID': creationParams.projectGuid ?? UUID.generateUuid().toUpperCase()
};
- let newProjFileContents = this.macroExpansion(templates.newSqlProjectTemplate, macroDict);
+ let newProjFileContents = templates.macroExpansion(templates.newSqlProjectTemplate, macroDict);
- let newProjFileName = newProjName;
+ let newProjFileName = creationParams.newProjName;
if (!newProjFileName.toLowerCase().endsWith(constants.sqlprojExtension)) {
newProjFileName += constants.sqlprojExtension;
}
- const newProjFilePath = makeOwnFolder ? path.join(folderUri.fsPath, path.parse(newProjFileName).name, newProjFileName) : path.join(folderUri.fsPath, newProjFileName);
+ const newProjFilePath = path.join(creationParams.folderUri.fsPath, path.parse(newProjFileName).name, newProjFileName);
- let fileExists = false;
- try {
- await fs.access(newProjFilePath);
- fileExists = true;
- }
- catch { } // file doesn't already exist
-
- if (fileExists) {
+ if (await utils.exists(newProjFilePath)) {
throw new Error(constants.projectAlreadyExists(newProjFileName, path.parse(newProjFilePath).dir));
}
await fs.mkdir(path.dirname(newProjFilePath), { recursive: true });
await fs.writeFile(newProjFilePath, newProjFileContents);
+ await this.addTemplateFiles(newProjFilePath, creationParams.projectTypeId);
+
return newProjFilePath;
}
@@ -256,7 +251,7 @@ export class ProjectsController {
}
}
- const itemType = templates.projectScriptTypeMap()[itemTypeName.toLocaleLowerCase()];
+ const itemType = templates.get(itemTypeName);
const absolutePathToParent = path.join(project.projectFolderPath, relativePath);
let itemObjectName = await this.promptForNewObjectName(itemType, project, absolutePathToParent, constants.sqlFileExtension);
@@ -266,18 +261,10 @@ export class ProjectsController {
return; // user cancelled
}
- const newFileText = this.macroExpansion(itemType.templateScript, { 'OBJECT_NAME': itemObjectName });
+ const newFileText = templates.macroExpansion(itemType.templateScript, { 'OBJECT_NAME': itemObjectName });
const relativeFilePath = path.join(relativePath, itemObjectName + constants.sqlFileExtension);
try {
- // check if file already exists
- const absoluteFilePath = path.join(project.projectFolderPath, relativeFilePath);
- const fileExists = await utils.exists(absoluteFilePath);
-
- if (fileExists) {
- throw new Error(constants.fileAlreadyExists(path.parse(absoluteFilePath).name));
- }
-
const newEntry = await project.addScriptItem(relativeFilePath, newFileText, itemType.type);
await vscode.commands.executeCommand(constants.vscodeOpenCommand, newEntry.fsUri);
@@ -460,6 +447,12 @@ export class ProjectsController {
return addDatabaseReferenceDialog;
}
+ /**
+ * Adds a database reference to a project, after selections have been made in the dialog
+ * @param project project to which to add the database reference
+ * @param settings settings for the database reference
+ * @param context a treeItem in a project's hierarchy, to be used to obtain a Project
+ */
public async addDatabaseReferenceCallback(project: Project, settings: ISystemDatabaseReferenceSettings | IDacpacReferenceSettings | IProjectReferenceSettings, context: dataworkspace.WorkspaceTreeItem): Promise {
try {
if ((settings).projectName !== undefined) {
@@ -494,6 +487,11 @@ export class ProjectsController {
}
}
+ /**
+ * Validates the contents of an external streaming job's query against the last-built dacpac.
+ * If no dacpac exists at the output path, one will be built first.
+ * @param node a treeItem in a project's hierarchy, to be used to obtain a Project
+ */
public async validateExternalStreamingJob(node: dataworkspace.WorkspaceTreeItem): Promise {
const project: Project = this.getProjectFromContext(node);
@@ -547,6 +545,29 @@ export class ProjectsController {
}
}
+ private async addTemplateFiles(newProjFilePath: string, projectTypeId: string): Promise {
+ if (projectTypeId === constants.emptySqlDatabaseProjectTypeId || newProjFilePath === '') {
+ return;
+ }
+
+ if (projectTypeId === constants.edgeSqlDatabaseProjectTypeId) {
+ const project = await Project.openProject(newProjFilePath);
+
+ await this.createFileFromTemplate(project, templates.get(templates.table), 'DataTable.sql', { 'OBJECT_NAME': 'DataTable' });
+ await this.createFileFromTemplate(project, templates.get(templates.dataSource), 'EdgeHubInputDataSource.sql', { 'OBJECT_NAME': 'EdgeHubInputDataSource', 'LOCATION': 'edgehub://' });
+ await this.createFileFromTemplate(project, templates.get(templates.dataSource), 'SqlOutputDataSource.sql', { 'OBJECT_NAME': 'SqlOutputDataSource', 'LOCATION': 'sqlserver://tcp:.,1433' });
+ await this.createFileFromTemplate(project, templates.get(templates.fileFormat), 'StreamFileFormat.sql', { 'OBJECT_NAME': 'StreamFileFormat' });
+ await this.createFileFromTemplate(project, templates.get(templates.externalStream), 'EdgeHubInputStream.sql', { 'OBJECT_NAME': 'EdgeHubInputStream', 'DATA_SOURCE_NAME': 'EdgeHubInputDataSource', 'LOCATION': 'input', 'OPTIONS': ',\n\tFILE_FORMAT = StreamFileFormat' });
+ await this.createFileFromTemplate(project, templates.get(templates.externalStream), 'SqlOutputStream.sql', { 'OBJECT_NAME': 'SqlOutputStream', 'DATA_SOURCE_NAME': 'SqlOutputDataSource', 'LOCATION': 'TSQLStreaming.dbo.DataTable', 'OPTIONS': '' });
+ await this.createFileFromTemplate(project, templates.get(templates.externalStreamingJob), 'EdgeStreamingJob.sql', { 'OBJECT_NAME': 'EdgeStreamingJob' });
+ }
+ }
+
+ private async createFileFromTemplate(project: Project, itemType: templates.ProjectScriptType, relativePath: string, expansionMacros: Record): Promise {
+ const newFileText = templates.macroExpansion(itemType.templateScript, expansionMacros);
+ await project.addScriptItem(relativePath, newFileText, itemType.type);
+ }
+
private getProjectFromContext(context: Project | BaseProjectTreeItem | dataworkspace.WorkspaceTreeItem): Project {
if ('element' in context) {
return context.element.root.project;
@@ -570,21 +591,7 @@ export class ProjectsController {
return (ext.exports as mssql.IExtension).dacFx;
}
- private macroExpansion(template: string, macroDict: Record): string {
- const macroIndicator = '@@';
- let output = template;
- for (const macro in macroDict) {
- // check if value contains the macroIndicator, which could break expansion for successive macros
- if (macroDict[macro].includes(macroIndicator)) {
- throw new Error(`Macro value ${macroDict[macro]} is invalid because it contains ${macroIndicator}`);
- }
-
- output = output.replace(new RegExp(macroIndicator + macro + macroIndicator, 'g'), macroDict[macro]);
- }
-
- return output;
- }
private async promptForNewObjectName(itemType: templates.ProjectScriptType, _project: Project, folderPath: string, fileExtension?: string): Promise {
const suggestedName = itemType.friendlyName.replace(/\s+/g, '');
@@ -632,7 +639,12 @@ export class ProjectsController {
const newProjFolderUri = model.filePath;
- const newProjFilePath = await this.createNewProject(model.projName, vscode.Uri.file(newProjFolderUri), true);
+ const newProjFilePath = await this.createNewProject({
+ newProjName: model.projName,
+ folderUri: vscode.Uri.file(newProjFolderUri),
+ projectTypeId: constants.emptySqlDatabaseProjectTypeId
+ });
+
model.filePath = path.dirname(newProjFilePath);
this.setFilePath(model);
@@ -718,3 +730,10 @@ export class ProjectsController {
//#endregion
}
+
+export interface NewProjectParams {
+ newProjName: string;
+ folderUri: vscode.Uri;
+ projectTypeId: string;
+ projectGuid?: string;
+}
diff --git a/extensions/sql-database-projects/src/models/project.ts b/extensions/sql-database-projects/src/models/project.ts
index a5718c8130..47354ad741 100644
--- a/extensions/sql-database-projects/src/models/project.ts
+++ b/extensions/sql-database-projects/src/models/project.ts
@@ -282,19 +282,26 @@ export class Project {
* @param contents Contents to be written to the new file
*/
public async addScriptItem(relativeFilePath: string, contents?: string, itemType?: string): Promise {
+ // check if file already exists
const absoluteFilePath = path.join(this.projectFolderPath, relativeFilePath);
+ if (contents !== undefined && contents !== '' && await utils.exists(absoluteFilePath)) {
+ throw new Error(constants.fileAlreadyExists(path.parse(absoluteFilePath).name));
+ }
+
+ // create the file
if (contents) {
await fs.mkdir(path.dirname(absoluteFilePath), { recursive: true });
await fs.writeFile(absoluteFilePath, contents);
}
- //Check that file actually exists
+ // check that file was successfully created
let exists = await utils.exists(absoluteFilePath);
if (!exists) {
throw new Error(constants.noFileExist(absoluteFilePath));
}
+ // update sqlproj XML
const fileEntry = this.createFileProjectEntry(relativeFilePath, EntryType.File);
let xmlTag;
diff --git a/extensions/sql-database-projects/src/projectProvider/projectProvider.ts b/extensions/sql-database-projects/src/projectProvider/projectProvider.ts
index 0b753d0f66..54883ef580 100644
--- a/extensions/sql-database-projects/src/projectProvider/projectProvider.ts
+++ b/extensions/sql-database-projects/src/projectProvider/projectProvider.ts
@@ -5,7 +5,7 @@
import * as dataworkspace from 'dataworkspace';
import * as vscode from 'vscode';
-import { sqlprojExtension, projectTypeDisplayName, projectTypeDescription, sqlDatabaseProjectTypeId } from '../common/constants';
+import * as constants from '../common/constants';
import { IconPathHelper } from '../common/iconHelper';
import { SqlDatabaseProjectTreeViewProvider } from '../controllers/databaseProjectTreeViewProvider';
import { ProjectsController } from '../controllers/projectController';
@@ -44,11 +44,18 @@ export class SqlDatabaseProjectProvider implements dataworkspace.IProjectProvide
*/
get supportedProjectTypes(): dataworkspace.IProjectType[] {
return [{
- id: sqlDatabaseProjectTypeId,
- projectFileExtension: sqlprojExtension.replace(/\./g, ''),
- displayName: projectTypeDisplayName,
- description: projectTypeDescription,
+ id: constants.emptySqlDatabaseProjectTypeId,
+ projectFileExtension: constants.sqlprojExtension.replace(/\./g, ''),
+ displayName: constants.emptyProjectTypeDisplayName,
+ description: constants.emptyProjectTypeDescription,
icon: IconPathHelper.colorfulSqlProject
+ },
+ {
+ id: constants.edgeSqlDatabaseProjectTypeId,
+ projectFileExtension: constants.sqlprojExtension.replace(/\./g, ''),
+ displayName: constants.edgeProjectTypeDisplayName,
+ description: constants.edgeProjectTypeDescription,
+ icon: IconPathHelper.sqlEdgeProject
}];
}
@@ -56,10 +63,16 @@ export class SqlDatabaseProjectProvider implements dataworkspace.IProjectProvide
* Create a project
* @param name name of the project
* @param location the parent directory
+ * @param projectTypeId the ID of the project/template
* @returns Uri of the newly created project file
*/
- async createProject(name: string, location: vscode.Uri, _: string): Promise {
- const projectFile = await this.projectController.createNewProject(name, location, true);
+ async createProject(name: string, location: vscode.Uri, projectTypeId: string): Promise {
+ const projectFile = await this.projectController.createNewProject({
+ newProjName: name,
+ folderUri: location,
+ projectTypeId: projectTypeId
+ });
+
return vscode.Uri.file(projectFile);
}
}
diff --git a/extensions/sql-database-projects/src/templates/templates.ts b/extensions/sql-database-projects/src/templates/templates.ts
index 2427083bbd..d83068d488 100644
--- a/extensions/sql-database-projects/src/templates/templates.ts
+++ b/extensions/sql-database-projects/src/templates/templates.ts
@@ -15,6 +15,9 @@ export const script: string = 'script';
export const table: string = 'table';
export const view: string = 'view';
export const storedProcedure: string = 'storedProcedure';
+export const dataSource: string = 'dataSource';
+export const fileFormat: string = 'fileFormat';
+export const externalStream: string = 'externalStream';
export const externalStreamingJob: string = 'externalStreamingJob';
export const folder: string = 'folder';
@@ -25,12 +28,12 @@ export const postDeployScript: string = 'postDeployScript';
let scriptTypeMap: Record = {};
-export function projectScriptTypeMap(): Record {
+export function get(key: string): ProjectScriptType {
if (Object.keys(scriptTypeMap).length === 0) {
throw new Error('Templates must be loaded from file before attempting to use.');
}
- return scriptTypeMap;
+ return scriptTypeMap[key.toLocaleLowerCase()];
}
let scriptTypes: ProjectScriptType[] = [];
@@ -44,6 +47,8 @@ export function projectScriptTypes(): ProjectScriptType[] {
}
export async function loadTemplates(templateFolderPath: string) {
+ reset();
+
await Promise.all([
Promise.resolve(newSqlProjectTemplate = await loadTemplate(templateFolderPath, 'newSqlProjectTemplate.xml')),
loadObjectTypeInfo(script, constants.scriptFriendlyName, templateFolderPath, 'newTsqlScriptTemplate.sql'),
@@ -52,11 +57,14 @@ export async function loadTemplates(templateFolderPath: string) {
loadObjectTypeInfo(storedProcedure, constants.storedProcedureFriendlyName, templateFolderPath, 'newTsqlStoredProcedureTemplate.sql'),
loadObjectTypeInfo(preDeployScript, constants.preDeployScriptFriendlyName, templateFolderPath, 'newTsqlPreDeployScriptTemplate.sql'),
loadObjectTypeInfo(postDeployScript, constants.postDeployScriptFriendlyName, templateFolderPath, 'newTsqlPostDeployScriptTemplate.sql'),
+ loadObjectTypeInfo(dataSource, constants.dataSourceFriendlyName, templateFolderPath, 'newTsqlDataSourceTemplate.sql'),
+ loadObjectTypeInfo(fileFormat, constants.fileFormatFriendlyName, templateFolderPath, 'newTsqlFileFormatTemplate.sql'),
+ loadObjectTypeInfo(externalStream, constants.externalStreamFriendlyName, templateFolderPath, 'newTsqlExternalStreamTemplate.sql'),
loadObjectTypeInfo(externalStreamingJob, constants.externalStreamingJobFriendlyName, templateFolderPath, 'newTsqlExternalStreamingJobTemplate.sql')
]);
for (const scriptType of scriptTypes) {
- if (Object.keys(projectScriptTypeMap).find(s => s === scriptType.type.toLocaleLowerCase() || s === scriptType.friendlyName.toLocaleLowerCase())) {
+ if (Object.keys(scriptTypeMap).find(s => s === scriptType.type.toLocaleLowerCase() || s === scriptType.friendlyName.toLocaleLowerCase())) {
throw new Error(`Script type map already contains ${scriptType.type} or its friendlyName.`);
}
@@ -65,9 +73,27 @@ export async function loadTemplates(templateFolderPath: string) {
}
}
-async function loadObjectTypeInfo(key: string, friendlyName: string, templateFolderPath: string, fileName: string) {
+export function macroExpansion(template: string, macroDict: Record): string {
+ const macroIndicator = '@@';
+ let output = template;
+
+ for (const macro in macroDict) {
+ // check if value contains the macroIndicator, which could break expansion for successive macros
+ if (macroDict[macro].includes(macroIndicator)) {
+ throw new Error(`Macro value ${macroDict[macro]} is invalid because it contains ${macroIndicator}`);
+ }
+
+ output = output.replace(new RegExp(macroIndicator + macro + macroIndicator, 'g'), macroDict[macro]);
+ }
+
+ return output;
+}
+
+async function loadObjectTypeInfo(key: string, friendlyName: string, templateFolderPath: string, fileName: string): Promise {
const template = await loadTemplate(templateFolderPath, fileName);
scriptTypes.push(new ProjectScriptType(key, friendlyName, template));
+
+ return key;
}
async function loadTemplate(templateFolderPath: string, fileName: string): Promise {
diff --git a/extensions/sql-database-projects/src/test/dialogs/publishDatabaseDialog.test.ts b/extensions/sql-database-projects/src/test/dialogs/publishDatabaseDialog.test.ts
index fa24f04a77..92539b62eb 100644
--- a/extensions/sql-database-projects/src/test/dialogs/publishDatabaseDialog.test.ts
+++ b/extensions/sql-database-projects/src/test/dialogs/publishDatabaseDialog.test.ts
@@ -16,6 +16,7 @@ import { PublishDatabaseDialog } from '../../dialogs/publishDatabaseDialog';
import { Project } from '../../models/project';
import { ProjectsController } from '../../controllers/projectController';
import { IPublishSettings, IGenerateScriptSettings } from '../../models/IPublishSettings';
+import { emptySqlDatabaseProjectTypeId } from '../../common/constants';
describe.skip('Publish Database Dialog', () => {
before(async function (): Promise {
@@ -27,7 +28,13 @@ describe.skip('Publish Database Dialog', () => {
const projController = new ProjectsController();
const projFileDir = path.join(os.tmpdir(), `TestProject_${new Date().getTime()}`);
- const projFilePath = await projController.createNewProject('TestProjectName', vscode.Uri.file(projFileDir), true, 'BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575');
+ const projFilePath = await projController.createNewProject({
+ newProjName: 'TestProjectName',
+ folderUri: vscode.Uri.file(projFileDir),
+ projectTypeId: emptySqlDatabaseProjectTypeId,
+ projectGuid: 'BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575'
+ });
+
const project = new Project(projFilePath);
const publishDatabaseDialog = new PublishDatabaseDialog(project);
publishDatabaseDialog.openDialog();
@@ -39,7 +46,13 @@ describe.skip('Publish Database Dialog', () => {
const projFolder = `TestProject_${new Date().getTime()}`;
const projFileDir = path.join(os.tmpdir(), projFolder);
- const projFilePath = await projController.createNewProject('TestProjectName', vscode.Uri.file(projFileDir), true, 'BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575');
+ const projFilePath = await projController.createNewProject({
+ newProjName: 'TestProjectName',
+ folderUri: vscode.Uri.file(projFileDir),
+ projectTypeId: emptySqlDatabaseProjectTypeId,
+ projectGuid: 'BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575'
+ });
+
const project = new Project(projFilePath);
const publishDatabaseDialog = new PublishDatabaseDialog(project);
@@ -55,7 +68,7 @@ describe.skip('Publish Database Dialog', () => {
let profile: IPublishSettings | IGenerateScriptSettings | undefined;
- const expectedPublish: IPublishSettings = {
+ const expectedPublish: IPublishSettings = {
databaseName: 'MockDatabaseName',
connectionUri: 'Mock|Connection|Uri',
upgradeExisting: true,
diff --git a/extensions/sql-database-projects/src/test/projectController.test.ts b/extensions/sql-database-projects/src/test/projectController.test.ts
index 787458b62f..f04ded635c 100644
--- a/extensions/sql-database-projects/src/test/projectController.test.ts
+++ b/extensions/sql-database-projects/src/test/projectController.test.ts
@@ -54,7 +54,12 @@ describe('ProjectsController', function (): void {
const projController = new ProjectsController();
const projFileDir = path.join(os.tmpdir(), `TestProject_${new Date().getTime()}`);
- const projFilePath = await projController.createNewProject('TestProjectName', vscode.Uri.file(projFileDir), false, 'BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575');
+ const projFilePath = await projController.createNewProject({
+ newProjName: 'TestProjectName',
+ folderUri: vscode.Uri.file(projFileDir),
+ projectTypeId: constants.emptySqlDatabaseProjectTypeId,
+ projectGuid: 'BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575'
+ });
let projFileText = (await fs.readFile(projFilePath)).toString();
@@ -152,6 +157,7 @@ describe('ProjectsController', function (): void {
it('Should delete nested ProjectEntry from node', async function (): Promise {
let proj = await testUtils.createTestProject(templates.newSqlProjectTemplate);
+
const setupResult = await setupDeleteExcludeTest(proj);
const scriptEntry = setupResult[0], projTreeRoot = setupResult[1], preDeployEntry = setupResult[2], postDeployEntry = setupResult[3], noneEntry = setupResult[4];
@@ -436,7 +442,15 @@ describe('ProjectsController', function (): void {
const createProjectFromDatabaseDialog = TypeMoq.Mock.ofType(CreateProjectFromDatabaseDialog, undefined, undefined, undefined);
createProjectFromDatabaseDialog.callBase = true;
createProjectFromDatabaseDialog.setup(x => x.handleCreateButtonClick()).returns(async () => {
- await projController.object.createProjectFromDatabaseCallback( { serverId: 'My Id', database: 'My Database', projName: 'testProject', filePath: 'testLocation', version: '1.0.0.0', extractTarget: mssql.ExtractTarget['schemaObjectType'] });
+ await projController.object.createProjectFromDatabaseCallback({
+ serverId: 'My Id',
+ database: 'My Database',
+ projName: 'testProject',
+ filePath: 'testLocation',
+ version: '1.0.0.0',
+ extractTarget: mssql.ExtractTarget['schemaObjectType']
+ });
+
return Promise.resolve(undefined);
});
diff --git a/extensions/sql-database-projects/src/test/templates.test.ts b/extensions/sql-database-projects/src/test/templates.test.ts
index 9557d87aff..71f505647b 100644
--- a/extensions/sql-database-projects/src/test/templates.test.ts
+++ b/extensions/sql-database-projects/src/test/templates.test.ts
@@ -14,8 +14,8 @@ describe('Templates: loading templates from disk', function (): void {
});
it('Should throw error when attempting to use templates before loaded from file', async function (): Promise {
- await shouldThrowSpecificError(() => templates.projectScriptTypeMap(), 'Templates must be loaded from file before attempting to use.');
- await shouldThrowSpecificError(() => templates.projectScriptTypes(), 'Templates must be loaded from file before attempting to use.');
+ await shouldThrowSpecificError(() => templates.get('foobar'), 'Templates must be loaded from file before attempting to use.');
+ await shouldThrowSpecificError(() => templates.get('foobar'), 'Templates must be loaded from file before attempting to use.');
});
it('Should load all templates from files', async function (): Promise {
@@ -23,7 +23,7 @@ describe('Templates: loading templates from disk', function (): void {
// check expected counts
- const numScriptObjectTypes = 7;
+ const numScriptObjectTypes = 10;
should(templates.projectScriptTypes().length).equal(numScriptObjectTypes);
should(Object.keys(templates.projectScriptTypes()).length).equal(numScriptObjectTypes);
diff --git a/extensions/sql-database-projects/src/test/testUtils.ts b/extensions/sql-database-projects/src/test/testUtils.ts
index bdc0f5d348..31cc943191 100644
--- a/extensions/sql-database-projects/src/test/testUtils.ts
+++ b/extensions/sql-database-projects/src/test/testUtils.ts
@@ -28,6 +28,7 @@ export async function shouldThrowSpecificError(block: Function, expectedMessage:
}
export async function createTestSqlProjFile(contents: string, folderPath?: string): Promise {
+ folderPath = folderPath ?? path.join(await generateTestFolderPath(), 'TestProject');
return await createTestFile(contents, 'TestProject.sqlproj', folderPath);
}
@@ -40,7 +41,7 @@ export async function createTestDataSources(contents: string, folderPath?: strin
}
export async function generateTestFolderPath(): Promise {
- const folderPath = path.join(os.tmpdir(), `TestProject_${new Date().getTime()}`);
+ const folderPath = path.join(os.tmpdir(), `TestRun_${new Date().getTime()}`);
await fs.mkdir(folderPath, { recursive: true });
return folderPath;
@@ -55,6 +56,7 @@ export async function createTestFile(contents: string, fileName: string, folderP
return filePath;
}
+
/**
* TestFolder directory structure
* - file1.sql