diff --git a/Packages.props b/Packages.props
index 5912fb2f..d662de1e 100644
--- a/Packages.props
+++ b/Packages.props
@@ -21,7 +21,7 @@
-
+
diff --git a/bin/nuget/Microsoft.SqlServer.DacFx.Projects.161.8086.0-alpha.nupkg b/bin/nuget/Microsoft.SqlServer.DacFx.Projects.161.8086.0-alpha.nupkg
deleted file mode 100644
index d9a24430..00000000
Binary files a/bin/nuget/Microsoft.SqlServer.DacFx.Projects.161.8086.0-alpha.nupkg and /dev/null differ
diff --git a/bin/nuget/Microsoft.SqlServer.DacFx.Projects.161.8093.0-alpha.nupkg b/bin/nuget/Microsoft.SqlServer.DacFx.Projects.161.8093.0-alpha.nupkg
new file mode 100644
index 00000000..9fef7734
Binary files /dev/null and b/bin/nuget/Microsoft.SqlServer.DacFx.Projects.161.8093.0-alpha.nupkg differ
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddDacpacReferenceParams.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddDacpacReferenceParams.cs
index 47712942..12acbcc5 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddDacpacReferenceParams.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddDacpacReferenceParams.cs
@@ -13,18 +13,12 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects.Contracts
///
/// Parameters for adding a Dacpac reference to a SQL project
///
- public class AddDacpacReferenceParams : AddDatabaseReferenceParams
+ public class AddDacpacReferenceParams : AddUserDatabaseReferenceParams
{
///
/// Path to the .dacpac file
///
public string DacpacPath { get; set; }
-
- ///
- /// SQLCMD variable name for specifying the other server this reference is to, if different from that of the current project.
- /// If this is set, DatabaseVariable must also be set.
- ///
- public string? ServerVariable { get; set; }
}
public class AddDacpacReferenceRequest
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddDatabaseReferenceParams.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddDatabaseReferenceParams.cs
index ddad37a0..1a6a18d5 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddDatabaseReferenceParams.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddDatabaseReferenceParams.cs
@@ -3,8 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-#nullable disable
-
namespace Microsoft.SqlTools.ServiceLayer.SqlProjects.Contracts
{
///
@@ -18,8 +16,8 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects.Contracts
public bool SuppressMissingDependencies { get; set; }
///
- /// SQLCMD variable name for specifying the other database this reference is to, if different from that of the current project
+ /// Literal name used to reference another database in the same server, if not using SQLCMD variables
///
- public string? DatabaseVariable { get; set; }
+ public string? DatabaseLiteral { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddSqlProjectReferenceParams.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddSqlProjectReferenceParams.cs
index 1e96aa5c..25343441 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddSqlProjectReferenceParams.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddSqlProjectReferenceParams.cs
@@ -13,7 +13,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects.Contracts
///
/// Parameters for adding a reference to another SQL project
///
- public class AddSqlProjectReferenceParams : AddDatabaseReferenceParams
+ public class AddSqlProjectReferenceParams : AddUserDatabaseReferenceParams
{
///
/// Path to the referenced .sqlproj file
@@ -23,13 +23,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects.Contracts
///
/// GUID for the referenced SQL project
///
- public string? ProjectGuid { get; set; }
-
- ///
- /// SQLCMD variable name for specifying the other server this reference is to, if different from that of the current project.
- /// If this is set, DatabaseVariable must also be set.
- ///
- public string? ServerVariable { get; set; }
+ public string ProjectGuid { get; set; }
}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddSystemDatabaseReference.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddSystemDatabaseReference.cs
index 83b1fc7e..95951cf5 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddSystemDatabaseReference.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddSystemDatabaseReference.cs
@@ -3,8 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-#nullable disable
-
using Microsoft.SqlServer.Dac.Projects;
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddUserDatabaseReferenceParams.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddUserDatabaseReferenceParams.cs
new file mode 100644
index 00000000..17420ac7
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddUserDatabaseReferenceParams.cs
@@ -0,0 +1,36 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+
+namespace Microsoft.SqlTools.ServiceLayer.SqlProjects.Contracts
+{
+ public abstract class AddUserDatabaseReferenceParams : AddDatabaseReferenceParams
+ {
+ ///
+ /// SQLCMD variable name for specifying the other database this reference is to, if different from that of the current project
+ ///
+ public string? DatabaseVariable { get; set; }
+
+ ///
+ /// SQLCMD variable name for specifying the other server this reference is to, if different from that of the current project.
+ /// If this is set, DatabaseVariable must also be set.
+ ///
+ public string? ServerVariable { get; set; }
+
+ ///
+ /// Throws if either both DatabaseVariable and DatabaseLiteral are set. This only validates
+ /// what is necessary for Tools Service. The DacFx Projects library does comprehensive validation.
+ ///
+ ///
+ internal void Validate()
+ {
+ if (DatabaseVariable != null && DatabaseLiteral != null)
+ {
+ throw new ArgumentException($"Both {nameof(DatabaseVariable)} and {nameof(DatabaseLiteral)} cannot be set.");
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Folders/AddFolder.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Folders/AddFolder.cs
index 8b5de800..b591e690 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Folders/AddFolder.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Folders/AddFolder.cs
@@ -3,6 +3,8 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
+#nullable disable
+
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/CloseSqlProject.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/CloseSqlProject.cs
index a00688ca..f6b3d7d1 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/CloseSqlProject.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/CloseSqlProject.cs
@@ -3,8 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-#nullable disable
-
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/GetCrossPlatformCompatibility.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/GetCrossPlatformCompatibility.cs
index cd6bbdd4..8c221450 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/GetCrossPlatformCompatibility.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/GetCrossPlatformCompatibility.cs
@@ -3,8 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-#nullable disable
-
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/NewSqlProject.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/NewSqlProject.cs
index 7a01457c..5bb93594 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/NewSqlProject.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/NewSqlProject.cs
@@ -3,8 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-#nullable disable
-
using Microsoft.SqlServer.Dac.Projects;
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/OpenSqlProject.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/OpenSqlProject.cs
index 8d7088f0..3d0af8e5 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/OpenSqlProject.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/OpenSqlProject.cs
@@ -3,8 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-#nullable disable
-
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlCmdVariables/DeleteSqlCmdVariable.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlCmdVariables/DeleteSqlCmdVariable.cs
index 492e8b33..84331c30 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlCmdVariables/DeleteSqlCmdVariable.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlCmdVariables/DeleteSqlCmdVariable.cs
@@ -3,8 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-#nullable disable
-
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
@@ -18,7 +16,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects.Contracts
///
/// Name of the SQLCMD variable to be deleted
///
- public string Name { get; set; }
+ public string? Name { get; set; }
}
public class DeleteSqlCmdVariableRequest
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlCmdVariables/UpdateSqlCmdvariable.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlCmdVariables/UpdateSqlCmdvariable.cs
index 504a9918..05bae35a 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlCmdVariables/UpdateSqlCmdvariable.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlCmdVariables/UpdateSqlCmdvariable.cs
@@ -3,8 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-#nullable disable
-
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjectScripts/AddSqlObjectScript.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjectScripts/AddSqlObjectScript.cs
index 2396ba93..54d828ac 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjectScripts/AddSqlObjectScript.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjectScripts/AddSqlObjectScript.cs
@@ -3,8 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-#nullable disable
-
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjectScripts/DeleteSqlObjectScript.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjectScripts/DeleteSqlObjectScript.cs
index 2615ec79..fce63055 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjectScripts/DeleteSqlObjectScript.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjectScripts/DeleteSqlObjectScript.cs
@@ -3,8 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-#nullable disable
-
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjectScripts/ExcludeSqlObjectScript.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjectScripts/ExcludeSqlObjectScript.cs
index b48aaa13..2405e7a2 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjectScripts/ExcludeSqlObjectScript.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjectScripts/ExcludeSqlObjectScript.cs
@@ -3,8 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-#nullable disable
-
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs
index 666984de..9663f92f 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs
@@ -81,20 +81,20 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects
internal async Task HandleOpenSqlProjectRequest(SqlProjectParams requestParams, RequestContext requestContext)
{
- await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri), requestContext);
+ await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri!), requestContext);
}
internal async Task HandleCloseSqlProjectRequest(SqlProjectParams requestParams, RequestContext requestContext)
{
- await RunWithErrorHandling(() => Projects.TryRemove(requestParams.ProjectUri, out _), requestContext);
+ await RunWithErrorHandling(() => Projects.TryRemove(requestParams.ProjectUri!, out _), requestContext);
}
internal async Task HandleNewSqlProjectRequest(NewSqlProjectParams requestParams, RequestContext requestContext)
{
await RunWithErrorHandling(async () =>
{
- await SqlProject.CreateProjectAsync(requestParams.ProjectUri, new CreateSqlProjectParams() { ProjectType = requestParams.SqlProjectType, DspVersion = requestParams.DatabaseSchemaProvider });
- GetProject(requestParams.ProjectUri); // load into the cache
+ await SqlProject.CreateProjectAsync(requestParams.ProjectUri!, new CreateSqlProjectParams() { ProjectType = requestParams.SqlProjectType, DspVersion = requestParams.DatabaseSchemaProvider });
+ GetProject(requestParams.ProjectUri!); // load into the cache
}, requestContext);
}
@@ -106,14 +106,14 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects
{
Success = true,
ErrorMessage = null,
- IsCrossPlatformCompatible = GetProject(requestParams.ProjectUri).CrossPlatformCompatible
+ IsCrossPlatformCompatible = GetProject(requestParams.ProjectUri!).CrossPlatformCompatible
};
}, requestContext);
}
internal async Task HandleUpdateProjectForCrossPlatformRequest(SqlProjectParams requestParams, RequestContext requestContext)
{
- await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).UpdateForCrossPlatform(), requestContext);
+ await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri!).UpdateForCrossPlatform(), requestContext);
}
#endregion
@@ -124,17 +124,17 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects
internal async Task HandleAddSqlObjectScriptRequest(SqlProjectScriptParams requestParams, RequestContext requestContext)
{
- await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).SqlObjectScripts.Add(new SqlObjectScript(requestParams.Path)), requestContext);
+ await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri!).SqlObjectScripts.Add(new SqlObjectScript(requestParams.Path!)), requestContext);
}
internal async Task HandleDeleteSqlObjectScriptRequest(SqlProjectScriptParams requestParams, RequestContext requestContext)
{
- await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).SqlObjectScripts.Delete(requestParams.Path), requestContext);
+ await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri!).SqlObjectScripts.Delete(requestParams.Path!), requestContext);
}
internal async Task HandleExcludeSqlObjectScriptRequest(SqlProjectScriptParams requestParams, RequestContext requestContext)
{
- await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).SqlObjectScripts.Exclude(requestParams.Path), requestContext);
+ await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri!).SqlObjectScripts.Exclude(requestParams.Path!), requestContext);
}
#endregion
@@ -193,11 +193,11 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects
internal async Task HandleAddSystemDatabaseReferenceRequest(AddSystemDatabaseReferenceParams requestParams, RequestContext requestContext)
{
- await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).DatabaseReferences.Add(
+ await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri!).DatabaseReferences.Add(
new SystemDatabaseReference(
requestParams.SystemDatabase,
requestParams.SuppressMissingDependencies,
- requestParams.DatabaseVariable)),
+ requestParams.DatabaseLiteral)),
requestContext);
}
@@ -205,14 +205,32 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects
{
await RunWithErrorHandling(() =>
{
- SqlProject project = GetProject(requestParams.ProjectUri);
+ requestParams.Validate();
- project.DatabaseReferences.Add(
- new DacpacReference(
+ SqlProject project = GetProject(requestParams.ProjectUri!);
+ DacpacReference reference;
+
+ if (requestParams.DatabaseLiteral != null) // same server, different database via database name literal
+ {
+ reference = new DacpacReference(
requestParams.DacpacPath,
requestParams.SuppressMissingDependencies,
- project.SqlCmdVariables.Get(requestParams.DatabaseVariable),
- project.SqlCmdVariables.Get(requestParams.ServerVariable)));
+ requestParams.DatabaseLiteral);
+ }
+ else if (requestParams.DatabaseVariable != null) // different database, possibly different server via sqlcmdvar
+ {
+ reference = new DacpacReference(
+ requestParams.DacpacPath,
+ requestParams.SuppressMissingDependencies,
+ project.SqlCmdVariables.Get(requestParams.DatabaseVariable!),
+ requestParams.ServerVariable != null ? project.SqlCmdVariables.Get(requestParams.ServerVariable) : null);
+ }
+ else // same database
+ {
+ reference = new DacpacReference(requestParams.DacpacPath, requestParams.SuppressMissingDependencies);
+ }
+
+ project.DatabaseReferences.Add(reference);
}, requestContext);
}
@@ -220,42 +238,64 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects
{
await RunWithErrorHandling(() =>
{
- SqlProject project = GetProject(requestParams.ProjectUri);
+ requestParams.Validate();
- project.DatabaseReferences.Add(
- new SqlProjectReference(
+ SqlProject project = GetProject(requestParams.ProjectUri!);
+ SqlProjectReference reference;
+
+ if (requestParams.DatabaseLiteral != null) // same server, different database via database name literal
+ {
+ reference = new SqlProjectReference(
requestParams.ProjectPath,
requestParams.ProjectGuid,
requestParams.SuppressMissingDependencies,
- project.SqlCmdVariables.Get(requestParams.DatabaseVariable),
- project.SqlCmdVariables.Get(requestParams.ServerVariable)));
+ requestParams.DatabaseLiteral);
+ }
+ else if (requestParams.DatabaseVariable != null) // different database, possibly different server via sqlcmdvar
+ {
+ reference = new SqlProjectReference(
+ requestParams.ProjectPath,
+ requestParams.ProjectGuid, requestParams.SuppressMissingDependencies,
+ project.SqlCmdVariables.Get(requestParams.DatabaseVariable!),
+ requestParams.ServerVariable != null ? project.SqlCmdVariables.Get(requestParams.ServerVariable) : null);
+ }
+ else // same database
+ {
+ reference = new SqlProjectReference(
+ requestParams.ProjectPath,
+ requestParams.ProjectGuid,
+ requestParams.SuppressMissingDependencies);
+ }
+
+ project.DatabaseReferences.Add(reference);
}, requestContext);
}
internal async Task HandleDeleteDatabaseReferenceRequest(DeleteDatabaseReferenceParams requestParams, RequestContext requestContext)
{
- await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).DatabaseReferences.Delete(requestParams.Name), requestContext);
+ await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri!).DatabaseReferences.Delete(requestParams.Name!), requestContext);
}
#endregion
+
#region SQLCMD variable functions
internal async Task HandleAddSqlCmdVariableRequest(AddSqlCmdVariableParams requestParams, RequestContext requestContext)
{
- await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).SqlCmdVariables.Add(new SqlCmdVariable(requestParams.Name, requestParams.DefaultValue, requestParams.Value)), requestContext);
+ await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri!).SqlCmdVariables.Add(new SqlCmdVariable(requestParams.Name, requestParams.DefaultValue, requestParams.Value)), requestContext);
}
internal async Task HandleDeleteSqlCmdVariableRequest(DeleteSqlCmdVariableParams requestParams, RequestContext requestContext)
{
- await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).SqlCmdVariables.Delete(requestParams.Name), requestContext);
+ await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri!).SqlCmdVariables.Delete(requestParams.Name), requestContext);
}
internal async Task HandleUpdateSqlCmdVariableRequest(AddSqlCmdVariableParams requestParams, RequestContext requestContext)
{
await RunWithErrorHandling(() =>
{
- SqlProject project = GetProject(requestParams.ProjectUri);
+ SqlProject project = GetProject(requestParams.ProjectUri!);
project.SqlCmdVariables.Delete(requestParams.Name); // idempotent (won't throw if doesn't exist)
project.SqlCmdVariables.Add(new SqlCmdVariable(requestParams.Name, requestParams.DefaultValue, requestParams.Value));
}, requestContext);
diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs
index baf32e57..eb5d037d 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs
@@ -283,40 +283,77 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects
Assert.IsFalse(File.Exists(scriptFullPath), $"{scriptFullPath} expected to have been deleted from disk");
}
+ #region Database reference tests
+
[Test]
- public async Task TestDatabaseReferenceAddDelete()
+ public async Task TestDatabaseReferenceDelete()
{
- // Setup
- SqlProjectsService service = new();
- string projectUri = await service.CreateSqlProject();
+ var (service, projectUri, _, _) = await SetUpDatabaseReferenceTest();
- SqlCmdVariable databaseVar = new SqlCmdVariable("$(OtherDb)", "OtherDbDefaultValue", "OtherDbValue");
- SqlCmdVariable serverVar = new SqlCmdVariable("$(OtherServer)", "OtherServerDefaultValue", "OtherServerValue");
+ // directly add a reference so there's something to delete
+ service.Projects[projectUri].DatabaseReferences.Add(new SystemDatabaseReference(SystemDatabase.Master, suppressMissingDependencies: true));
- service.Projects[projectUri].SqlCmdVariables.Add(databaseVar);
- service.Projects[projectUri].SqlCmdVariables.Add(serverVar);
+ Assert.AreEqual(1, service.Projects[projectUri].DatabaseReferences.Count, "Database references after adding reference");
- Assert.AreEqual(0, service.Projects[projectUri].DatabaseReferences.Count, "Baseline number of database references");
+ MockRequest requestMock = new();
+ await service.HandleDeleteDatabaseReferenceRequest(new DeleteDatabaseReferenceParams()
+ {
+ ProjectUri = projectUri,
+ Name = SystemDatabase.Master.ToString()
+ }, requestMock.Object);
+
+ requestMock.AssertSuccess(nameof(service.HandleDeleteDatabaseReferenceRequest));
+ Assert.AreEqual(0, service.Projects[projectUri].DatabaseReferences.Count, "Database references after deleting reference");
+ }
+
+ [Test]
+ public async Task TestSystemDatabaseReferenceAdd()
+ {
+ var (service, projectUri, _, _) = await SetUpDatabaseReferenceTest();
- // Validate adding a system database reference
MockRequest requestMock = new();
await service.HandleAddSystemDatabaseReferenceRequest(new AddSystemDatabaseReferenceParams()
{
ProjectUri = projectUri,
SystemDatabase = SystemDatabase.MSDB,
- DatabaseVariable = "$(EmEssDeeBee)",
+ DatabaseLiteral = "EmEssDeeBee",
SuppressMissingDependencies = false
}, requestMock.Object);
requestMock.AssertSuccess(nameof(service.HandleAddSystemDatabaseReferenceRequest));
Assert.AreEqual(1, service.Projects[projectUri].DatabaseReferences.Count, "Database references after adding system db reference");
- SystemDatabaseReference systemDbRef = (SystemDatabaseReference)service.Projects[projectUri].DatabaseReferences.First(x => x is SystemDatabaseReference);
+ SystemDatabaseReference systemDbRef = (SystemDatabaseReference)service.Projects[projectUri].DatabaseReferences.Get(SystemDatabase.MSDB.ToString());
Assert.AreEqual(SystemDatabase.MSDB, systemDbRef.SystemDb, "Referenced system DB");
- Assert.AreEqual("$(EmEssDeeBee)", systemDbRef.DatabaseVariableLiteralName);
+ Assert.AreEqual("EmEssDeeBee", systemDbRef.DatabaseVariableLiteralName);
Assert.IsFalse(systemDbRef.SuppressMissingDependencies, nameof(systemDbRef.SuppressMissingDependencies));
+ }
- // Validate adding a dacpac reference
- string mockReferencePath = Path.Join(Path.GetDirectoryName(projectUri), "OtherDatabase.dacpac");
+ [Test]
+ public async Task TestDacpacReferenceAdd()
+ {
+ var (service, projectUri, databaseVar, serverVar) = await SetUpDatabaseReferenceTest();
+
+ // Validate adding a dacpac reference on the same server
+ string mockReferencePath = Path.Join(Path.GetDirectoryName(projectUri), "OtherDatabaseSameServer.dacpac");
+
+ MockRequest requestMock = new();
+ await service.HandleAddDacpacReferenceRequest(new AddDacpacReferenceParams()
+ {
+ ProjectUri = projectUri,
+ DacpacPath = mockReferencePath,
+ SuppressMissingDependencies = false
+ }, requestMock.Object);
+
+ requestMock.AssertSuccess(nameof(service.HandleAddDacpacReferenceRequest), "same server");
+ Assert.AreEqual(1, service.Projects[projectUri].DatabaseReferences.Count, "Database references after adding dacpac reference (same server)");
+ DacpacReference dacpacRef = (DacpacReference)service.Projects[projectUri].DatabaseReferences.Get(FileUtils.NormalizePath(mockReferencePath, PlatformID.Win32NT));
+ Assert.AreEqual(FileUtils.NormalizePath(mockReferencePath, PlatformID.Win32NT), dacpacRef.DacpacPath, "Referenced dacpac");
+ Assert.IsFalse(dacpacRef.SuppressMissingDependencies, nameof(dacpacRef.SuppressMissingDependencies));
+ Assert.IsNull(dacpacRef.DatabaseVariableLiteralName, nameof(dacpacRef.DatabaseVariableLiteralName));
+ Assert.IsNull(dacpacRef.DatabaseVariable, nameof(dacpacRef.DatabaseVariable));
+
+ // Validate adding a dacpac reference via SQLCMD variable
+ mockReferencePath = Path.Join(Path.GetDirectoryName(projectUri), "OtherDatabaseSqlCmd.dacpac");
requestMock = new();
await service.HandleAddDacpacReferenceRequest(new AddDacpacReferenceParams()
@@ -328,16 +365,60 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects
ServerVariable = serverVar.Name
}, requestMock.Object);
- requestMock.AssertSuccess(nameof(service.HandleAddDacpacReferenceRequest));
- Assert.AreEqual(2, service.Projects[projectUri].DatabaseReferences.Count, "Database references after adding dacpac reference");
- DacpacReference dacpacRef = (DacpacReference)service.Projects[projectUri].DatabaseReferences.First(x => x is DacpacReference);
+ requestMock.AssertSuccess(nameof(service.HandleAddDacpacReferenceRequest), "sqlcmdvar");
+ Assert.AreEqual(2, service.Projects[projectUri].DatabaseReferences.Count, "Database references after adding dacpac reference (sqlcmdvar)");
+ dacpacRef = (DacpacReference)service.Projects[projectUri].DatabaseReferences.Get(FileUtils.NormalizePath(mockReferencePath, PlatformID.Win32NT));
Assert.AreEqual(FileUtils.NormalizePath(mockReferencePath, PlatformID.Win32NT), dacpacRef.DacpacPath, "Referenced dacpac");
- Assert.AreEqual(databaseVar.Name, dacpacRef.DatabaseVariable.VarName);
- Assert.AreEqual(serverVar.Name, dacpacRef.ServerVariable.VarName);
+ Assert.AreEqual(databaseVar.Name, dacpacRef.DatabaseVariable!.VarName);
+ Assert.AreEqual(serverVar.Name, dacpacRef.ServerVariable!.VarName);
Assert.IsFalse(dacpacRef.SuppressMissingDependencies, nameof(dacpacRef.SuppressMissingDependencies));
- // Validate adding a project reference
- mockReferencePath = Path.Join(Path.GetDirectoryName(projectUri), "..", "OtherDatabase", "OtherDatabase.sqlproj");
+ // Validate adding a dacpac reference via database literal
+ mockReferencePath = Path.Join(Path.GetDirectoryName(projectUri), "OtherDatabaseLiteral.dacpac");
+
+ requestMock = new();
+ await service.HandleAddDacpacReferenceRequest(new AddDacpacReferenceParams()
+ {
+ ProjectUri = projectUri,
+ DacpacPath = mockReferencePath,
+ SuppressMissingDependencies = false,
+ DatabaseLiteral = "DacpacLiteral"
+ }, requestMock.Object);
+
+ requestMock.AssertSuccess(nameof(service.HandleAddDacpacReferenceRequest), "db literal");
+ Assert.AreEqual(3, service.Projects[projectUri].DatabaseReferences.Count, "Database references after adding dacpac reference (db literal)");
+ dacpacRef = (DacpacReference)service.Projects[projectUri].DatabaseReferences.Get(FileUtils.NormalizePath(mockReferencePath, PlatformID.Win32NT));
+ Assert.AreEqual(FileUtils.NormalizePath(mockReferencePath, PlatformID.Win32NT), dacpacRef.DacpacPath, "Referenced dacpac");
+ Assert.AreEqual("DacpacLiteral", dacpacRef.DatabaseVariableLiteralName, nameof(dacpacRef.DatabaseVariableLiteralName));
+ Assert.IsFalse(dacpacRef.SuppressMissingDependencies, nameof(dacpacRef.SuppressMissingDependencies));
+ }
+
+ [Test]
+ public async Task TestSqlProjectReferenceAdd()
+ {
+ var (service, projectUri, databaseVar, serverVar) = await SetUpDatabaseReferenceTest();
+
+ // Validate adding a project reference on the same server
+ string mockReferencePath = Path.Join(Path.GetDirectoryName(projectUri), "..", "SameDatabase", "SameDatabaseSqlCmd.sqlproj");
+
+ MockRequest requestMock = new();
+ await service.HandleAddSqlProjectReferenceRequest(new AddSqlProjectReferenceParams()
+ {
+ ProjectUri = projectUri,
+ ProjectPath = mockReferencePath,
+ SuppressMissingDependencies = false
+ }, requestMock.Object);
+
+ requestMock.AssertSuccess(nameof(service.HandleAddSqlProjectReferenceRequest), "same server");
+ Assert.AreEqual(1, service.Projects[projectUri].DatabaseReferences.Count, "Database references after adding SQL project reference (same server)");
+ SqlProjectReference projectRef = (SqlProjectReference)service.Projects[projectUri].DatabaseReferences.Get(FileUtils.NormalizePath(mockReferencePath, PlatformID.Win32NT));
+ Assert.AreEqual(FileUtils.NormalizePath(mockReferencePath, PlatformID.Win32NT), projectRef.ProjectPath, "Referenced project");
+ Assert.IsFalse(projectRef.SuppressMissingDependencies, nameof(projectRef.SuppressMissingDependencies));
+ Assert.IsNull(projectRef.DatabaseVariableLiteralName, nameof(projectRef.DatabaseVariableLiteralName));
+ Assert.IsNull(projectRef.DatabaseVariable, nameof(projectRef.DatabaseVariable));
+
+ // Validate adding a project reference via SQLCMD variable
+ mockReferencePath = Path.Join(Path.GetDirectoryName(projectUri), "..", "OtherDatabase", "OtherDatabaseSqlCmd.sqlproj");
requestMock = new();
await service.HandleAddSqlProjectReferenceRequest(new AddSqlProjectReferenceParams()
@@ -351,27 +432,38 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects
}, requestMock.Object);
requestMock.AssertSuccess(nameof(service.HandleAddSqlProjectReferenceRequest));
- Assert.AreEqual(3, service.Projects[projectUri].DatabaseReferences.Count, "Database references after adding SQL project reference");
- SqlProjectReference projectRef = (SqlProjectReference)service.Projects[projectUri].DatabaseReferences.First(x => x is SqlProjectReference);
- Assert.AreEqual(mockReferencePath, projectRef.ProjectPath, "Referenced project");
+ Assert.AreEqual(2, service.Projects[projectUri].DatabaseReferences.Count, "Database references after adding SQL project reference (sqlcmdvar)");
+ projectRef = (SqlProjectReference)service.Projects[projectUri].DatabaseReferences.Get(FileUtils.NormalizePath(mockReferencePath, PlatformID.Win32NT));
+ Assert.AreEqual(FileUtils.NormalizePath(mockReferencePath, PlatformID.Win32NT), projectRef.ProjectPath, "Referenced project");
Assert.AreEqual(TEST_GUID, projectRef.ProjectGuid, "Referenced project GUID");
- Assert.AreEqual(databaseVar.Name, projectRef.DatabaseVariable.VarName);
- Assert.AreEqual(serverVar.Name, projectRef.ServerVariable.VarName);
+ Assert.AreEqual(databaseVar.Name, projectRef.DatabaseVariable!.VarName);
+ Assert.AreEqual(serverVar.Name, projectRef.ServerVariable!.VarName);
Assert.IsFalse(projectRef.SuppressMissingDependencies, nameof(projectRef.SuppressMissingDependencies));
- // Validate deleting a reference
+ // Validate adding a project reference via database literal
+ mockReferencePath = Path.Join(Path.GetDirectoryName(projectUri), "..", "OtherDatabase", "OtherDatabaseLiteral.sqlproj");
+
requestMock = new();
- await service.HandleDeleteDatabaseReferenceRequest(new DeleteDatabaseReferenceParams()
+ await service.HandleAddSqlProjectReferenceRequest(new AddSqlProjectReferenceParams()
{
ProjectUri = projectUri,
- Name = mockReferencePath
+ ProjectPath = mockReferencePath,
+ ProjectGuid = TEST_GUID,
+ SuppressMissingDependencies = false,
+ DatabaseLiteral = "ProjectLiteral"
}, requestMock.Object);
- requestMock.AssertSuccess(nameof(service.HandleDeleteDatabaseReferenceRequest));
- Assert.AreEqual(2, service.Projects[projectUri].DatabaseReferences.Count, "Database references after deleting SQL project reference");
- Assert.IsFalse(service.Projects[projectUri].DatabaseReferences.Any(x => x is SqlProjectReference), "Database references list expected to not contain the SQL Project reference");
+ requestMock.AssertSuccess(nameof(service.HandleAddSqlProjectReferenceRequest));
+ Assert.AreEqual(3, service.Projects[projectUri].DatabaseReferences.Count, "Database references after adding SQL project reference (db literal)");
+ projectRef = (SqlProjectReference)service.Projects[projectUri].DatabaseReferences.Get(FileUtils.NormalizePath(mockReferencePath, PlatformID.Win32NT));
+ Assert.AreEqual(FileUtils.NormalizePath(mockReferencePath, PlatformID.Win32NT), projectRef.ProjectPath, "Referenced project");
+ Assert.AreEqual(TEST_GUID, projectRef.ProjectGuid, "Referenced project GUID");
+ Assert.AreEqual("ProjectLiteral", projectRef.DatabaseVariableLiteralName);
+ Assert.IsFalse(projectRef.SuppressMissingDependencies, nameof(projectRef.SuppressMissingDependencies));
}
+ #endregion
+
[Test]
public async Task TestFolderAddDelete()
{
@@ -497,6 +589,27 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects
getRequestMock.AssertSuccess(nameof(service.HandleGetCrossPlatformCompatibilityRequest));
Assert.IsTrue(((GetCrossPlatformCompatiblityResult)getRequestMock.Result).IsCrossPlatformCompatible, "Input file should be cross-platform compatible after conversion");
}
+
+ #region Helpers
+
+ private async Task<(SqlProjectsService Service, string ProjectUri, SqlCmdVariable DatabaseVar, SqlCmdVariable ServerVar)> SetUpDatabaseReferenceTest()
+ {
+ // Setup
+ SqlProjectsService service = new();
+ string projectUri = await service.CreateSqlProject();
+
+ SqlCmdVariable databaseVar = new SqlCmdVariable("$(OtherDb)", "OtherDbDefaultValue", "OtherDbValue");
+ SqlCmdVariable serverVar = new SqlCmdVariable("$(OtherServer)", "OtherServerDefaultValue", "OtherServerValue");
+
+ service.Projects[projectUri].SqlCmdVariables.Add(databaseVar);
+ service.Projects[projectUri].SqlCmdVariables.Add(serverVar);
+
+ Assert.AreEqual(0, service.Projects[projectUri].DatabaseReferences.Count, "Baseline number of database references");
+
+ return (service, projectUri, databaseVar, serverVar);
+ }
+
+ #endregion
}
internal static class SqlProjectsExtensions
diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/SqlProjects/SqlProjectTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/SqlProjects/SqlProjectTests.cs
new file mode 100644
index 00000000..6bd26308
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/SqlProjects/SqlProjectTests.cs
@@ -0,0 +1,37 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using Microsoft.SqlTools.ServiceLayer.SqlProjects.Contracts;
+using NUnit.Framework;
+
+namespace Microsoft.SqlTools.ServiceLayer.UnitTests.SqlProjects
+{
+ public class SqlProjectTests
+ {
+ [Test]
+ public void DatabaseReferenceValidationTest()
+ {
+ // Verify that Validate() throws when both DatabaseLiteral and DatabaseVariable are set
+ AddUserDatabaseReferenceParams reference = new AddDacpacReferenceParams() // any concrete class will do
+ {
+ DatabaseLiteral = "DatabaseName",
+ DatabaseVariable = "$(DatabaseVariable)"
+ };
+
+ Assert.Throws(() => reference.Validate(), $"Validate() for a reference with both {nameof(reference.DatabaseLiteral)} and {nameof(reference.DatabaseVariable)} should have failed");
+
+ // Verify that Validate() passes any other time
+ reference = new AddDacpacReferenceParams() { DatabaseLiteral = "DatabaseName" };
+ reference.Validate();
+
+ reference = new AddDacpacReferenceParams() { DatabaseVariable = "$(DatabaseVariable)" };
+ reference.Validate();
+
+ reference = new AddDacpacReferenceParams();
+ reference.Validate();
+ }
+ }
+}