diff --git a/src/Microsoft.SqlTools.ServiceLayer/DacFx/Contracts/GetObjectsFromTSqlModelRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/DacFx/Contracts/GetObjectsFromTSqlModelRequest.cs
new file mode 100644
index 00000000..86cf8dc0
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/DacFx/Contracts/GetObjectsFromTSqlModelRequest.cs
@@ -0,0 +1,33 @@
+//
+// 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;
+
+namespace Microsoft.SqlTools.ServiceLayer.DacFx.Contracts
+{
+ ///
+ /// Parameters to get objects from SQL model
+ ///
+ public class GetObjectsFromTSqlModelParams
+ {
+ ///
+ /// URI of the project file this model is for
+ ///
+ public string ProjectUri { get; set; }
+
+ ///
+ /// Object types to query
+ ///
+ public string[] ObjectTypes { get; set; }
+ }
+
+ ///
+ /// Defines the get objects sql model request
+ ///
+ class GetObjectsFromTSqlModelRequest
+ {
+ public static readonly RequestType Type =
+ RequestType.Create("dacFx/getObjectsFromTSqlModel");
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/DacFx/Contracts/TSqlObjectInfo.cs b/src/Microsoft.SqlTools.ServiceLayer/DacFx/Contracts/TSqlObjectInfo.cs
new file mode 100644
index 00000000..cf93482c
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/DacFx/Contracts/TSqlObjectInfo.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.
+//
+
+namespace Microsoft.SqlTools.ServiceLayer.DacFx.Contracts
+{
+ ///
+ /// Describes TSqlObject information
+ ///
+ public class TSqlObjectInfo
+ {
+ public string Name { get; set; }
+
+ public string ObjectType { get; set; }
+
+ public TSqlObjectRelationship[] ReferencedObjects { get; set; }
+ }
+
+ ///
+ /// Describes objects referenced and their relationship type
+ ///
+ public class TSqlObjectRelationship
+ {
+ public string Name { get; set; }
+
+ public string ObjectType { get; set; }
+
+ public string RelationshipType { get; set; }
+
+ public string FromObjectName { get; set; }
+
+ public string FromObjectType { get; set; }
+ }
+
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/DacFx/DacFxService.cs b/src/Microsoft.SqlTools.ServiceLayer/DacFx/DacFxService.cs
index af5c4cd0..583767c6 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/DacFx/DacFxService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/DacFx/DacFxService.cs
@@ -57,6 +57,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DacFx
serviceHost.SetRequestHandler(GetDefaultPublishOptionsRequest.Type, this.HandleGetDefaultPublishOptionsRequest);
serviceHost.SetRequestHandler(ParseTSqlScriptRequest.Type, this.HandleParseTSqlScriptRequest);
serviceHost.SetRequestHandler(GenerateTSqlModelRequest.Type, this.HandleGenerateTSqlModelRequest);
+ serviceHost.SetRequestHandler(GetObjectsFromTSqlModelRequest.Type, this.HandleGetObjectsFromTSqlModelRequest);
}
///
@@ -286,6 +287,28 @@ namespace Microsoft.SqlTools.ServiceLayer.DacFx
}
}
+ ///
+ /// Handles request to get objects from sql model
+ ///
+ ///
+ public async Task HandleGetObjectsFromTSqlModelRequest(GetObjectsFromTSqlModelParams requestParams, RequestContext requestContext)
+ {
+ TSqlObjectInfo[] objectInfos = { };
+ var model = projectModels.Value[requestParams.ProjectUri];
+
+ if (model == null)
+ {
+ await requestContext.SendError(new Exception(SR.SqlProjectModelNotFound(requestParams.ProjectUri)));
+ }
+ else
+ {
+ GetObjectsFromTSqlModelOperation operation = new GetObjectsFromTSqlModelOperation(requestParams, model);
+ objectInfos = operation.GetObjectsFromTSqlModel();
+ await requestContext.SendResult(objectInfos);
+ }
+ return;
+ }
+
private void ExecuteOperation(DacFxOperation operation, DacFxParams parameters, string taskName, RequestContext requestContext)
{
Task.Run(async () =>
diff --git a/src/Microsoft.SqlTools.ServiceLayer/DacFx/GetObjectsFromTSqlModelOperation.cs b/src/Microsoft.SqlTools.ServiceLayer/DacFx/GetObjectsFromTSqlModelOperation.cs
new file mode 100644
index 00000000..d1d1697c
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/DacFx/GetObjectsFromTSqlModelOperation.cs
@@ -0,0 +1,77 @@
+//
+// 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 System.Linq;
+using Microsoft.SqlTools.ServiceLayer.DacFx.Contracts;
+using Microsoft.SqlTools.Utility;
+using Microsoft.SqlServer.Dac.Model;
+
+namespace Microsoft.SqlTools.ServiceLayer.DacFx
+{
+ ///
+ /// Class to represent request to get objects from model
+ ///
+ public class GetObjectsFromTSqlModelOperation
+ {
+ private TSqlModel Model;
+ public GetObjectsFromTSqlModelParams Parameters { get; }
+
+ public GetObjectsFromTSqlModelOperation(GetObjectsFromTSqlModelParams parameters, TSqlModel model)
+ {
+ Validate.IsNotNull("parameters", parameters);
+ Validate.IsNotNull("model", model);
+ this.Parameters = parameters;
+ this.Model = model;
+ }
+
+ ///
+ /// Get user defined top level type objects from model
+ ///
+ public TSqlObjectInfo[] GetObjectsFromTSqlModel()
+ {
+ try
+ {
+ var filters = Parameters.ObjectTypes.Select(t => MapType(t)).ToArray();
+ var objects = Model.GetObjects(DacQueryScopes.UserDefined, filters).ToList();
+
+ return objects.Select(o => new TSqlObjectInfo
+ {
+ Name = o.Name.ToString(),
+ ObjectType = o.ObjectType.Name,
+ ReferencedObjects = o.GetReferencedRelationshipInstances().ToList().Select(r => new TSqlObjectRelationship
+ {
+ Name = r.ObjectName.ToString(),
+ ObjectType = r.Object.ObjectType.Name,
+ RelationshipType = r.Relationship.Type.ToString(),
+ FromObjectName = r.FromObject.Name.ToString(),
+ FromObjectType = r.FromObject.ObjectType.Name
+ }).ToArray()
+ }).ToArray();
+ }
+ catch (Exception ex)
+ {
+ Logger.Error(new Exception(SR.GetUserDefinedObjectsFromModelFailed, ex));
+ throw;
+ }
+ }
+
+ ///
+ /// Class to represent the type of objects to query within the sql model
+ ///
+ public static ModelTypeClass MapType(string type)
+ {
+ switch (type.ToLower())
+ {
+ case "table":
+ return ModelSchema.Table;
+ case "view":
+ return ModelSchema.View;
+ default:
+ throw new ArgumentException(SR.UnsupportedModelType(type));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs
index ce8e7b81..3d79884b 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs
@@ -9429,6 +9429,14 @@ namespace Microsoft.SqlTools.ServiceLayer
}
}
+ public static string GetUserDefinedObjectsFromModelFailed
+ {
+ get
+ {
+ return Keys.GetString(Keys.GetUserDefinedObjectsFromModelFailed);
+ }
+ }
+
public static string ConnectionServiceListDbErrorNotConnected(string uri)
{
return Keys.GetString(Keys.ConnectionServiceListDbErrorNotConnected, uri);
@@ -9814,6 +9822,16 @@ namespace Microsoft.SqlTools.ServiceLayer
return Keys.GetString(Keys.ComputedColumnNeedToBePersistedInForeignKeyRuleDescription, columnName, foreignKeyName);
}
+ public static string SqlProjectModelNotFound(string projectUri)
+ {
+ return Keys.GetString(Keys.SqlProjectModelNotFound, projectUri);
+ }
+
+ public static string UnsupportedModelType(string type)
+ {
+ return Keys.GetString(Keys.UnsupportedModelType, type);
+ }
+
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Keys
{
@@ -13578,6 +13596,15 @@ namespace Microsoft.SqlTools.ServiceLayer
public const string ComputedColumnNeedToBePersistedInForeignKeyRuleDescription = "ComputedColumnNeedToBePersistedInForeignKeyRuleDescription";
+ public const string SqlProjectModelNotFound = "SqlProjectModelNotFound";
+
+
+ public const string UnsupportedModelType = "UnsupportedModelType";
+
+
+ public const string GetUserDefinedObjectsFromModelFailed = "GetUserDefinedObjectsFromModelFailed";
+
+
private Keys()
{ }
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx
index 21d4d2b4..ff660017 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx
+++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx
@@ -5206,4 +5206,18 @@ The Query Processor estimates that implementing the following index could improv
.
Parameters: 0 - columnName (string), 1 - foreignKeyName (string)
+
+ Could not find SQL model from project: {0}.
+ .
+ Parameters: 0 - projectUri (string)
+
+
+ Unsupported model type: {0}.
+ .
+ Parameters: 0 - type (string)
+
+
+ Failed to get user defined objects from model.
+
+
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings
index 466e7ad8..e179664b 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings
+++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings
@@ -2381,4 +2381,11 @@ ClusteredIndexCannotHaveFilterPredicateRuleDescription = Filter predicate is not
ColumnCanOnlyAppearOnceInIndexIncludedColumnsRuleDescription(string columnName, string indexName, int rowNumber) = Column with name '{0}' has already been included to the index '{1}'. Row number: {2}.
ColumnCannotDuplicateWitIndexKeyColumnsRuleDescription(string columnName, string indexName, int rowNumber) = Included column with name '{0}' has already been part of the index '{1}' and it cannot be included. Row number: {2}.
ComputedColumnNeedToBePersistedAndNotNullInPrimaryKeyRuleDescription(string columnName) = The computed column with name '{0}' has to be persisted and not nullable to be part of a primary key.
-ComputedColumnNeedToBePersistedInForeignKeyRuleDescription(string columnName, string foreignKeyName) = The computed column with name '{0}' has to be persisted to be part of the foreign key '{1}'.
\ No newline at end of file
+ComputedColumnNeedToBePersistedInForeignKeyRuleDescription(string columnName, string foreignKeyName) = The computed column with name '{0}' has to be persisted to be part of the foreign key '{1}'.
+
+############################################################################
+# TSql Model
+
+SqlProjectModelNotFound(string projectUri) = Could not find SQL model from project: {0}.
+UnsupportedModelType(string type) = Unsupported model type: {0}.
+GetUserDefinedObjectsFromModelFailed = Failed to get user defined objects from model.
\ No newline at end of file
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf
index 2611c891..f3235e5a 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf
+++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf
@@ -6331,6 +6331,23 @@ The Query Processor estimates that implementing the following index could improv
Dropped Ledger Views
+
+ Could not find SQL model from project: {0}.
+ Could not find SQL model from project: {0}.
+ .
+ Parameters: 0 - projectUri (string)
+
+
+ Unsupported model type: {0}.
+ Unsupported model type: {0}.
+ .
+ Parameters: 0 - type (string)
+
+
+ Failed to get user defined objects from model.
+ Failed to get user defined objects from model.
+
+ The computed column with name '{0}' has to be persisted and not nullable to be part of a primary key.The computed column with name '{0}' has to be persisted and not nullable to be part of a primary key.
diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DacFx/DacFxServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DacFx/DacFxServiceTests.cs
index c460e088..d3791d02 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DacFx/DacFxServiceTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DacFx/DacFxServiceTests.cs
@@ -1057,4 +1057,57 @@ public class TSqlModelRequestTests
await service.HandleGenerateTSqlModelRequest(generateTSqlScriptParams, requestContext.Object);
Assert.That(service.projectModels.Value, Contains.Key(generateTSqlScriptParams.ProjectUri), "Model was not stored under project uri");
}
+
+ ///
+ /// Verify the get objects TSql Model handle
+ ///
+ [Test]
+ public async Task VerifyGetObjectsFromTSqlModelHandle()
+ {
+ string sqlTable1DefinitionPath = Path.Join(TSqlModelTestFolder, "table1.sql");
+ string sqlTable2DefinitionPath = Path.Join(TSqlModelTestFolder, "table2.sql");
+ string view1DefinitionPath = Path.Join(TSqlModelTestFolder, "view1.sql");
+ const string table1 = @"CREATE TABLE [dbo].[table1]
+ (
+ [ID] INT NOT NULL PRIMARY KEY,
+ )";
+ const string table2 = @"CREATE TABLE [dbo].[table2]
+ (
+ [ID] INT NOT NULL PRIMARY KEY,
+ )";
+ const string view1 = "CREATE VIEW [dbo].[view1] AS SELECT dbo.table1.* FROM dbo.table1";
+ // create sql file
+ File.WriteAllText(sqlTable1DefinitionPath, table1);
+ File.WriteAllText(sqlTable2DefinitionPath, table2);
+ File.WriteAllText(view1DefinitionPath, view1);
+
+ var generateTSqlScriptParams = new GenerateTSqlModelParams
+ {
+ ProjectUri = Path.Join(TSqlModelTestFolder, "test.sqlproj"),
+ ModelTargetVersion = "Sql160",
+ FilePaths = new[] { sqlTable1DefinitionPath, sqlTable2DefinitionPath }
+ };
+
+ GenerateTSqlModelOperation op = new GenerateTSqlModelOperation(generateTSqlScriptParams);
+ var model = op.GenerateTSqlModel();
+
+ service.projectModels.Value.TryAdd(generateTSqlScriptParams.ProjectUri, model);
+
+ var getObjectsParams = new GetObjectsFromTSqlModelParams
+ {
+ ProjectUri = Path.Join(TSqlModelTestFolder, "test.sqlproj"),
+ ObjectTypes = new[] { "Table" }
+ };
+
+ var requestContext = new Mock>();
+ var actualResponse = new List();
+ requestContext.Setup(x => x.SendResult(It.IsAny()))
+ .Callback(actual => actualResponse = actual.ToList())
+ .Returns(Task.CompletedTask);
+ await service.HandleGetObjectsFromTSqlModelRequest(getObjectsParams, requestContext.Object);
+
+ Assert.IsNotNull(actualResponse);
+ Assert.AreEqual(actualResponse.Count, 2);
+ CollectionAssert.AreEquivalent(actualResponse.Select(o => o.Name), new[] { "[dbo].[table1]", "[dbo].[table2]" }, "Table names do not match");
+ }
}