diff --git a/src/Microsoft.SqlTools.ServiceLayer/HostLoader.cs b/src/Microsoft.SqlTools.ServiceLayer/HostLoader.cs
index aa46a8d9..bb5f2a85 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/HostLoader.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/HostLoader.cs
@@ -4,6 +4,7 @@
//
using System;
+using System.IO;
using System.Threading.Tasks;
using Microsoft.SqlTools.Credentials;
using Microsoft.SqlTools.Extensibility;
@@ -11,12 +12,14 @@ using Microsoft.SqlTools.Hosting;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Admin;
using Microsoft.SqlTools.ServiceLayer.Agent;
+using Microsoft.SqlTools.ServiceLayer.AzureBlob;
using Microsoft.SqlTools.ServiceLayer.AzureFunctions;
using Microsoft.SqlTools.ServiceLayer.Cms;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.DacFx;
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery;
using Microsoft.SqlTools.ServiceLayer.EditData;
+using Microsoft.SqlTools.ServiceLayer.ExecutionPlan;
using Microsoft.SqlTools.ServiceLayer.FileBrowser;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.LanguageExtensibility;
@@ -25,6 +28,9 @@ using Microsoft.SqlTools.ServiceLayer.Metadata;
#if INCLUDE_MIGRATION
using Microsoft.SqlTools.ServiceLayer.Migration;
#endif
+using Microsoft.SqlTools.ServiceLayer.ModelManagement;
+using Microsoft.SqlTools.ServiceLayer.NotebookConvert;
+using Microsoft.SqlTools.ServiceLayer.ObjectManagement;
using Microsoft.SqlTools.ServiceLayer.Profiler;
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
using Microsoft.SqlTools.ServiceLayer.SchemaCompare;
@@ -33,15 +39,9 @@ using Microsoft.SqlTools.ServiceLayer.Security;
using Microsoft.SqlTools.ServiceLayer.ServerConfigurations;
using Microsoft.SqlTools.ServiceLayer.SqlAssessment;
using Microsoft.SqlTools.ServiceLayer.SqlContext;
-using Microsoft.SqlTools.ServiceLayer.Workspace;
-using Microsoft.SqlTools.ServiceLayer.NotebookConvert;
-using Microsoft.SqlTools.ServiceLayer.ModelManagement;
-using Microsoft.SqlTools.ServiceLayer.TableDesigner;
-using Microsoft.SqlTools.ServiceLayer.AzureBlob;
-using Microsoft.SqlTools.ServiceLayer.ExecutionPlan;
-using Microsoft.SqlTools.ServiceLayer.ObjectManagement;
-using System.IO;
using Microsoft.SqlTools.ServiceLayer.SqlProjects;
+using Microsoft.SqlTools.ServiceLayer.TableDesigner;
+using Microsoft.SqlTools.ServiceLayer.Workspace;
namespace Microsoft.SqlTools.ServiceLayer
{
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlCmdVariables/AddSqlCmdVariable.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlCmdVariables/AddSqlCmdVariable.cs
new file mode 100644
index 00000000..5230948e
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlCmdVariables/AddSqlCmdVariable.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 Microsoft.SqlTools.Hosting.Protocol.Contracts;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.SqlProjects.Contracts
+{
+ ///
+ /// Parameters for adding a SQLCMD variable to a project
+ ///
+ public class AddSqlCmdVariableParams : SqlProjectParams
+ {
+ ///
+ /// Name of the SQLCMD variable
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Default value of the SQLCMD variable
+ ///
+ public string DefaultValue { get; set; }
+
+ ///
+ /// Value of the SQLCMD variable, with or without the $()
+ ///
+ public string Value { get; set; }
+ }
+
+ public class AddSqlCmdVariableRequest
+ {
+ public static readonly RequestType Type = RequestType.Create("sqlprojects/addSqlCmdVariable");
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlCmdVariables/DeleteSqlCmdVariable.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlCmdVariables/DeleteSqlCmdVariable.cs
new file mode 100644
index 00000000..21c86e0e
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlCmdVariables/DeleteSqlCmdVariable.cs
@@ -0,0 +1,26 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.SqlTools.Hosting.Protocol.Contracts;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.SqlProjects.Contracts
+{
+ ///
+ /// Parameters for deleting a SQLCMD variable from a project
+ ///
+ public class DeleteSqlCmdVariableParams : SqlProjectParams
+ {
+ ///
+ /// Name of the SQLCMD variable to be deleted
+ ///
+ public string Name { get; set; }
+ }
+
+ public class DeleteSqlCmdVariableRequest
+ {
+ public static readonly RequestType Type = RequestType.Create("sqlprojects/deleteSqlCmdVariable");
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlCmdVariables/UpdateSqlCmdvariable.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlCmdVariables/UpdateSqlCmdvariable.cs
new file mode 100644
index 00000000..10a6f59a
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlCmdVariables/UpdateSqlCmdvariable.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.SqlTools.Hosting.Protocol.Contracts;
+using Microsoft.SqlTools.ServiceLayer.Utility;
+
+namespace Microsoft.SqlTools.ServiceLayer.SqlProjects.Contracts
+{
+ public class UpdateSqlCmdVariableRequest
+ {
+ public static readonly RequestType Type = RequestType.Create("sqlprojects/updateSqlCmdVariable");
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs
index 4e6b661c..d55f6cc6 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs
@@ -43,10 +43,15 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects
serviceHost.SetRequestHandler(CloseSqlProjectRequest.Type, HandleCloseSqlProjectRequest, isParallelProcessingSupported: true);
serviceHost.SetRequestHandler(NewSqlProjectRequest.Type, HandleNewSqlProjectRequest, isParallelProcessingSupported: true);
- // SQL object script calls
+ // SQL object script functions
serviceHost.SetRequestHandler(AddSqlObjectScriptRequest.Type, HandleAddSqlObjectScriptRequest, isParallelProcessingSupported: false);
serviceHost.SetRequestHandler(DeleteSqlObjectScriptRequest.Type, HandleDeleteSqlObjectScriptRequest, isParallelProcessingSupported: false);
serviceHost.SetRequestHandler(ExcludeSqlObjectScriptRequest.Type, HandleExcludeSqlObjectScriptRequest, isParallelProcessingSupported: false);
+
+ // SQLCMD variable functions
+ serviceHost.SetRequestHandler(AddSqlCmdVariableRequest.Type, HandleAddSqlCmdVariableRequest, isParallelProcessingSupported: false);
+ serviceHost.SetRequestHandler(DeleteSqlCmdVariableRequest.Type, HandleDeleteSqlCmdVariableRequest, isParallelProcessingSupported: false);
+ serviceHost.SetRequestHandler(UpdateSqlCmdVariableRequest.Type, HandleUpdateSqlCmdVariableRequest, isParallelProcessingSupported: false);
}
#region Handlers
@@ -75,7 +80,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects
#endregion
- #region Sql object script calls
+ #region SQL object script functions
internal async Task HandleAddSqlObjectScriptRequest(SqlProjectScriptParams requestParams, RequestContext requestContext)
{
@@ -94,6 +99,30 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects
#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);
+ }
+
+ internal async Task HandleDeleteSqlCmdVariableRequest(DeleteSqlCmdVariableParams requestParams, RequestContext 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);
+ 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);
+ }
+
+ #endregion
+
#endregion
#region Helper methods
diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs
index 53274822..d661c2e7 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs
@@ -4,6 +4,7 @@
//
using System.IO;
+using System.Linq;
using System.Threading.Tasks;
using Microsoft.SqlServer.Dac.Projects;
using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
@@ -105,7 +106,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects
// Validate adding a SQL object script
MockRequest requestMock = new();
- string scriptRelativePath = "MyTable.sql";
+ string scriptRelativePath = "MyTable.sql";
string scriptFullPath = Path.Join(Path.GetDirectoryName(projectUri), scriptRelativePath);
await File.WriteAllTextAsync(scriptFullPath, "CREATE TABLE [MyTable] ([Id] INT)");
Assert.IsTrue(File.Exists(scriptFullPath), $"{scriptFullPath} expected to be on disk");
@@ -155,6 +156,61 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects
Assert.AreEqual(0, service.Projects[projectUri].SqlObjectScripts.Count, "SqlObjectScripts count after delete");
Assert.IsFalse(File.Exists(scriptFullPath), $"{scriptFullPath} expected to have been deleted from disk");
}
+
+ [Test]
+ public async Task TestSqlCmdVariablesAddDelete()
+ {
+ SqlProjectsService service = new();
+ string projectUri = await service.CreateSqlProject();
+
+ Assert.AreEqual(0, service.Projects[projectUri].SqlCmdVariables.Count, "Baseline number of SQLCMD variables not as expected");
+
+ // Validate adding a SQLCMD variable
+ MockRequest requestMock = new();
+
+ const string variableName = "TestVarName";
+
+ await service.HandleAddSqlCmdVariableRequest(new AddSqlCmdVariableParams()
+ {
+ ProjectUri = projectUri,
+ Name = variableName,
+ DefaultValue = "$(TestVarDefaultValue)",
+ Value = "$(TestVarValue)"
+ }, requestMock.Object);
+
+ requestMock.AssertSuccess(nameof(service.HandleAddSqlCmdVariableRequest));
+ Assert.AreEqual(1, service.Projects[projectUri].SqlCmdVariables.Count, "Number of SQLCMD variables after addition not as expected");
+ Assert.IsTrue(service.Projects[projectUri].SqlCmdVariables.Contains(variableName), $"List of SQLCMD variables expected to contain {variableName}");
+
+ // Validate updating a SQLCMD variable
+ const string updatedDefaultValue = "$(UpdatedDefaultValue)";
+ const string updatedValue = "$(UpdatedValue)";
+
+ requestMock = new();
+ await service.HandleUpdateSqlCmdVariableRequest(new AddSqlCmdVariableParams()
+ {
+ ProjectUri = projectUri,
+ Name = variableName,
+ DefaultValue = updatedDefaultValue,
+ Value = updatedValue
+ }, requestMock.Object);
+
+ requestMock.AssertSuccess(nameof(service.HandleUpdateSqlCmdVariableRequest));
+ Assert.AreEqual(1, service.Projects[projectUri].SqlCmdVariables.Count, "Number of SQLCMD variables after update not as expected");
+ Assert.AreEqual(updatedDefaultValue, service.Projects[projectUri].SqlCmdVariables.First().DefaultValue, "Updated default value");
+ Assert.AreEqual(updatedValue, service.Projects[projectUri].SqlCmdVariables.First().Value, "Updated value");
+
+ // Validate deleting a SQLCMD variable
+ requestMock = new();
+ await service.HandleDeleteSqlCmdVariableRequest(new DeleteSqlCmdVariableParams()
+ {
+ ProjectUri = projectUri,
+ Name = variableName,
+ }, requestMock.Object);
+
+ requestMock.AssertSuccess(nameof(service.HandleDeleteSqlCmdVariableRequest));
+ Assert.AreEqual(0, service.Projects[projectUri].SqlCmdVariables.Count, "Number of SQLCMD variables after deletion not as expected");
+ }
}
internal static class SqlProjectsExtensions