mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Aligns how Import and New project flows work (#11184)
* Slight import refactor * Test updates * Adds test, sets script name for File extractType to projectName * generating correct folder list * Correctly setting serverId for Imports started from Object Explorer * Adding regression test * uncommented test check
This commit is contained in:
@@ -56,11 +56,11 @@ export class ProjectsController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const newProject = new Project(projectFile.fsPath);
|
let newProject: Project;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Read project file
|
// Read project file
|
||||||
await newProject.readProjFile();
|
newProject = await Project.openProject(projectFile.fsPath);
|
||||||
this.projects.push(newProject);
|
this.projects.push(newProject);
|
||||||
|
|
||||||
// Update for round tripping as needed
|
// Update for round tripping as needed
|
||||||
@@ -69,29 +69,29 @@ export class ProjectsController {
|
|||||||
// Read datasources.json (if present)
|
// Read datasources.json (if present)
|
||||||
const dataSourcesFilePath = path.join(path.dirname(projectFile.fsPath), constants.dataSourcesFileName);
|
const dataSourcesFilePath = path.join(path.dirname(projectFile.fsPath), constants.dataSourcesFileName);
|
||||||
|
|
||||||
newProject.dataSources = await dataSources.load(dataSourcesFilePath);
|
try {
|
||||||
}
|
newProject.dataSources = await dataSources.load(dataSourcesFilePath);
|
||||||
catch (err) {
|
|
||||||
if (err instanceof dataSources.NoDataSourcesFileError) {
|
|
||||||
// TODO: prompt to create new datasources.json; for now, swallow
|
|
||||||
}
|
}
|
||||||
else {
|
catch (err) {
|
||||||
this.projects = this.projects.filter((e) => { return e !== newProject; });
|
if (err instanceof dataSources.NoDataSourcesFileError) {
|
||||||
throw err;
|
// TODO: prompt to create new datasources.json; for now, swallow
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.refreshProjectsTree();
|
this.refreshProjectsTree();
|
||||||
await this.focusProject(newProject);
|
await this.focusProject(newProject);
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
// if the project didnt load - remove it from the list of open projects
|
// if the project didnt load - remove it from the list of open projects
|
||||||
this.projects = this.projects.filter((e) => { return e !== newProject; });
|
this.projects = this.projects.filter((e) => { return e !== newProject; });
|
||||||
|
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return newProject;
|
return newProject!;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async focusProject(project?: Project): Promise<void> {
|
public async focusProject(project?: Project): Promise<void> {
|
||||||
@@ -633,36 +633,70 @@ export class ProjectsController {
|
|||||||
* prompting the user for a name, file path location and extract target
|
* prompting the user for a name, file path location and extract target
|
||||||
*/
|
*/
|
||||||
public async importNewDatabaseProject(context: IConnectionProfile | any): Promise<void> {
|
public async importNewDatabaseProject(context: IConnectionProfile | any): Promise<void> {
|
||||||
let model = <ImportDataModel>{};
|
|
||||||
|
|
||||||
// TODO: Refactor code
|
// TODO: Refactor code
|
||||||
try {
|
try {
|
||||||
let profile = this.getConnectionProfileFromContext(context);
|
const model: ImportDataModel | undefined = await this.getModelFromContext(context);
|
||||||
//TODO: Prompt for new connection addition and get database information if context information isn't provided.
|
|
||||||
|
|
||||||
let connectionId;
|
if (!model) {
|
||||||
if (profile) {
|
return; // cancelled by user
|
||||||
model.database = profile.databaseName;
|
|
||||||
connectionId = profile.id;
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
const connection = await this.apiWrapper.openConnectionDialog();
|
|
||||||
if (!connection) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectionId = connection.connectionId;
|
model.projName = await this.getProjectName(model.database);
|
||||||
|
let newProjFolderUri = (await this.getFolderLocation()).fsPath;
|
||||||
|
model.extractTarget = await this.getExtractTarget();
|
||||||
|
model.version = '1.0.0.0';
|
||||||
|
|
||||||
// use database that was connected to
|
const newProjFilePath = await this.createNewProject(model.projName, Uri.file(newProjFolderUri), true);
|
||||||
if (connection.options['database']) {
|
|
||||||
model.database = connection.options['database'];
|
model.filePath = path.dirname(newProjFilePath);
|
||||||
}
|
|
||||||
|
if (model.extractTarget === mssql.ExtractTarget.file) {
|
||||||
|
model.filePath = path.join(model.filePath, model.projName + '.sql'); // File extractTarget specifies the exact file rather than the containing folder
|
||||||
|
}
|
||||||
|
|
||||||
|
const project = await Project.openProject(newProjFilePath);
|
||||||
|
|
||||||
|
await this.importApiCall(model); // Call ExtractAPI in DacFx Service
|
||||||
|
let fileFolderList: string[] = model.extractTarget === mssql.ExtractTarget.file ? [model.filePath] : await this.generateList(model.filePath); // Create a list of all the files and directories to be added to project
|
||||||
|
|
||||||
|
await project.addToProject(fileFolderList); // Add generated file structure to the project
|
||||||
|
await this.openProject(Uri.file(newProjFilePath));
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
this.apiWrapper.showErrorMessage(utils.getErrorMessage(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getModelFromContext(context: any): Promise<ImportDataModel | undefined> {
|
||||||
|
let model = <ImportDataModel>{};
|
||||||
|
|
||||||
|
let profile = this.getConnectionProfileFromContext(context);
|
||||||
|
let connectionId, database;
|
||||||
|
//TODO: Prompt for new connection addition and get database information if context information isn't provided.
|
||||||
|
|
||||||
|
if (profile) {
|
||||||
|
database = profile.databaseName;
|
||||||
|
connectionId = profile.id;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const connection = await this.apiWrapper.openConnectionDialog();
|
||||||
|
|
||||||
|
if (!connection) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectionId = connection.connectionId;
|
||||||
|
|
||||||
|
// use database that was connected to
|
||||||
|
if (connection.options['database']) {
|
||||||
|
database = connection.options['database'];
|
||||||
}
|
}
|
||||||
|
|
||||||
// choose database if connection was to a server or master
|
// choose database if connection was to a server or master
|
||||||
if (!model.database || model.database === constants.master) {
|
if (!model.database || model.database === constants.master) {
|
||||||
const databaseList = await this.apiWrapper.listDatabases(connectionId);
|
const databaseList = await this.apiWrapper.listDatabases(connectionId);
|
||||||
let database = (await this.apiWrapper.showQuickPick(databaseList.map(dbName => { return { label: dbName }; }),
|
database = (await this.apiWrapper.showQuickPick(databaseList.map(dbName => { return { label: dbName }; }),
|
||||||
{
|
{
|
||||||
canPickMany: false,
|
canPickMany: false,
|
||||||
placeHolder: constants.extractDatabaseSelection
|
placeHolder: constants.extractDatabaseSelection
|
||||||
@@ -671,68 +705,13 @@ export class ProjectsController {
|
|||||||
if (!database) {
|
if (!database) {
|
||||||
throw new Error(constants.databaseSelectionRequired);
|
throw new Error(constants.databaseSelectionRequired);
|
||||||
}
|
}
|
||||||
|
|
||||||
model.database = database;
|
|
||||||
model.serverId = connectionId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get project name
|
|
||||||
let newProjName = await this.getProjectName(model.database);
|
|
||||||
if (!newProjName) {
|
|
||||||
throw new Error(constants.projectNameRequired);
|
|
||||||
}
|
|
||||||
model.projName = newProjName;
|
|
||||||
|
|
||||||
// Get extractTarget
|
|
||||||
let extractTarget: mssql.ExtractTarget = await this.getExtractTarget();
|
|
||||||
model.extractTarget = extractTarget;
|
|
||||||
|
|
||||||
// Get folder location for project creation
|
|
||||||
let newProjUri = await this.getFolderLocation(model.extractTarget);
|
|
||||||
if (!newProjUri) {
|
|
||||||
throw new Error(constants.projectLocationRequired);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set project folder/file location
|
|
||||||
let newProjFolderUri;
|
|
||||||
if (extractTarget === mssql.ExtractTarget['file']) {
|
|
||||||
// Get folder info, if extractTarget = File
|
|
||||||
newProjFolderUri = Uri.file(path.dirname(newProjUri.fsPath));
|
|
||||||
} else {
|
|
||||||
newProjFolderUri = newProjUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check folder is empty
|
|
||||||
let isEmpty: boolean = await this.isDirEmpty(newProjFolderUri.fsPath);
|
|
||||||
if (!isEmpty) {
|
|
||||||
throw new Error(constants.projectLocationNotEmpty);
|
|
||||||
}
|
|
||||||
// TODO: what if the selected folder is outside the workspace?
|
|
||||||
model.filePath = newProjUri.fsPath;
|
|
||||||
|
|
||||||
//Set model version
|
|
||||||
model.version = '1.0.0.0';
|
|
||||||
|
|
||||||
// Call ExtractAPI in DacFx Service
|
|
||||||
await this.importApiCall(model);
|
|
||||||
// TODO: Check for success
|
|
||||||
|
|
||||||
// Create and open new project
|
|
||||||
const newProjFilePath = await this.createNewProject(newProjName as string, newProjFolderUri as Uri, false);
|
|
||||||
const project = await this.openProject(Uri.file(newProjFilePath));
|
|
||||||
|
|
||||||
//Create a list of all the files and directories to be added to project
|
|
||||||
let fileFolderList: string[] = await this.generateList(model.filePath);
|
|
||||||
|
|
||||||
// Add generated file structure to the project
|
|
||||||
await project.addToProject(fileFolderList);
|
|
||||||
|
|
||||||
//Refresh project to show the added files
|
|
||||||
this.refreshProjectsTree();
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
this.apiWrapper.showErrorMessage(utils.getErrorMessage(err));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model.database = database;
|
||||||
|
model.serverId = connectionId;
|
||||||
|
|
||||||
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getConnectionProfileFromContext(context: IConnectionProfile | any): IConnectionProfile | undefined {
|
private getConnectionProfileFromContext(context: IConnectionProfile | any): IConnectionProfile | undefined {
|
||||||
@@ -745,7 +724,7 @@ export class ProjectsController {
|
|||||||
return (<any>context).connectionProfile ? (<any>context).connectionProfile : context;
|
return (<any>context).connectionProfile ? (<any>context).connectionProfile : context;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getProjectName(dbName: string): Promise<string | undefined> {
|
private async getProjectName(dbName: string): Promise<string> {
|
||||||
let projName = await this.apiWrapper.showInputBox({
|
let projName = await this.apiWrapper.showInputBox({
|
||||||
prompt: constants.newDatabaseProjectName,
|
prompt: constants.newDatabaseProjectName,
|
||||||
value: `DatabaseProject${dbName}`
|
value: `DatabaseProject${dbName}`
|
||||||
@@ -753,6 +732,10 @@ export class ProjectsController {
|
|||||||
|
|
||||||
projName = projName?.trim();
|
projName = projName?.trim();
|
||||||
|
|
||||||
|
if (!projName) {
|
||||||
|
throw new Error(constants.projectNameRequired);
|
||||||
|
}
|
||||||
|
|
||||||
return projName;
|
return projName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -794,52 +777,36 @@ export class ProjectsController {
|
|||||||
return extractTarget;
|
return extractTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getFolderLocation(extractTarget: mssql.ExtractTarget): Promise<Uri | undefined> {
|
private async getFolderLocation(): Promise<Uri> {
|
||||||
let selectionResult;
|
let projUri: Uri;
|
||||||
let projUri;
|
|
||||||
|
|
||||||
if (extractTarget !== mssql.ExtractTarget.file) {
|
const selectionResult = await this.apiWrapper.showOpenDialog({
|
||||||
selectionResult = await this.apiWrapper.showOpenDialog({
|
canSelectFiles: false,
|
||||||
canSelectFiles: false,
|
canSelectFolders: true,
|
||||||
canSelectFolders: true,
|
canSelectMany: false,
|
||||||
canSelectMany: false,
|
openLabel: constants.selectString,
|
||||||
openLabel: constants.selectString,
|
defaultUri: this.apiWrapper.workspaceFolders() ? (this.apiWrapper.workspaceFolders() as WorkspaceFolder[])[0].uri : undefined
|
||||||
defaultUri: this.apiWrapper.workspaceFolders() ? (this.apiWrapper.workspaceFolders() as WorkspaceFolder[])[0].uri : undefined
|
});
|
||||||
});
|
|
||||||
if (selectionResult) {
|
if (selectionResult) {
|
||||||
projUri = (selectionResult as Uri[])[0];
|
projUri = (selectionResult as Uri[])[0];
|
||||||
}
|
}
|
||||||
} else {
|
else {
|
||||||
// Get filename
|
throw new Error(constants.projectLocationRequired);
|
||||||
selectionResult = await this.apiWrapper.showSaveDialog(
|
|
||||||
{
|
|
||||||
defaultUri: this.apiWrapper.workspaceFolders() ? (this.apiWrapper.workspaceFolders() as WorkspaceFolder[])[0].uri : undefined,
|
|
||||||
saveLabel: constants.selectString,
|
|
||||||
filters: {
|
|
||||||
'SQL files': ['sql'],
|
|
||||||
'All files': ['*']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if (selectionResult) {
|
|
||||||
projUri = selectionResult as unknown as Uri;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return projUri;
|
return projUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async isDirEmpty(newProjFolderUri: string): Promise<boolean> {
|
public async importApiCall(model: ImportDataModel): Promise<void> {
|
||||||
return (await fs.readdir(newProjFolderUri)).length === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async importApiCall(model: ImportDataModel): Promise<void> {
|
|
||||||
let ext = this.apiWrapper.getExtension(mssql.extension.name)!;
|
let ext = this.apiWrapper.getExtension(mssql.extension.name)!;
|
||||||
|
|
||||||
const service = (await ext.activate() as mssql.IExtension).dacFx;
|
const service = (await ext.activate() as mssql.IExtension).dacFx;
|
||||||
const ownerUri = await this.apiWrapper.getUriForConnection(model.serverId);
|
const ownerUri = await this.apiWrapper.getUriForConnection(model.serverId);
|
||||||
|
|
||||||
await service.importDatabaseProject(model.database, model.filePath, model.projName, model.version, ownerUri, model.extractTarget, TaskExecutionMode.execute);
|
await service.importDatabaseProject(model.database, model.filePath, model.projName, model.version, ownerUri, model.extractTarget, TaskExecutionMode.execute);
|
||||||
|
|
||||||
|
// TODO: Check for success; throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -37,6 +37,16 @@ export class Project {
|
|||||||
this.projectFileName = path.basename(projectFilePath, '.sqlproj');
|
this.projectFileName = path.basename(projectFilePath, '.sqlproj');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open and load a .sqlproj file
|
||||||
|
*/
|
||||||
|
public static async openProject(projectFilePath: string): Promise<Project> {
|
||||||
|
const proj = new Project(projectFilePath);
|
||||||
|
await proj.readProjFile();
|
||||||
|
|
||||||
|
return proj;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the project setting and contents from the file
|
* Reads the project setting and contents from the file
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -26,8 +26,7 @@ describe('Project: sqlproj content operations', function (): void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Should read Project from sqlproj', async function (): Promise<void> {
|
it('Should read Project from sqlproj', async function (): Promise<void> {
|
||||||
const project: Project = new Project(projFilePath);
|
const project: Project = await Project.openProject(projFilePath);
|
||||||
await project.readProjFile();
|
|
||||||
|
|
||||||
// Files and folders
|
// Files and folders
|
||||||
should(project.files.filter(f => f.type === EntryType.File).length).equal(4);
|
should(project.files.filter(f => f.type === EntryType.File).length).equal(4);
|
||||||
@@ -48,8 +47,7 @@ describe('Project: sqlproj content operations', function (): void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Should add Folder and Build entries to sqlproj', async function (): Promise<void> {
|
it('Should add Folder and Build entries to sqlproj', async function (): Promise<void> {
|
||||||
const project: Project = new Project(projFilePath);
|
const project = await Project.openProject(projFilePath);
|
||||||
await project.readProjFile();
|
|
||||||
|
|
||||||
const folderPath = 'Stored Procedures';
|
const folderPath = 'Stored Procedures';
|
||||||
const filePath = path.join(folderPath, 'Fake Stored Proc.sql');
|
const filePath = path.join(folderPath, 'Fake Stored Proc.sql');
|
||||||
@@ -58,8 +56,7 @@ describe('Project: sqlproj content operations', function (): void {
|
|||||||
await project.addFolderItem(folderPath);
|
await project.addFolderItem(folderPath);
|
||||||
await project.addScriptItem(filePath, fileContents);
|
await project.addScriptItem(filePath, fileContents);
|
||||||
|
|
||||||
const newProject = new Project(projFilePath);
|
const newProject = await Project.openProject(projFilePath);
|
||||||
await newProject.readProjFile();
|
|
||||||
|
|
||||||
should(newProject.files.find(f => f.type === EntryType.Folder && f.relativePath === convertSlashesForSqlProj(folderPath))).not.equal(undefined);
|
should(newProject.files.find(f => f.type === EntryType.Folder && f.relativePath === convertSlashesForSqlProj(folderPath))).not.equal(undefined);
|
||||||
should(newProject.files.find(f => f.type === EntryType.File && f.relativePath === convertSlashesForSqlProj(filePath))).not.equal(undefined);
|
should(newProject.files.find(f => f.type === EntryType.File && f.relativePath === convertSlashesForSqlProj(filePath))).not.equal(undefined);
|
||||||
@@ -71,8 +68,7 @@ describe('Project: sqlproj content operations', function (): void {
|
|||||||
|
|
||||||
it('Should add Folder and Build entries to sqlproj with pre-existing scripts on disk', async function (): Promise<void> {
|
it('Should add Folder and Build entries to sqlproj with pre-existing scripts on disk', async function (): Promise<void> {
|
||||||
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
|
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
|
||||||
const project: Project = new Project(projFilePath);
|
const project = await Project.openProject(projFilePath);
|
||||||
await project.readProjFile();
|
|
||||||
|
|
||||||
let list: string[] = await testUtils.createListOfFiles(path.dirname(projFilePath));
|
let list: string[] = await testUtils.createListOfFiles(path.dirname(projFilePath));
|
||||||
|
|
||||||
@@ -84,8 +80,7 @@ describe('Project: sqlproj content operations', function (): void {
|
|||||||
|
|
||||||
it('Should throw error while adding Folder and Build entries to sqlproj when a file/folder does not exist on disk', async function (): Promise<void> {
|
it('Should throw error while adding Folder and Build entries to sqlproj when a file/folder does not exist on disk', async function (): Promise<void> {
|
||||||
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
|
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
|
||||||
const project = new Project(projFilePath);
|
const project = await Project.openProject(projFilePath);
|
||||||
await project.readProjFile();
|
|
||||||
|
|
||||||
let list: string[] = [];
|
let list: string[] = [];
|
||||||
let testFolderPath: string = await testUtils.createDummyFileStructure(true, list, path.dirname(projFilePath));
|
let testFolderPath: string = await testUtils.createDummyFileStructure(true, list, path.dirname(projFilePath));
|
||||||
@@ -98,8 +93,7 @@ describe('Project: sqlproj content operations', function (): void {
|
|||||||
|
|
||||||
it('Should choose correct master dacpac', async function (): Promise<void> {
|
it('Should choose correct master dacpac', async function (): Promise<void> {
|
||||||
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
|
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
|
||||||
const project = new Project(projFilePath);
|
const project = await Project.openProject(projFilePath);
|
||||||
await project.readProjFile();
|
|
||||||
|
|
||||||
let uri = project.getSystemDacpacUri(constants.masterDacpac);
|
let uri = project.getSystemDacpacUri(constants.masterDacpac);
|
||||||
let ssdtUri = project.getSystemDacpacSsdtUri(constants.masterDacpac);
|
let ssdtUri = project.getSystemDacpacSsdtUri(constants.masterDacpac);
|
||||||
@@ -121,8 +115,7 @@ describe('Project: sqlproj content operations', function (): void {
|
|||||||
|
|
||||||
it('Should choose correct msdb dacpac', async function (): Promise<void> {
|
it('Should choose correct msdb dacpac', async function (): Promise<void> {
|
||||||
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
|
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
|
||||||
const project = new Project(projFilePath);
|
const project = await Project.openProject(projFilePath);
|
||||||
await project.readProjFile();
|
|
||||||
|
|
||||||
let uri = project.getSystemDacpacUri(constants.msdbDacpac);
|
let uri = project.getSystemDacpacUri(constants.msdbDacpac);
|
||||||
let ssdtUri = project.getSystemDacpacSsdtUri(constants.msdbDacpac);
|
let ssdtUri = project.getSystemDacpacSsdtUri(constants.msdbDacpac);
|
||||||
@@ -144,8 +137,7 @@ describe('Project: sqlproj content operations', function (): void {
|
|||||||
|
|
||||||
it('Should throw error when choosing correct master dacpac if invalid DSP', async function (): Promise<void> {
|
it('Should throw error when choosing correct master dacpac if invalid DSP', async function (): Promise<void> {
|
||||||
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
|
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
|
||||||
const project = new Project(projFilePath);
|
const project = await Project.openProject(projFilePath);
|
||||||
await project.readProjFile();
|
|
||||||
|
|
||||||
project.changeDSP('invalidPlatform');
|
project.changeDSP('invalidPlatform');
|
||||||
await testUtils.shouldThrowSpecificError(async () => await project.getSystemDacpacUri(constants.masterDacpac), constants.invalidDataSchemaProvider);
|
await testUtils.shouldThrowSpecificError(async () => await project.getSystemDacpacUri(constants.masterDacpac), constants.invalidDataSchemaProvider);
|
||||||
@@ -153,8 +145,7 @@ describe('Project: sqlproj content operations', function (): void {
|
|||||||
|
|
||||||
it('Should add database references correctly', async function (): Promise<void> {
|
it('Should add database references correctly', async function (): Promise<void> {
|
||||||
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
|
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
|
||||||
const project = new Project(projFilePath);
|
const project = await Project.openProject(projFilePath);
|
||||||
await project.readProjFile();
|
|
||||||
|
|
||||||
should(project.databaseReferences.length).equal(0, 'There should be no datbase references to start with');
|
should(project.databaseReferences.length).equal(0, 'There should be no datbase references to start with');
|
||||||
await project.addSystemDatabaseReference(SystemDatabase.master);
|
await project.addSystemDatabaseReference(SystemDatabase.master);
|
||||||
@@ -178,8 +169,7 @@ describe('Project: sqlproj content operations', function (): void {
|
|||||||
|
|
||||||
it('Should not allow adding duplicate database references', async function (): Promise<void> {
|
it('Should not allow adding duplicate database references', async function (): Promise<void> {
|
||||||
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
|
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
|
||||||
const project = new Project(projFilePath);
|
const project = await Project.openProject(projFilePath);
|
||||||
await project.readProjFile();
|
|
||||||
|
|
||||||
should(project.databaseReferences.length).equal(0, 'There should be no database references to start with');
|
should(project.databaseReferences.length).equal(0, 'There should be no database references to start with');
|
||||||
await project.addSystemDatabaseReference(SystemDatabase.master);
|
await project.addSystemDatabaseReference(SystemDatabase.master);
|
||||||
@@ -220,8 +210,7 @@ describe('Project: round trip updates', function (): void {
|
|||||||
|
|
||||||
async function testUpdateInRoundTrip(fileBeforeupdate: string, fileAfterUpdate: string, testTargets: boolean, testReferences: boolean): Promise<void> {
|
async function testUpdateInRoundTrip(fileBeforeupdate: string, fileAfterUpdate: string, testTargets: boolean, testReferences: boolean): Promise<void> {
|
||||||
projFilePath = await testUtils.createTestSqlProjFile(fileBeforeupdate);
|
projFilePath = await testUtils.createTestSqlProjFile(fileBeforeupdate);
|
||||||
const project: Project = new Project(projFilePath);
|
const project = await Project.openProject(projFilePath);
|
||||||
await project.readProjFile();
|
|
||||||
|
|
||||||
if (testTargets) {
|
if (testTargets) {
|
||||||
await testUpdateTargetsImportsRoundTrip(project);
|
await testUpdateTargetsImportsRoundTrip(project);
|
||||||
|
|||||||
@@ -189,8 +189,7 @@ describe('ProjectsController: project controller operations', function (): void
|
|||||||
|
|
||||||
await projController.delete(projTreeRoot.children.find(x => x.friendlyName === 'UpperFolder')!.children[0] /* LowerFolder */);
|
await projController.delete(projTreeRoot.children.find(x => x.friendlyName === 'UpperFolder')!.children[0] /* LowerFolder */);
|
||||||
|
|
||||||
proj = new Project(proj.projectFilePath);
|
proj = await Project.openProject(proj.projectFilePath); // reload edited sqlproj from disk
|
||||||
await proj.readProjFile(); // reload edited sqlproj from disk
|
|
||||||
|
|
||||||
// confirm result
|
// confirm result
|
||||||
should(proj.files.length).equal(1, 'number of file/folder entries'); // lowerEntry and the contained scripts should be deleted
|
should(proj.files.length).equal(1, 'number of file/folder entries'); // lowerEntry and the contained scripts should be deleted
|
||||||
@@ -208,8 +207,7 @@ describe('ProjectsController: project controller operations', function (): void
|
|||||||
|
|
||||||
await projController.exclude(<FolderNode>projTreeRoot.children.find(x => x.friendlyName === 'UpperFolder')!.children[0] /* LowerFolder */);
|
await projController.exclude(<FolderNode>projTreeRoot.children.find(x => x.friendlyName === 'UpperFolder')!.children[0] /* LowerFolder */);
|
||||||
|
|
||||||
proj = new Project(proj.projectFilePath);
|
proj = await Project.openProject(proj.projectFilePath); // reload edited sqlproj from disk
|
||||||
await proj.readProjFile(); // reload edited sqlproj from disk
|
|
||||||
|
|
||||||
// confirm result
|
// confirm result
|
||||||
should(proj.files.length).equal(1, 'number of file/folder entries'); // LowerFolder and the contained scripts should be deleted
|
should(proj.files.length).equal(1, 'number of file/folder entries'); // LowerFolder and the contained scripts should be deleted
|
||||||
@@ -362,6 +360,7 @@ describe('ProjectsController: import operations', function (): void {
|
|||||||
|
|
||||||
it('Should show error when no target information provided', async function (): Promise<void> {
|
it('Should show error when no target information provided', async function (): Promise<void> {
|
||||||
testContext.apiWrapper.setup(x => x.showInputBox(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('MyProjectName'));
|
testContext.apiWrapper.setup(x => x.showInputBox(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('MyProjectName'));
|
||||||
|
testContext.apiWrapper.setup(x => x.showOpenDialog(TypeMoq.It.isAny())).returns(() => Promise.resolve([vscode.Uri.file('fakePath')]));
|
||||||
testContext.apiWrapper.setup(x => x.showQuickPick(TypeMoq.It.isAny())).returns(() => Promise.resolve(undefined));
|
testContext.apiWrapper.setup(x => x.showQuickPick(TypeMoq.It.isAny())).returns(() => Promise.resolve(undefined));
|
||||||
testContext.apiWrapper.setup(x => x.showErrorMessage(TypeMoq.It.isAny())).returns((s) => { throw new Error(s); });
|
testContext.apiWrapper.setup(x => x.showErrorMessage(TypeMoq.It.isAny())).returns((s) => { throw new Error(s); });
|
||||||
|
|
||||||
@@ -390,18 +389,55 @@ describe('ProjectsController: import operations', function (): void {
|
|||||||
await testUtils.shouldThrowSpecificError(async () => await projController.importNewDatabaseProject({ connectionProfile: mockConnectionProfile }), constants.projectLocationRequired);
|
await testUtils.shouldThrowSpecificError(async () => await projController.importNewDatabaseProject({ connectionProfile: mockConnectionProfile }), constants.projectLocationRequired);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should show error when selected folder is not empty', async function (): Promise<void> {
|
it('Should set model filePath correctly for ExtractType = File and not-File.', async function (): Promise<void> {
|
||||||
const testFolderPath = await testUtils.createDummyFileStructure();
|
const projectName = 'MyProjectName';
|
||||||
|
let folderPath = await testUtils.generateTestFolderPath();
|
||||||
|
|
||||||
testContext.apiWrapper.setup(x => x.showInputBox(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('MyProjectName'));
|
testContext.apiWrapper.setup(x => x.showInputBox(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(projectName));
|
||||||
testContext.apiWrapper.setup(x => x.showQuickPick(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({ label: constants.objectType }));
|
testContext.apiWrapper.setup(x => x.showQuickPick(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({ label: constants.file }));
|
||||||
testContext.apiWrapper.setup(x => x.showOpenDialog(TypeMoq.It.isAny())).returns(() => Promise.resolve([vscode.Uri.file(testFolderPath)]));
|
testContext.apiWrapper.setup(x => x.showOpenDialog(TypeMoq.It.isAny())).returns(() => Promise.resolve([vscode.Uri.file(folderPath)]));
|
||||||
testContext.apiWrapper.setup(x => x.workspaceFolders()).returns(() => undefined);
|
|
||||||
testContext.apiWrapper.setup(x => x.showErrorMessage(TypeMoq.It.isAny())).returns((s) => { throw new Error(s); });
|
|
||||||
|
|
||||||
const projController = new ProjectsController(testContext.apiWrapper.object, new SqlDatabaseProjectTreeViewProvider());
|
let importPath;
|
||||||
|
|
||||||
await testUtils.shouldThrowSpecificError(async () => await projController.importNewDatabaseProject({ connectionProfile: mockConnectionProfile }), constants.projectLocationNotEmpty);
|
let projController = TypeMoq.Mock.ofType(ProjectsController, undefined, undefined, testContext.apiWrapper.object, new SqlDatabaseProjectTreeViewProvider());
|
||||||
|
projController.callBase = true;
|
||||||
|
|
||||||
|
projController.setup(x => x.importApiCall(TypeMoq.It.isAny())).returns(async (model) => { importPath = model.filePath; });
|
||||||
|
|
||||||
|
await projController.object.importNewDatabaseProject({ connectionProfile: mockConnectionProfile });
|
||||||
|
should(importPath).equal(vscode.Uri.file(path.join(folderPath, projectName, projectName + '.sql')).fsPath, `model.filePath should be set to a specific file for ExtractTarget === file, but was ${importPath}`);
|
||||||
|
|
||||||
|
// reset for counter-test
|
||||||
|
importPath = undefined;
|
||||||
|
folderPath = await testUtils.generateTestFolderPath();
|
||||||
|
testContext.apiWrapper.setup(x => x.showQuickPick(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({ label: constants.schemaObjectType }));
|
||||||
|
|
||||||
|
await projController.object.importNewDatabaseProject({ connectionProfile: mockConnectionProfile });
|
||||||
|
should(importPath).equal(vscode.Uri.file(path.join(folderPath, projectName)).fsPath, `model.filePath should be set to a folder for ExtractTarget !== file, but was ${importPath}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should establish Import context correctly for ObjectExplorer and palette launch points', async function (): Promise<void> {
|
||||||
|
// test welcome button and palette launch points (context-less)
|
||||||
|
let mockDbSelection = 'FakeDatabase';
|
||||||
|
|
||||||
|
testContext.apiWrapper.setup(x => x.listDatabases(TypeMoq.It.isAny())).returns(() => Promise.resolve([]));
|
||||||
|
testContext.apiWrapper.setup(x => x.showQuickPick(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({ label: mockDbSelection }));
|
||||||
|
testContext.apiWrapper.setup(x => x.openConnectionDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({
|
||||||
|
providerName: 'MSSQL',
|
||||||
|
connectionId: 'BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575',
|
||||||
|
options: {}
|
||||||
|
}));
|
||||||
|
|
||||||
|
let projController = new ProjectsController(testContext.apiWrapper.object, new SqlDatabaseProjectTreeViewProvider());
|
||||||
|
|
||||||
|
let result = await projController.getModelFromContext(undefined);
|
||||||
|
|
||||||
|
should(result).deepEqual({database: mockDbSelection, serverId: 'BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575'});
|
||||||
|
|
||||||
|
// test launch via Object Explorer context
|
||||||
|
testContext.apiWrapper.reset();
|
||||||
|
result = await projController.getModelFromContext(mockConnectionProfile);
|
||||||
|
should(result).deepEqual({database: 'My Database', serverId: 'My Id'});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -437,8 +473,7 @@ describe('ProjectsController: add database reference operations', function (): v
|
|||||||
it('Should return the correct system database', async function (): Promise<void> {
|
it('Should return the correct system database', async function (): Promise<void> {
|
||||||
const projController = new ProjectsController(testContext.apiWrapper.object, new SqlDatabaseProjectTreeViewProvider());
|
const projController = new ProjectsController(testContext.apiWrapper.object, new SqlDatabaseProjectTreeViewProvider());
|
||||||
const projFilePath = await testUtils.createTestSqlProjFile(baselines.openProjectFileBaseline);
|
const projFilePath = await testUtils.createTestSqlProjFile(baselines.openProjectFileBaseline);
|
||||||
const project: Project = new Project(projFilePath);
|
const project = await Project.openProject(projFilePath);
|
||||||
await project.readProjFile();
|
|
||||||
|
|
||||||
testContext.apiWrapper.setup(x => x.showQuickPick(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({ label: constants.master }));
|
testContext.apiWrapper.setup(x => x.showQuickPick(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({ label: constants.master }));
|
||||||
let systemDb = await projController.getSystemDatabaseName(project);
|
let systemDb = await projController.getSystemDatabaseName(project);
|
||||||
|
|||||||
@@ -32,10 +32,7 @@ export async function createTestSqlProjFile(contents: string, folderPath?: strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function createTestProject(contents: string, folderPath?: string): Promise<Project> {
|
export async function createTestProject(contents: string, folderPath?: string): Promise<Project> {
|
||||||
const proj = new Project(await createTestSqlProjFile(contents, folderPath));
|
return await Project.openProject(await createTestSqlProjFile(contents, folderPath));
|
||||||
await proj.readProjFile();
|
|
||||||
|
|
||||||
return proj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createTestDataSources(contents: string, folderPath?: string): Promise<string> {
|
export async function createTestDataSources(contents: string, folderPath?: string): Promise<string> {
|
||||||
|
|||||||
Reference in New Issue
Block a user