Added new Kusto ServiceLayer (#1009)

* Copy smoModel some rename

* Copy entire service layer

* Building copy

* Fixing some references

* Launch profile

* Resolve namespace issues

* Compiling tests. Correct manifest.

* Fixing localization resources

* ReliableKustoClient

* Some trimming of extra code and Kusto code

* Kusto client creation in bindingContent

* Removing Smo and new Kusto classes

* More trimming

* Kusto schema hookup

* Solidying DataSource abstraction

* Solidifying further

* Latest refatoring

* More refactoring

* Building and launching Kusto service layer

* Working model which enumerates databases

* Refactoring to pass IDataSource to all tree nodes

* Removing some dependencies on the context

* Working with tables and schema

* Comment checkin

* Refactoring to give out select script

* Query created and sent back to ADS

* Fix query generation

* Fix listing of databases

* Tunneling the query through.

* Successful query execution

* Return only results table

* Deleting Cms

* Delete DacFx

* Delete SchemaCompare and TaskServices

* Change build definition to not stop at launch

* Fix error after merge

* Save Kusto results in different formats (#935)

* save results as csv etc

* some fixes

Co-authored-by: Monica Gupta <mogupt@microsoft.com>

* 2407 Added OrderBy clause in KustoDataSource > GetDatabaseMetaData and GetColumnMetadata (#959)

* 2405 Defaulted Options when setting ServerInfo in ConnectionService > GetConnectionCompleteParams (#965)

* 2747 Fixed IsUnknownType error for Kusto (#989)

* 2747 Removed unused directives in Kusto > DbColumnWrapper. Refactored IsUnknownType to handle null DataTypeName

* 2747 Reverted IsUnknownType change in DbColumnWrapper. Changed DataTypeName to get calue from ColumnType. Refactored SafeGetValue to type check before hard casting to reduce case exceptions.

* Added EmbeddedResourceUseDependentUponConvention to Microsoft.Kusto.ServiceLayer.csproj. Also renamed DACfx to match Microsoft.SqlTools.ServiceLayer. Added to compile Exclude="**/obj/**/*.cs"

* Srahman cleanup sql code (#992)

* Removed Management and Security Service Code.

* Remove FileBrowser service

* Comment why we are using SqlServer library

* Remove SQL specific type definitions

* clean up formatter service (#996)

Co-authored-by: Monica Gupta <mogupt@microsoft.com>

* Code clean up and Kusto intellisense (#994)

* Code clean up and Kusto intellisense

* Addressed few comments

* Addressed few comments

* addressed comments

Co-authored-by: Monica Gupta <mogupt@microsoft.com>

* Return multiple tables for Kusto

* Changes required for Kusto manage dashboard (#1039)

* Changes required for manage dashboard

* Addressed comments

Co-authored-by: Monica Gupta <mogupt@microsoft.com>

* 2728 Kusto function support (#1038)

* loc update (#914)

* loc update

* loc updates

* 2728 moved ColumnInfo and KustoResultsReader to separate files. Added Folder and Function to TreeNode.cs

* 2728 Added FunctionInfo. Added Folder to ColumnInfo. Removed partial class from KustoResultsReader. Set Function.IsAlwaysLeaf=true in TreeNode.cs. In KustoDataSource changed tableMetadata type to TableMetaData. Added folder and function dictionaries. Refactored GetSchema function. Renamed GenerateColumnMetadataKey to GenerateMetadataKey

* 2728 Added FunctionInfo. Added Folder to ColumnInfo. Removed partial class from KustoResultsReader. Set Function.IsAlwaysLeaf=true in TreeNode.cs. In KustoDataSource changed tableMetadata type to TableMetaData. Added folder and function dictionaries. Refactored GetSchema function. Renamed GenerateColumnMetadataKey to GenerateMetadataKey

* 2728 Created new SqlConnection within using block. Refactored KustoDataSource > columnmetadata to sort on get instead of insert.

* 2728 Added GetFunctionInfo function to KustoDataSource.

* 2728 Reverted change to Microsoft.Kusto.ServiceLayer.csproj from merge

* 2728 Reverted change to SqlTools.ServiceLayer\Localization\transXliff

* 2728 Reverted change to sr.de.xlf and sr.zh-hans.xlf

* 2728 Refactored KustoDataSource Function folders to support subfolders

* 2728 Refactored KustoDataSource to use urn for folders, functions, and tables instead of name.

* Merge remote-tracking branch 'origin/main' into feature-ADE

# Conflicts:
#	Packages.props

* 2728 Moved metadata files into Metadata subdirectory. Added GenerateAlterFunction to IDataSource and DataSourceBase.

* 2728 Added summary information to SafeAdd in SystemExtensions. Renamed local variable in SetTableMetadata

* 2728 Moved SafeAdd from SystemExtensions to KustoQueryUtils. Added check when getting database schema to return existing records before querying again. Added AddRange function to KustoQueryUtils. Created SetFolderMetadataForFunctions method.

* 2728 Added DatabaseKeyPrefix to only return tables to a database for the dashboard. Added logic to store all database tables within the tableMetadata dictionary for the dashboard.

* 2728 Created TableInfo and moved info objects into Models directory. Refactored KustoDataSource to lazy load columns for tables. Refactored logic to load tables using cslschema instead of schema.

* 2728 Renamed LoadColumnSchema to GetTableSchema to be consistent.

Co-authored-by: khoiph1 <khoiph@microsoft.com>

* Addressed comments

Co-authored-by: Shafiq Rahman <srahman@microsoft.com>
Co-authored-by: Monica Gupta <mogupt@microsoft.com>
Co-authored-by: Justin M <63619224+JustinMDotNet@users.noreply.github.com>
Co-authored-by: rkselfhost <rkselfhost@outlook.com>
Co-authored-by: khoiph1 <khoiph@microsoft.com>
This commit is contained in:
Monica Gupta
2020-08-12 15:34:38 -07:00
committed by GitHub
parent d2f5bfaa16
commit 148b6e398d
276 changed files with 75983 additions and 1 deletions

View File

@@ -0,0 +1,52 @@
// This file was generated by a T4 Template. Do not modify directly, instead update the SmoQueryModelDefinition.xml file
// and re-run the T4 template. This can be done in Visual Studio by right-click in and choosing "Run Custom Tool",
// or from the command-line on any platform by running "build.cmd -Target=CodeGen" or "build.sh -Target=CodeGen".
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel
{
// TODOKusto: Do we need the Querier. This has been short circuited in smoChildFactoryBase. There is no caller to the "Query" function.
[Export(typeof(DataSourceQuerier))]
internal partial class DatabaseQuerier: DataSourceQuerier
{
public override IEnumerable<DataSourceObjectMetadata> Query(QueryContext context, string filter, bool refresh, IEnumerable<string> extraProperties)
{
if (context.DataSource != null)
{
return context.DataSource.GetChildObjects(context.ParentObjectMetadata);
}
return Enumerable.Empty<DataSourceObjectMetadata>();
}
}
[Export(typeof(DataSourceQuerier))]
internal partial class TableQuerier: DataSourceQuerier
{
public override IEnumerable<DataSourceObjectMetadata> Query(QueryContext context, string filter, bool refresh, IEnumerable<string> extraProperties)
{
if (context.ParentObjectMetadata != null)
{
return context.DataSource.GetChildObjects(context.ParentObjectMetadata);
}
return Enumerable.Empty<DataSourceObjectMetadata>();
}
}
[Export(typeof(DataSourceQuerier))]
internal partial class ColumnQuerier: DataSourceQuerier
{
public override IEnumerable<DataSourceObjectMetadata> Query(QueryContext context, string filter, bool refresh, IEnumerable<string> extraProperties)
{
if (context.ParentObjectMetadata != null)
{
return context.DataSource.GetChildObjects(context.ParentObjectMetadata);
}
return Enumerable.Empty<DataSourceObjectMetadata>();
}
}
}

View File

@@ -0,0 +1,39 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.Kusto.ServiceLayer.DataSource;
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel
{
/// <summary>
/// Represents a folder node in the tree
/// </summary>
public class FolderNode : DataSourceTreeNode
{
public FolderNode(IDataSource dataSource, DataSourceObjectMetadata objectMetadata)
: base(dataSource, objectMetadata)
{
}
/// <summary>
/// For folders, this copies the context of its parent if available
/// </summary>
/// <returns></returns>
public override object GetContext()
{
return Parent?.GetContext();
}
/// <summary>
/// For folders, searches for its parent's SMO object rather than copying for itself
/// </summary>
/// <returns><see cref="KustoMetadata"/> from this parent's parent, or null if not found</returns>
public override DataSourceObjectMetadata GetParentObjectMetadata()
{
return ParentAs<DataSourceTreeNode>()?.GetParentObjectMetadata();
}
}
}

View File

@@ -0,0 +1,268 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;
namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel
{
public class NodePathGenerator
{
private static ServerExplorerTree TreeRoot { get; set; }
private static Dictionary<string, HashSet<Node>> NodeTypeDictionary { get; set; }
internal static void Initialize()
{
if (TreeRoot != null)
{
return;
}
var assembly = typeof(ObjectExplorerService).Assembly;
var resource = assembly.GetManifestResourceStream("Microsoft.Kusto.ServiceLayer.ObjectExplorer.SmoModel.TreeNodeDefinition.xml");
var serializer = new XmlSerializer(typeof(ServerExplorerTree));
NodeTypeDictionary = new Dictionary<string, HashSet<Node>>();
using (var reader = new StreamReader(resource))
{
TreeRoot = (ServerExplorerTree)serializer.Deserialize(reader);
}
foreach (var node in TreeRoot.Nodes)
{
var containedType = node.ContainedType();
if (containedType != null && node.Label() != string.Empty)
{
if (!NodeTypeDictionary.ContainsKey(containedType))
{
NodeTypeDictionary.Add(containedType, new HashSet<Node>());
}
NodeTypeDictionary.GetValueOrDefault(containedType).Add(node);
}
}
var serverNode = TreeRoot.Nodes.FirstOrDefault(node => node.Name == "Server");
var serverSet = new HashSet<Node>();
serverSet.Add(serverNode);
NodeTypeDictionary.Add("Server", serverSet);
}
internal static HashSet<string> FindNodePaths(ObjectExplorerService.ObjectExplorerSession objectExplorerSession, string typeName, string schema, string name, string databaseName, List<string> parentNames = null)
{
if (TreeRoot == null)
{
Initialize();
}
var returnSet = new HashSet<string>();
var matchingNodes = NodeTypeDictionary.GetValueOrDefault(typeName);
if (matchingNodes == null)
{
return returnSet;
}
var path = name;
if (schema != null)
{
path = schema + "." + path;
}
if (path == null)
{
path = "";
}
foreach (var matchingNode in matchingNodes)
{
var paths = GenerateNodePath(objectExplorerSession, matchingNode, databaseName, parentNames, path);
foreach (var newPath in paths)
{
returnSet.Add(newPath);
}
}
return returnSet;
}
private static HashSet<string> GenerateNodePath(ObjectExplorerService.ObjectExplorerSession objectExplorerSession, Node currentNode, string databaseName, List<string> parentNames, string path)
{
if (parentNames != null)
{
parentNames = parentNames.ToList();
}
if (currentNode.Name == "Server" || (currentNode.Name == "Database" && objectExplorerSession.Root.NodeType == "Database"))
{
var serverRoot = objectExplorerSession.Root;
if (objectExplorerSession.Root.NodeType == "Database")
{
serverRoot = objectExplorerSession.Root.Parent;
path = objectExplorerSession.Root.NodeValue + (path.Length > 0 ? ("/" + path) : "");
}
path = serverRoot.NodeValue + (path.Length > 0 ? ("/" + path) : "");
var returnSet = new HashSet<string>();
returnSet.Add(path);
return returnSet;
}
var currentLabel = currentNode.Label();
if (currentLabel != string.Empty)
{
path = currentLabel + "/" + path;
var returnSet = new HashSet<string>();
foreach (var parent in currentNode.ParentNodes())
{
var paths = GenerateNodePath(objectExplorerSession, parent, databaseName, parentNames, path);
foreach (var newPath in paths)
{
returnSet.Add(newPath);
}
}
return returnSet;
}
else
{
var returnSet = new HashSet<string>();
if (currentNode.ContainedType() == "Database")
{
path = databaseName + "/" + path;
}
else if (parentNames != null && parentNames.Count > 0)
{
var parentName = parentNames.Last();
parentNames.RemoveAt(parentNames.Count - 1);
path = parentName + "/" + path;
}
else
{
return returnSet;
}
foreach (var parentNode in currentNode.ParentNodes())
{
var newPaths = GenerateNodePath(objectExplorerSession, parentNode, databaseName, parentNames, path);
foreach (var newPath in newPaths)
{
returnSet.Add(newPath);
}
}
return returnSet;
}
}
[XmlRoot("ServerExplorerTree")]
public class ServerExplorerTree
{
[XmlElement("Node", typeof(Node))]
public List<Node> Nodes { get; set; }
public Node GetNode(string name)
{
foreach (var node in this.Nodes)
{
if (node.Name == name)
{
return node;
}
}
return null;
}
}
public class Node
{
[XmlAttribute]
public string Name { get; set; }
[XmlAttribute]
public string LocLabel { get; set; }
[XmlAttribute]
public string TreeNode { get; set; }
[XmlAttribute]
public string NodeType { get; set; }
[XmlElement("Child", typeof(Child))]
public List<Child> Children { get; set; }
public HashSet<Node> ChildFolders()
{
var childSet = new HashSet<Node>();
foreach (var child in this.Children)
{
var node = TreeRoot.GetNode(child.Name);
if (node != null)
{
childSet.Add(node);
}
}
return childSet;
}
public string ContainedType()
{
if (this.TreeNode != null)
{
return this.TreeNode.Replace("TreeNode", "");
}
else if (this.NodeType != null)
{
return this.NodeType;
}
return null;
}
public Node ContainedObject()
{
var containedType = this.ContainedType();
if (containedType == null)
{
return null;
}
var containedNode = TreeRoot.GetNode(containedType);
if (containedNode == this)
{
return null;
}
return containedNode;
}
public string Label()
{
if (this.LocLabel.StartsWith("SR."))
{
return SR.Keys.GetString(this.LocLabel.Remove(0, 3));
}
return string.Empty;
}
public HashSet<Node> ParentNodes()
{
var parentNodes = new HashSet<Node>();
foreach (var node in TreeRoot.Nodes)
{
if (this != node && (node.ContainedType() == this.Name || node.Children.Any(child => child.Name == this.Name)))
{
parentNodes.Add(node);
}
}
return parentNodes;
}
}
public class Child
{
[XmlAttribute]
public string Name { get; set; }
}
}
}

View File

@@ -0,0 +1,129 @@
//
// 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.Diagnostics;
using System.Globalization;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlTools.Extensibility;
using Microsoft.Kusto.ServiceLayer.Connection.Contracts;
using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes;
using Microsoft.Kusto.ServiceLayer.Utility;
using Microsoft.Kusto.ServiceLayer.DataSource;
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
using Microsoft.SqlTools.Utility;
namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel
{
/// <summary>
/// Server node implementation
/// </summary>
public class ServerNode : TreeNode
{
private ConnectionSummary connectionSummary;
private ServerInfo serverInfo;
private Lazy<QueryContext> context;
private ServerConnection serverConnection;
public ServerNode(ConnectionCompleteParams connInfo, IMultiServiceProvider serviceProvider, ServerConnection serverConnection, IDataSource dataSource, DataSourceObjectMetadata objectMetadata)
: base(dataSource, objectMetadata)
{
Validate.IsNotNull(nameof(connInfo), connInfo);
Validate.IsNotNull("connInfo.ConnectionSummary", connInfo.ConnectionSummary);
Validate.IsNotNull(nameof(serviceProvider), serviceProvider);
this.connectionSummary = connInfo.ConnectionSummary;
this.serverInfo = connInfo.ServerInfo;
this.context = new Lazy<QueryContext>(() => CreateContext(serviceProvider));
this.serverConnection = serverConnection;
NodeValue = connectionSummary.ServerName;
IsAlwaysLeaf = false;
NodeType = NodeTypes.Server.ToString();
NodeTypeId = NodeTypes.Server;
Label = GetConnectionLabel();
}
/// <summary>
/// Returns the label to display to the user.
/// </summary>
internal string GetConnectionLabel()
{
string userName = connectionSummary.UserName;
// TODO Domain and username is not yet supported on .Net Core.
// Consider passing as an input from the extension where this can be queried
//if (string.IsNullOrWhiteSpace(userName))
//{
// userName = Environment.UserDomainName + @"\" + Environment.UserName;
//}
// TODO Consider adding IsAuthenticatingDatabaseMaster check in the code and
// referencing result here
if (!DatabaseUtils.IsSystemDatabaseConnection(connectionSummary.DatabaseName))
{
// We either have an azure with a database specified or a Denali database using a contained user
if (string.IsNullOrWhiteSpace(userName))
{
userName = connectionSummary.DatabaseName;
}
else
{
userName += ", " + connectionSummary.DatabaseName;
}
}
string label;
if (string.IsNullOrWhiteSpace(userName))
{
label = string.Format(
CultureInfo.InvariantCulture,
"{0} ({1} {2})",
connectionSummary.ServerName,
"SQL Server",
serverInfo.ServerVersion);
}
else
{
label = string.Format(
CultureInfo.InvariantCulture,
"{0} ({1} {2} - {3})",
connectionSummary.ServerName,
"SQL Server",
serverInfo.ServerVersion,
userName);
}
return label;
}
private QueryContext CreateContext(IMultiServiceProvider serviceProvider)
{
string exceptionMessage;
try
{
return new QueryContext(DataSource, serviceProvider)
{
ParentObjectMetadata = this.ObjectMetadata
};
}
catch (Exception ex)
{
exceptionMessage = ex.Message;
}
Logger.Write(TraceEventType.Error, "Exception at ServerNode.CreateContext() : " + exceptionMessage);
this.ErrorStateMessage = string.Format(SR.TreeNodeError, exceptionMessage);
return null;
}
public override object GetContext()
{
return context.Value;
}
}
}

View File

@@ -0,0 +1,178 @@
//
// 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.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes;
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel
{
public class DataSourceChildFactoryBase : ChildFactory
{
private IEnumerable<NodeSmoProperty> smoProperties;
public override IEnumerable<string> ApplicableParents()
{
return null;
}
public override IEnumerable<TreeNode> Expand(TreeNode parent, bool refresh, string name, bool includeSystemObjects, CancellationToken cancellationToken)
{
throw new NotImplementedException(); // Moved to TreeNode.cs
}
private bool ShouldFilterNode(TreeNode childNode, ValidForFlag validForFlag)
{
bool filterTheNode = false;
return filterTheNode;
}
private string GetProperyFilter(IEnumerable<NodeFilter> filters, Type querierType, ValidForFlag validForFlag)
{
string filter = string.Empty;
if (filters != null)
{
var filtersToApply = filters.Where(f => f.CanApplyFilter(querierType, validForFlag)).ToList();
filter = string.Empty;
if (filtersToApply.Any())
{
filter = NodeFilter.ConcatProperties(filtersToApply);
}
}
return filter;
}
private bool IsCompatibleQuerier(DataSourceQuerier querier)
{
if (ChildQuerierTypes == null)
{
return false;
}
Type actualType = querier.GetType();
foreach (Type childType in ChildQuerierTypes)
{
// We will accept any querier that is compatible with the listed querier type
if (childType.IsAssignableFrom(actualType))
{
return true;
}
}
return false;
}
public override bool CanCreateChild(TreeNode parent, object context)
{
return false;
}
public override TreeNode CreateChild(TreeNode parent, DataSourceObjectMetadata childMetadata)
{
throw new NotImplementedException();
}
protected virtual void InitializeChild(TreeNode parent, TreeNode child, object context)
{
DataSourceObjectMetadata objectMetadata = context as DataSourceObjectMetadata;
if (objectMetadata == null)
{
Debug.WriteLine("context is not a DataSourceObjectMetadata type: " + context.GetType());
}
else
{
smoProperties = SmoProperties;
DataSourceTreeNode childAsMeItem = (DataSourceTreeNode)child;
childAsMeItem.CacheInfoFromModel(objectMetadata);
QueryContext oeContext = parent.GetContextAs<QueryContext>();
// If node has custom name, replaced it with the name already set
string customizedName = GetNodeCustomName(context, oeContext);
if (!string.IsNullOrEmpty(customizedName))
{
childAsMeItem.NodeValue = customizedName;
childAsMeItem.NodePathName = GetNodePathName(context);
}
childAsMeItem.NodeSubType = GetNodeSubType(context, oeContext);
childAsMeItem.NodeStatus = GetNodeStatus(context, oeContext);
}
}
internal virtual Type[] ChildQuerierTypes
{
get
{
return null;
}
}
public override IEnumerable<NodeFilter> Filters
{
get
{
return Enumerable.Empty<NodeFilter>();
}
}
public override IEnumerable<NodeSmoProperty> SmoProperties
{
get
{
return Enumerable.Empty<NodeSmoProperty>();
}
}
internal IEnumerable<NodeSmoProperty> CachedSmoProperties
{
get
{
return smoProperties == null ? SmoProperties : smoProperties;
}
}
/// <summary>
/// Returns true if any final validation of the object to be added passes, and false
/// if validation fails. This provides a chance to filter specific items out of a list
/// </summary>
/// <param name="parent"></param>
/// <param name="contextObject"></param>
/// <returns>boolean</returns>
public virtual bool PassesFinalFilters(TreeNode parent, object context)
{
return true;
}
public override string GetNodeSubType(object objectMetadata, QueryContext oeContext)
{
return string.Empty;
}
public override string GetNodeStatus(object objectMetadata, QueryContext oeContext)
{
return string.Empty;
}
public static bool IsPropertySupported(string propertyName, QueryContext context, DataSourceObjectMetadata objectMetadata, IEnumerable<NodeSmoProperty> supportedProperties)
{
return true;
}
public override string GetNodeCustomName(object objectMetadata, QueryContext oeContext)
{
return (objectMetadata as DataSourceObjectMetadata).PrettyName;
}
public override string GetNodePathName(object objectMetadata)
{
return (objectMetadata as DataSourceObjectMetadata).Urn;
}
}
}

View File

@@ -0,0 +1,57 @@
//
// 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.Collections;
using System.Collections.Generic;
using Microsoft.SqlServer.Management.Smo;
namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel
{
/// <summary>
/// Wrapper to convert non-generic Smo enumerables to generic enumerable types for easier use in
/// </summary>
/// <typeparam name="T"></typeparam>
public class SmoCollectionWrapper<T> : IEnumerable<T>
where T : SqlSmoObject
{
private SmoCollectionBase collection;
/// <summary>
/// Constructor which accepts a <see cref="SmoCollectionBase"/> containing the objects
/// to wrap
/// </summary>
/// <param name="collection"><see cref="SmoCollectionBase"/> or null if none were set</param>
public SmoCollectionWrapper(SmoCollectionBase collection)
{
this.collection = collection;
}
/// <summary>
/// <see cref="IEnumerable{T}.GetEnumerator"/>
/// </summary>
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
{
if (collection == null)
{
yield break;
}
foreach(Object obj in collection)
{
yield return (T)obj;
}
}
/// <summary>
/// <see cref="IEnumerable.GetEnumerator"/>
/// </summary>
/// <returns></returns>
IEnumerator IEnumerable.GetEnumerator()
{
return collection?.GetEnumerator();
}
}
}

View File

@@ -0,0 +1,356 @@
//
// 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.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes;
using Microsoft.SqlTools.Utility;
namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel
{
/// <summary>
/// Custom name for Columns
/// </summary>
internal partial class ColumnsChildFactory : DataSourceChildFactoryBase
{
public override string GetNodeCustomName(object objectMetadata, QueryContext oeContext)
{
return SmoColumnCustomNodeHelper.CalculateCustomLabel(objectMetadata, oeContext);
}
private readonly Lazy<List<NodeSmoProperty>> smoPropertiesLazy = new Lazy<List<NodeSmoProperty>>(() => new List<NodeSmoProperty>
{
new NodeSmoProperty
{
Name = "Computed",
ValidFor = ValidForFlag.All
},
new NodeSmoProperty
{
Name = "IsColumnSet",
ValidFor = ValidForFlag.All
},
new NodeSmoProperty
{
Name = "Nullable",
ValidFor = ValidForFlag.All
},
new NodeSmoProperty
{
Name = "DataType",
ValidFor = ValidForFlag.All
},
new NodeSmoProperty
{
Name = "InPrimaryKey",
ValidFor = ValidForFlag.All
},
new NodeSmoProperty
{
Name = "IsForeignKey",
ValidFor = ValidForFlag.All
},
new NodeSmoProperty
{
Name = "SystemType",
ValidFor = ValidForFlag.All
},
new NodeSmoProperty
{
Name = "Length",
ValidFor = ValidForFlag.All
},
new NodeSmoProperty
{
Name = "NumericPrecision",
ValidFor = ValidForFlag.All
},
new NodeSmoProperty
{
Name = "NumericScale",
ValidFor = ValidForFlag.All
},
new NodeSmoProperty
{
Name = "XmlSchemaNamespaceSchema",
ValidFor = ValidForFlag.NotSqlDw
},
new NodeSmoProperty
{
Name = "XmlSchemaNamespace",
ValidFor = ValidForFlag.NotSqlDw
},
new NodeSmoProperty
{
Name = "XmlDocumentConstraint",
ValidFor = ValidForFlag.NotSqlDw
}
});
public override IEnumerable<NodeSmoProperty> SmoProperties => smoPropertiesLazy.Value;
}
/// <summary>
/// Custom name for UserDefinedTableTypeColumn
/// </summary>
internal partial class UserDefinedTableTypeColumnsChildFactory : DataSourceChildFactoryBase
{
public override string GetNodeCustomName(object objectMetadata, QueryContext oeContext)
{
return SmoColumnCustomNodeHelper.CalculateCustomLabel(objectMetadata, oeContext);
}
}
static class SmoColumnCustomNodeHelper
{
private const string SimpleColumnLabelWithType = "{0} ({1}{2}, {3})";
private const string SimpleColumnLabelWithoutType = "{0} ({1})";
private const string SimpleColumnLabelWithTypeAndKeyString = "{0} ({1}, {2}, {3})";
internal static string CalculateCustomLabel(object context, QueryContext oeContext)
{
UserDefinedDataTypeCollection uddts = null; // TODOKusto: Remove. Not needed.
Column column = context as Column;
if(column != null)
{
return GetCustomizedLabel(column, uddts);
}
return string.Empty;
}
private static string GetCustomizedLabel(Column column, UserDefinedDataTypeCollection uddts)
{
try
{
if (column.Computed)
{
return GetComputedColumnLabel(column, uddts);
}
else if (column.IsColumnSet)
{
return GetColumnSetLabel(column, uddts);
}
else
{
return GetSimpleColumnLabel(column, uddts);
}
}
catch(Exception ex)
{
Logger.Write(TraceEventType.Error, $"Failed to get customized column name. error:{ex.Message}");
}
return string.Empty;
}
private static string GetTypeSpecifierLabel(DataType dataType, UserDefinedDataTypeCollection uddts)
{
string typeName = string.Empty;
if (dataType != null)
{
// typeSpecifier might still be in a resolve candidate status. If so then the
// name might be null. Don't ask for the type specifier name in this case.
typeName = dataType.Name;
// This may return [dbo].[MyType], but for the purposes of display we only want MyType
if (!string.IsNullOrWhiteSpace(typeName) &&
typeName.EndsWith("]", StringComparison.Ordinal))
{
int nameStart = typeName.LastIndexOf('[');
typeName = typeName.Substring(nameStart + 1, typeName.Length - nameStart - 2);
}
if(dataType.SqlDataType == SqlDataType.UserDefinedDataType && uddts != null)
{
foreach (UserDefinedDataType item in uddts)
{
if(item.Name == dataType.Name)
{
typeName += $"({item.SystemType})";
break;
}
}
}
// These types supports detailed information
switch (dataType.SqlDataType)
{
case SqlDataType.Char:
case SqlDataType.NChar:
case SqlDataType.Binary:
case SqlDataType.VarChar:
case SqlDataType.NVarChar:
case SqlDataType.VarBinary:
typeName += $"({dataType.MaximumLength})";
break;
case SqlDataType.Numeric:
case SqlDataType.Decimal:
typeName += $"({dataType.NumericPrecision},{dataType.NumericScale})";
break;
case SqlDataType.DateTime2:
case SqlDataType.Time:
case SqlDataType.DateTimeOffset:
typeName += $"({dataType.NumericScale})";
break;
case SqlDataType.VarBinaryMax:
case SqlDataType.NVarCharMax:
case SqlDataType.VarCharMax:
typeName += "(max)";
break;
}
}
return typeName;
}
private static string GetKeyString(Column column)
{
// Get if it's a PK or FK (or both)
// Here's how it could be both...notice t2c1 is both a primary and foreign key
//
// Create table t1 (t1c1 int, t1c2 int not null primary key)
// Create table t2 (t2c1 int primary key, t2c2 int not null)
// Alter table t2 add FOREIGN KEY(t2c1) references t1(t1c2)
//
string keyString = null;
if (column.InPrimaryKey)
keyString = "PK";
if (column.IsForeignKey)
{
keyString = (keyString == null) ? "FK" :
"PK, FK";
}
return keyString;
}
private static string GetColumnSetLabel(Column column, UserDefinedDataTypeCollection uddts)
{
// This is the simple name
string label = column.Name;
// Get the column type
string columnType = GetTypeSpecifierLabel(column.DataType, uddts);
string keyString = GetKeyString(column);
if (keyString != null && !string.IsNullOrWhiteSpace(columnType))
{
return string.Format(CultureInfo.InvariantCulture,
SR.SchemaHierarchy_ColumnSetLabelWithTypeAndKeyString,
label,
keyString,
columnType,
SR.SchemaHierarchy_NullColumn_Label);
}
if (!string.IsNullOrWhiteSpace(columnType))
{
return string.Format(CultureInfo.InvariantCulture,
SR.SchemaHierarchy_ColumnSetLabelWithType,
label,
keyString,
columnType,
SR.SchemaHierarchy_NullColumn_Label);
}
return string.Format(CultureInfo.InvariantCulture,
SR.SchemaHierarchy_ColumnSetLabelWithoutType,
label,
SR.SchemaHierarchy_NullColumn_Label);
}
private static string GetSimpleColumnLabel(Column column, UserDefinedDataTypeCollection uddts)
{
// This is the simple name
string label = column.Name;
// Get the nullability
string isNullable = column.Nullable ? SR.SchemaHierarchy_NullColumn_Label : SR.SchemaHierarchy_NotNullColumn_Label;
// Get the column type
string columnType = GetTypeSpecifierLabel(column.DataType, uddts);
string keyString = GetKeyString(column);
if (keyString != null && !string.IsNullOrWhiteSpace(columnType))
{
return string.Format(CultureInfo.InvariantCulture,
SimpleColumnLabelWithTypeAndKeyString,
label,
keyString,
columnType,
isNullable);
}
if (!string.IsNullOrWhiteSpace(columnType))
{
return string.Format(CultureInfo.InvariantCulture,
SimpleColumnLabelWithType,
label,
keyString,
columnType,
isNullable);
}
return string.Format(CultureInfo.InvariantCulture,
SimpleColumnLabelWithoutType,
label,
isNullable);
}
private static string GetComputedColumnLabel(Column column, UserDefinedDataTypeCollection uddts)
{
string columnType = null;
// Display the type name as fully qualified
string label = column.Name;
// Get the nullability
string isNullable = column.Nullable ? SR.SchemaHierarchy_NullColumn_Label : SR.SchemaHierarchy_NotNullColumn_Label;
string keyString = GetKeyString(column);
// Get the column type
columnType = GetTypeSpecifierLabel(column.DataType, uddts);
if (!string.IsNullOrWhiteSpace(columnType))
{
if (column.Parent is View)
{
// View columns are always computed, but SSMS shows then as never computed, so
// treat them as simple columns
return string.Format(CultureInfo.InvariantCulture,
SimpleColumnLabelWithType,
label,
keyString,
columnType,
isNullable);
}
return string.Format(CultureInfo.InvariantCulture,
SR.SchemaHierarchy_ComputedColumnLabelWithType,
label,
keyString,
columnType,
isNullable);
}
if (column.Parent is View)
{
return string.Format(CultureInfo.InvariantCulture,
SimpleColumnLabelWithoutType,
label,
keyString);
}
return string.Format(CultureInfo.InvariantCulture,
SR.SchemaHierarchy_ComputedColumnLabelWithoutType,
label,
keyString);
}
}
}

View File

@@ -0,0 +1,55 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Collections.Generic;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes;
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel
{
/// <summary>
/// Status for databases
/// </summary>
internal partial class DatabasesChildFactory : DataSourceChildFactoryBase
{
public override string GetNodeStatus(object objectMetadata, QueryContext oeContext)
{
return DatabasesCustomNodeHelper.GetStatus(objectMetadata, oeContext, CachedSmoProperties);
}
protected override void InitializeChild(TreeNode parent, TreeNode child, object context)
{
base.InitializeChild(parent, child, context);
var dsTreeNode = child as DataSourceTreeNode;
if (dsTreeNode != null && dsTreeNode.ObjectMetadata != null
&& DatabasesCustomNodeHelper.GetDatabaseIsUnavailable(dsTreeNode.ObjectMetadata, parent.GetContextAs<QueryContext>(), CachedSmoProperties))
{
child.IsAlwaysLeaf = true;
}
}
}
internal static class DatabasesCustomNodeHelper
{
private static readonly DatabaseStatus[] UnavailableDatabaseStatuses = { DatabaseStatus.Inaccessible, DatabaseStatus.Offline, DatabaseStatus.Recovering,
DatabaseStatus.RecoveryPending, DatabaseStatus.Restoring, DatabaseStatus.Suspect, DatabaseStatus.Shutdown };
internal static bool GetDatabaseIsUnavailable(object objectMetadata, QueryContext oeContext, IEnumerable<NodeSmoProperty> supportedProperties)
{
if(oeContext.DataSource == null) return false; // Assume that database is available
return !oeContext.DataSource.Exists(objectMetadata as DataSourceObjectMetadata);
}
internal static string GetStatus(object objectMetadata, QueryContext oeContext, IEnumerable<NodeSmoProperty> supportedProperties)
{
// TODOKusto: Remove if not needed. Returning a value appends it to the database name
// if(oeContext.DataSource.Exists(objectMetadata as DataSourceObjectMetadata)) return "Online";
return string.Empty;
}
}
}

View File

@@ -0,0 +1,115 @@
//
// 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.Collections.Generic;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes;
using Index = Microsoft.SqlServer.Management.Smo.Index;
namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel
{
/// <summary>
/// Subtye for keys
/// </summary>
internal partial class KeysChildFactory : DataSourceChildFactoryBase
{
public override string GetNodeSubType(object objectMetadata, QueryContext oeContext)
{
return IndexCustomeNodeHelper.GetSubType(objectMetadata);
}
}
/// <summary>
/// Sub types and custom name for indexes
/// </summary>
internal partial class IndexesChildFactory : DataSourceChildFactoryBase
{
private readonly Lazy<List<NodeSmoProperty>> smoPropertiesLazy = new Lazy<List<NodeSmoProperty>>(() => new List<NodeSmoProperty>
{
new NodeSmoProperty
{
Name = "IsUnique",
ValidFor = ValidForFlag.All
},
new NodeSmoProperty
{
Name = "IsClustered",
ValidFor = ValidForFlag.All
},
new NodeSmoProperty
{
Name = "IndexKeyType",
ValidFor = ValidForFlag.All
}
});
public override IEnumerable<NodeSmoProperty> SmoProperties => smoPropertiesLazy.Value;
public override string GetNodeSubType(object objectMetadata, QueryContext oeContext)
{
return IndexCustomeNodeHelper.GetSubType(objectMetadata);
}
public override string GetNodeCustomName(object objectMetadata, QueryContext oeContext)
{
return IndexCustomeNodeHelper.GetCustomLabel(objectMetadata);
}
}
/// <summary>
/// sub type for UserDefinedTableTypeKeys
/// </summary>
internal partial class UserDefinedTableTypeKeysChildFactory : DataSourceChildFactoryBase
{
public override string GetNodeSubType(object objectMetadata, QueryContext oeContext)
{
return IndexCustomeNodeHelper.GetSubType(objectMetadata);
}
}
internal static class IndexCustomeNodeHelper
{
internal static string GetCustomLabel(object context)
{
Index index = context as Index;
if (index != null)
{
string name = index.Name;
string unique = index.IsUnique ? SR.UniqueIndex_LabelPart : SR.NonUniqueIndex_LabelPart;
string clustered = index.IsClustered ? SR.ClusteredIndex_LabelPart : SR.NonClusteredIndex_LabelPart;
name = name + $" ({unique}, {clustered})";
return name;
}
return string.Empty;
}
internal static string GetSubType(object context)
{
Index index = context as Index;
if (index != null)
{
switch (index.IndexKeyType)
{
case IndexKeyType.DriPrimaryKey:
return "PrimaryKey";
case IndexKeyType.DriUniqueKey:
return "UniqueKey";
}
}
ForeignKey foreignKey = context as ForeignKey;
if (foreignKey != null)
{
return "ForeignKey";
}
return string.Empty;
}
}
}

View File

@@ -0,0 +1,52 @@
//
// 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.Collections.Generic;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes;
namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel
{
/// <summary>
/// Status for logins
/// </summary>
internal partial class ServerLevelLoginsChildFactory : DataSourceChildFactoryBase
{
public override string GetNodeStatus(object objectMetadata, QueryContext oeContext)
{
return LoginCustomNodeHelper.GetStatus(objectMetadata);
}
private readonly Lazy<List<NodeSmoProperty>> smoPropertiesLazy = new Lazy<List<NodeSmoProperty>>(() => new List<NodeSmoProperty>
{
new NodeSmoProperty
{
Name = "IsDisabled",
ValidFor = ValidForFlag.All
}
});
public override IEnumerable<NodeSmoProperty> SmoProperties => smoPropertiesLazy.Value;
}
internal static class LoginCustomNodeHelper
{
internal static string GetStatus(object context)
{
Login login = context as Login;
if (login != null)
{
if (login.IsDisabled)
{
return "Disabled";
}
}
return string.Empty;
}
}
}

View File

@@ -0,0 +1,137 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Globalization;
using Microsoft.SqlServer.Management.Smo;
namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel
{
/// <summary>
/// Custom name for parameters
/// </summary>
internal partial class TableValuedFunctionParametersChildFactory : DataSourceChildFactoryBase
{
public override string GetNodeCustomName(object objectMetadata, QueryContext oeContext)
{
return ParameterCustomeNodeHelper.GetCustomLabel(objectMetadata, oeContext);
}
public override string GetNodeSubType(object objectMetadata, QueryContext oeContext)
{
return ParameterCustomeNodeHelper.GetSubType(objectMetadata);
}
}
/// <summary>
/// Custom name for parameters
/// </summary>
internal partial class ScalarValuedFunctionParametersChildFactory : DataSourceChildFactoryBase
{
public override string GetNodeCustomName(object objectMetadata, QueryContext oeContext)
{
return ParameterCustomeNodeHelper.GetCustomLabel(objectMetadata, oeContext);
}
public override string GetNodeSubType(object objectMetadata, QueryContext oeContext)
{
return ParameterCustomeNodeHelper.GetSubType(objectMetadata);
}
}
/// <summary>
/// Custom name for parameters
/// </summary>
internal partial class AggregateFunctionParametersChildFactory : DataSourceChildFactoryBase
{
public override string GetNodeCustomName(object objectMetadata, QueryContext oeContext)
{
return ParameterCustomeNodeHelper.GetCustomLabel(objectMetadata, oeContext);
}
public override string GetNodeSubType(object objectMetadata, QueryContext oeContext)
{
return ParameterCustomeNodeHelper.GetSubType(objectMetadata);
}
}
/// <summary>
/// Custom name for parameters
/// </summary>
internal partial class StoredProcedureParametersChildFactory : DataSourceChildFactoryBase
{
public override string GetNodeCustomName(object objectMetadata, QueryContext oeContext)
{
return ParameterCustomeNodeHelper.GetCustomLabel(objectMetadata, oeContext);
}
public override string GetNodeSubType(object objectMetadata, QueryContext oeContext)
{
return ParameterCustomeNodeHelper.GetSubType(objectMetadata);
}
}
static class ParameterCustomeNodeHelper
{
internal static string GetSubType(object context)
{
Parameter parameter = context as Parameter;
if (parameter != null)
{
StoredProcedureParameter stordProcedureParameter = parameter as StoredProcedureParameter;
if (stordProcedureParameter != null && stordProcedureParameter.IsOutputParameter)
{
return "Output";
}
return "Input";
//TODO return parameters
}
return string.Empty;
}
internal static string GetCustomLabel(object context, QueryContext oeContext)
{
Parameter parameter = context as Parameter;
if (parameter != null)
{
return GetParameterCustomLabel(parameter);
}
return string.Empty;
}
internal static string GetParameterCustomLabel(Parameter parameter)
{
string label = parameter.Name;
string defaultString = SR.SchemaHierarchy_SubroutineParameterNoDefaultLabel;
string inputOutputString = SR.SchemaHierarchy_SubroutineParameterInputLabel;
string typeName = parameter.DataType.ToString();
if (parameter.DefaultValue != null &&
!string.IsNullOrEmpty(parameter.DefaultValue))
{
defaultString = SR.SchemaHierarchy_SubroutineParameterDefaultLabel;
}
StoredProcedureParameter stordProcedureParameter = parameter as StoredProcedureParameter;
if (stordProcedureParameter != null && stordProcedureParameter.IsOutputParameter)
{
inputOutputString = SR.SchemaHierarchy_SubroutineParameterInputOutputLabel;
if (parameter.IsReadOnly)
{
inputOutputString = SR.SchemaHierarchy_SubroutineParameterInputOutputReadOnlyLabel;
}
}
else if (parameter.IsReadOnly)
{
inputOutputString = SR.SchemaHierarchy_SubroutineParameterInputReadOnlyLabel;
}
return string.Format(CultureInfo.InvariantCulture,
SR.SchemaHierarchy_SubroutineParameterLabelFormatString,
label,
typeName,
inputOutputString,
defaultString);
}
}
}

View File

@@ -0,0 +1,85 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Collections.Generic;
using System.Data;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.Extensibility;
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel
{
/// <summary>
/// A <see cref="DataSourceQuerier"/> handles SMO queries for one or more SMO object types.
/// The <see cref="SupportedObjectTypes"/> property defines which types can be queried.
///
/// To query multiple
/// </summary>
public abstract class DataSourceQuerier : IComposableService
{
private static object lockObject = new object();
/// <summary>
/// Queries SMO for a collection of objects using the <see cref="QueryContext"/>
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public abstract IEnumerable<DataSourceObjectMetadata> Query(QueryContext context, string filter, bool refresh, IEnumerable<string> extraProperties);
internal IMultiServiceProvider ServiceProvider
{
get;
private set;
}
public void SetServiceProvider(IMultiServiceProvider provider)
{
ServiceProvider = provider;
}
/// <summary>
/// Convert the data to data reader is possible
/// </summary>
protected IDataReader GetDataReader(object data)
{
IDataReader reader = null;
if (data is IDataReader)
{
reader = data as IDataReader;
}
else if(data is DataTable)
{
reader = ((DataTable)data).CreateDataReader();
}
else if (data is DataSet)
{
reader = ((DataSet)data).Tables[0].CreateDataReader();
}
return reader;
}
/// <summary>
/// Mthod used to do custom filtering on smo objects if cannot be implemented using the filters
/// </summary>
protected virtual bool PassesFinalFilters(SqlSmoObject parent, SqlSmoObject objectMetadata)
{
return true;
}
/// <summary>
/// Indicates which platforms the querier is valid for
/// </summary>
public virtual ValidForFlag ValidFor
{
get
{
return ValidForFlag.All;
}
}
}
}

View File

@@ -0,0 +1,66 @@
//
// 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.Extensibility;
using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes;
using Microsoft.Kusto.ServiceLayer.DataSource;
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel
{
/// <summary>
/// Context object containing key properties needed to query for SMO objects
/// </summary>
public class QueryContext
{
public IDataSource DataSource { get; private set; }
/// <summary>
/// Creates a context object with a server to use as the basis for any queries
/// </summary>
/// <param name="server"></param>
public QueryContext(IDataSource dataSource, IMultiServiceProvider serviceProvider)
{
DataSource = dataSource;
ServiceProvider = serviceProvider;
}
/// <summary>
/// Parent of a give node to use for queries
/// </summary>
public DataSourceObjectMetadata ParentObjectMetadata { get; set; }
/// <summary>
/// A query loader that can be used to find <see cref="DataSourceQuerier"/> objects
/// for specific SMO types
/// </summary>
public IMultiServiceProvider ServiceProvider { get; private set; }
/// <summary>
/// Helper method to cast a parent to a specific type
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T ParentAs<T>()
where T : TreeNode
{
return ParentObjectMetadata as T;
}
/// <summary>
/// Copies the context for use by another node
/// </summary>
/// <param name="parent">New Parent to set</param>
/// <returns>new <see cref="QueryContext"/> with all fields except <see cref="ParentObjectMetadata"/> the same</returns>
public QueryContext CopyWithParent(DataSourceObjectMetadata parent)
{
QueryContext context = new QueryContext(this.DataSource, this.ServiceProvider)
{
ParentObjectMetadata = parent
};
return context;
}
}
}

View File

@@ -0,0 +1,320 @@
<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Xml.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Globalization" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
// This file was generated by a T4 Template. Do not modify directly, instead update the SmoQueryModelDefinition.xml file
// and re-run the T4 template. This can be done in Visual Studio by right-click in and choosing "Run Custom Tool",
// or from the command-line on any platform by running "build.cmd -Target=CodeGen" or "build.sh -Target=CodeGen".
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Smo.Broker;
namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.SmoModel
{
<#
var directory = Path.GetDirectoryName(Host.TemplateFile);
string xmlFile = Path.Combine(directory, "SmoQueryModelDefinition.xml");
/////////
// Now generate all the Query methods
/////////
var allNodes = GetNodes(xmlFile);
var indent = " ";
foreach (var nodeName in allNodes)
{
XmlElement nodeElement = GetNodeElement(xmlFile, nodeName);
IList<string> parents = GetParents(nodeElement, xmlFile, nodeName);
string nodeType = GetNodeType(nodeElement, nodeName);
var validFor = nodeElement.GetAttribute("ValidFor");
string queryBaseClass = "SmoQuerier";
PushIndent(indent);
WriteLine("");
WriteLine(string.Format("[Export(typeof({0}))]", queryBaseClass));
WriteLine(string.Format("internal partial class {0}Querier: {1}", nodeName, queryBaseClass));
WriteLine("{");
PushIndent(indent);
// Supported Types
WriteLine("Type[] supportedTypes = new Type[] { typeof("+ nodeType + ") };");
if (!string.IsNullOrWhiteSpace(validFor))
{
WriteLine("");
WriteLine(string.Format("public override ValidForFlag ValidFor {{ get {{ return {0}; }} }}", GetValidForFlags(validFor)));
WriteLine("");
}
WriteLine("");
WriteLine("public override Type[] SupportedObjectTypes { get { return supportedTypes; } }");
WriteLine("");
// Query impl
WriteLine("public override IEnumerable<SqlSmoObject> Query(SmoQueryContext context, string filter, bool refresh, IEnumerable<string> extraProperties)");
WriteLine("{");
PushIndent(indent);
// TODO Allow override of the navigation path
foreach(var parentType in parents)
{
string parentVar = string.Format("parent{0}", parentType);
WriteLine(string.Format("{0} {1} = context.Parent as {0};", parentType, parentVar));
WriteLine(string.Format("if ({0} != null)", parentVar));
WriteLine("{");
PushIndent(indent);
XmlElement navPathElement = GetNavPathElement(xmlFile, nodeName, parentType);
string navigationPath = GetNavigationPath(nodeElement, nodeName, navPathElement);
string subField = GetNavPathAttribute(navPathElement, "SubField");
string fieldType = GetNavPathAttribute(navPathElement, "FieldType");
WriteLine(string.Format("var retValue = {0}.{1};", parentVar, navigationPath));
WriteLine("if (retValue != null)");
WriteLine("{");
PushIndent(indent);
if (IsCollection(nodeElement))
{
WriteLine(string.Format("retValue.ClearAndInitialize(filter, extraProperties);"));
if (string.IsNullOrEmpty(subField) )
{
WriteLine(string.Format("return new SmoCollectionWrapper<{0}>(retValue).Where(c => PassesFinalFilters({1}, c));", nodeType, parentVar));
}
else
{
WriteLine(string.Format("List<{0}> subFieldResult = new List<{0}>();", nodeType));
WriteLine(string.Format("foreach({0} field in retValue)", fieldType));
WriteLine("{");
PushIndent(indent);
WriteLine(string.Format("{0} subField = field.{1};", nodeType, subField));
WriteLine(string.Format("if (subField != null)"));
WriteLine("{");
PushIndent(indent);
WriteLine(string.Format("subFieldResult.Add(subField);"));
PopIndent();
WriteLine("}");
PopIndent();
WriteLine("}");
WriteLine(string.Format("return subFieldResult.Where(c => PassesFinalFilters({1}, c));", nodeType, parentVar));
}
}
else
{
WriteLine("if (refresh)");
WriteLine("{");
PushIndent(indent);
WriteLine(string.Format("{0}.{1}.Refresh();", parentVar, navigationPath));
PopIndent();
WriteLine("}");
WriteLine("return new SqlSmoObject[] { retValue };");
}
PopIndent();
WriteLine("}");
PopIndent();
WriteLine("}"); // close If
}
WriteLine("return Enumerable.Empty<SqlSmoObject>();");
PopIndent();
WriteLine("}"); // close Query method
PopIndent();
WriteLine("}"); // close Class
PopIndent();
}
#>
}
<#+
public static string[] GetNodes(string xmlFile)
{
List<string> typesList = new List<string>();
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
XmlNodeList treeTypes = doc.SelectNodes("/SmoQueryModel/Node");
if (treeTypes != null)
{
foreach (var type in treeTypes)
{
XmlElement element = type as XmlElement;
if (element != null)
{
typesList.Add(element.GetAttribute("Name"));
}
}
}
return typesList.ToArray();
}
public static XmlElement GetNodeElement(string xmlFile, string nodeName)
{
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
return (XmlElement)doc.SelectSingleNode(string.Format("/SmoQueryModel/Node[@Name='{0}']", nodeName));
}
public static XmlElement GetNavPathElement(string xmlFile, string nodeName, string parent)
{
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
XmlElement navPathElement = (XmlElement)doc.SelectSingleNode(string.Format("/SmoQueryModel/Node[@Name='{0}']/NavigationPath[@Parent='{1}']", nodeName, parent));
return navPathElement;
}
public static string GetNavPathAttribute(XmlElement navPathElement, string attributeName)
{
return navPathElement == null ? null : navPathElement.GetAttribute(attributeName);
}
public static string GetNavigationPath(XmlElement nodeElement, string nodeName, XmlElement navPathElement)
{
string navPathField = GetNavPathAttribute(navPathElement, "Field");
if (!string.IsNullOrEmpty(navPathField))
{
return navPathField;
}
// else use pluralized type as this is the most common scenario
string nodeType = GetNodeType(nodeElement, nodeName);
string nodeTypeAccessor = IsCollection(nodeElement) ? string.Format("{0}s", nodeType) : nodeType;
return nodeTypeAccessor;
}
public static string GetNodeType(XmlElement nodeElement, string nodeName)
{
var type = nodeElement.GetAttribute("Type");
if (!string.IsNullOrEmpty(type))
{
return type;
}
// Otherwise assume the type is the node name without "Sql" at the start
var prefix = "Sql";
return nodeName.IndexOf(prefix) == 0 ? nodeName.Substring(prefix.Length) : nodeName;
}
public static bool IsCollection(XmlElement nodeElement)
{
var collection = nodeElement.GetAttribute("Collection");
bool result;
if (bool.TryParse(collection, out result))
{
return result;
}
// Default is true
return true;
}
public static IList<string> GetParents(XmlElement nodeElement, string xmlFile, string parentName)
{
var parentAttr = nodeElement.GetAttribute("Parent");
if (!string.IsNullOrEmpty(parentAttr))
{
return new string[] { parentAttr };
}
var parentNodes = GetChildren(xmlFile, parentName, "Parent");
if (parentNodes != null && parentNodes.Count > 0)
{
List<string> parents = new List<string>();
foreach(var node in parentNodes)
{
parents.Add(node.InnerText);
}
return parents;
}
// default to assuming a type is under Database
return new string[] { "Database" };
}
public static List<XmlElement> GetChildren(string xmlFile, string parentName, string childNode)
{
XmlElement nodeElement = GetNodeElement(xmlFile, parentName);
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
List<XmlElement> retElements = new List<XmlElement>();
XmlNodeList nodeList = doc.SelectNodes(string.Format("/SmoQueryModel/Node[@Name='{0}']/{1}", parentName, childNode));
foreach (var item in nodeList)
{
XmlElement itemAsElement = item as XmlElement;
if (itemAsElement != null)
{
retElements.Add(itemAsElement);
}
}
return retElements;
}
public static string GetValidForFlags(string validForStr)
{
List<string> flags = new List<string>();
if (validForStr.Contains("Sql2005"))
{
flags.Add("ValidForFlag.Sql2005");
}
if (validForStr.Contains("Sql2008"))
{
flags.Add("ValidForFlag.Sql2008");
}
if (validForStr.Contains("Sql2012"))
{
flags.Add("ValidForFlag.Sql2012");
}
if (validForStr.Contains("Sql2014"))
{
flags.Add("ValidForFlag.Sql2014");
}
if (validForStr.Contains("Sql2016"))
{
flags.Add("ValidForFlag.Sql2016");
}
if (validForStr.Contains("Sql2017"))
{
flags.Add("ValidForFlag.Sql2017");
}
if (validForStr.Contains("AzureV12"))
{
flags.Add("ValidForFlag.AzureV12");
}
if (validForStr.Contains("AllOnPrem"))
{
flags.Add("ValidForFlag.AllOnPrem");
}
if (validForStr.Contains("AllAzure"))
{
flags.Add("ValidForFlag.AllAzure");
}
if (validForStr.Contains("NotSqlDw"))
{
flags.Add("ValidForFlag.NotSqlDw");
}
if (validForStr == "All")
{
flags.Add("ValidForFlag.All");
}
return string.Join("|", flags);
}
#>

View File

@@ -0,0 +1,164 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
This XML file defines how to query for a given SMO type based on a parent/child or
XPath relationship. From this file, the paths to query each type should be buildable
into code using a T4 template.
Key properties:
Name: This maps
Type: Optional SMO type. If not specified, the Name without the Sql prefix is used
Parent: Expected parent type. Needed to codegen the response. if there are multiple parents
then each one
NavigationPath: For types whose access path differs based on parent or needs custom navigation
this can be used.
-->
<SmoQueryModel>
<!--<Node Name="SqlServer"/> -->
<Node Name="SqlDatabase" Type="Database" Parent="Server" />
<Node Name="SqlLinkedServerLogin" Type="LinkedServer" Parent="Server"/>
<Node Name="SqlLogin" Type="Login" Parent="Server" />
<Node Name="SqlServerRole" Type="" Parent="Server" >
<NavigationPath Parent="Server" Field="Roles" />
</Node>
<Node Name="SqlCredential" Parent="Server" />
<Node Name="SqlCryptographicProvider" Parent="Server" />
<Node Name="SqlServerAudit" Type="Audit" Parent="Server" />
<Node Name="SqlServerAuditSpecification" Type="ServerAuditSpecification" Parent="Server"/>
<Node Name="SqlEndpoint" Parent="Server"/>
<Node Name="SqlLinkedServer" Parent="Server" />
<Node Name="SqlServerDdlTrigger" Parent="Server" ValidFor="NotSqlDw" >
<NavigationPath Parent="Server" Field="Triggers" />
</Node>
<Node Name="SqlErrorMessage" Type="UserDefinedMessage" Parent="Server" />
<Node Name="SqlTable" Parent="Database" />
<Node Name="SqlHistoryTable" Type="Table" Parent="Table" >
<NavigationPath Parent="Table" Type="Table" Field="Parent.Tables" />
</Node>
<Node Name="SqlView" Parent="Database" />
<Node Name="SqlSynonym" Parent="Database" ValidFor="NotSqlDw" />
<Node Name="SqlColumn" Parent="TableViewTableTypeBase"/>
<Node Name="SqlIndex" Parent="TableViewTableTypeBase">
<NavigationPath Parent="TableViewTableTypeBase" Field="Indexes" />
</Node>
<Node Name="SqlCheck" Parent="Table"/>
<Node Name="SqlForeignKeyConstraint" Type="ForeignKey" Parent="Table" />
<Node Name="SqlDefaultConstraint" Collection="True" >
<Parent>Table</Parent>
<Parent>UserDefinedTableType</Parent>
<NavigationPath Parent="Table" Field="Columns" SubField="DefaultConstraint" FieldType="Column" />
<NavigationPath Parent="UserDefinedTableType" Field="Columns" SubField="DefaultConstraint" FieldType="Column" />
</Node>
<Node Name="SqlDmlTrigger" Type="Trigger" ValidFor="NotSqlDw">
<Parent>Table</Parent>
<Parent>View</Parent>
</Node>
<Node Name="SqlFullTextIndex" Parent="Table" Collection="False" ValidFor="NotSqlDw" />
<Node Name="SqlStatistic" Parent="TableViewBase"/>
<Node Name="SqlDatabaseDdlTrigger" Type="DatabaseDdlTrigger" Parent="Database" ValidFor="NotSqlDw">
<NavigationPath Parent="Database" Field="Triggers" />
</Node>
<Node Name="SqlAssembly" Type="SqlAssembly" Parent="Database" >
<NavigationPath Parent="Database" Field="Assemblies" />
</Node>
<!-- Deprecated
<Node Name="SqlRule" Parent="Database" />
<Node Name="SqlDefault" Parent="Database" />
-->
<Node Name="SqlSequence" Parent="Database" />
<Node Name="SqlUserDefinedDataType" Parent="Database" ValidFor="NotSqlDw" />
<Node Name="SqlUserDefinedTableType" Parent="Database" />
<Node Name="SqlXmlSchemaCollection" />
<Node Name="SqlUserDefinedType" />
<Node Name="SqlUserDefinedFunction" />
<Node Name="SqlUserDefinedAggregate" />
<Node Name="SqlFileGroup" />
<Node Name="SqlFile" Type="DataFile" Parent="FileGroup" >
<NavigationPath Parent="FileGroup" Field="Files" />
</Node>
<Node Name="SqlFullTextCatalog"/>
<Node Name="SqlFullTextStopList" />
<Node Name="SqlPartitionFunction"/>
<Node Name="SqlPartitionScheme"/>
<Node Name="SqlSearchPropertyList" />
<Node Name="SqlUser"/>
<Node Name="SqlSchema"/>
<Node Name="SqlAsymmetricKey" />
<Node Name="SqlCertificate" />
<Node Name="SqlSymmetricKey" />
<Node Name="SqlDatabaseEncryptionKey" Collection="False" />
<Node Name="SqlMasterKey" Collection="False" />
<Node Name="SqlDatabaseAuditSpecification" />
<Node Name="SqlSecurityPolicy" >
<NavigationPath Parent="Database" Field="SecurityPolicies" />
</Node>
<Node Name="SqlDatabaseCredential" Type="DatabaseScopedCredential"/>
<Node Name="SqlRole" Type="DatabaseRole" >
<NavigationPath Parent="Database" Field="Roles" />
</Node>
<Node Name="SqlApplicationRole" />
<Node Name="SqlColumnMasterKey" />
<Node Name="SqlColumnEncryptionKey" />
<Node Name="SqlServiceBroker" Type="ServiceBroker" Collection="False" />
<Node Name="SqlService" Type="BrokerService" Parent="ServiceBroker" >
<NavigationPath Parent="ServiceBroker" Field="Services" />
</Node>
-
<Node Name="SqlContract" Type="ServiceContract" Parent="ServiceBroker" />
<Node Name="SqlQueue" Type="ServiceQueue" Parent="ServiceBroker" >
<NavigationPath Parent="ServiceBroker" Field="Queues" />
</Node>
<Node Name="SqlRemoteServiceBinding" Parent="ServiceBroker" />
<Node Name="SqlBrokerPriority" Parent="ServiceBroker" >
<NavigationPath Parent="ServiceBroker" Field="Priorities" />
</Node>
<Node Name="SqlMessageType" Parent="ServiceBroker"/>
<Node Name="SqlExternalDataSource" />
<Node Name="SqlExternalFileFormat" />
<Node Name="SqlProcedure" Type="StoredProcedure"/>
<Node Name="SqlExtendedStoredProcedure" />
<Node Name="SqlSubroutineParameter" Type="Parameter" >
<Parent>StoredProcedure</Parent>
<Parent>UserDefinedAggregate</Parent>
<Parent>UserDefinedFunction</Parent>
</Node>
<Node Name="SqlPartitionFunctionParameter" Parent="PartitionFunction" />
<Node Name="SqlBuiltInType" Type="SystemDataType" Parent="Database">
<NavigationPath Parent="Database" Field="Parent.SystemDataTypes" FieldForUrn="Parent" />
</Node>
<!-- TODO Enable all types
<Node Name="SqlRoute"/>
-->
<!-- Signatures appear to be missing entirely from SMO and SSMS object explorer...
<Node Name="SqlSignature" />
-->
<!-- TODO find mapping - exists in SSDT but not SSMS / SMO?
<Node Name="SqlEventNotification" Parent="ServiceBroker" />
-->
<!-- TODO Requires XEvents SMO DLL in .Net Core
<Node Name="SqlEventSession" Type="Session" />
<Node Name="SqlServerEventNotification" Type="Event" Parent="Server" />
-->
</SmoQueryModel>

View File

@@ -0,0 +1,34 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlServer.Management.Smo;
// TODOKusto: Remove this file. These classes might not be needed.
namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel
{
/// <summary>
/// Custom name for table
/// </summary>
internal partial class TablesChildFactory : DataSourceChildFactoryBase
{
// TODOKusto: If we are always passing DataSourceMetadataObject, stop passing object. Make it type safe.
public override string GetNodePathName(object objectMetadata)
{
return base.GetNodePathName(objectMetadata);
}
}
/// <summary>
/// Custom name for history table
/// </summary>
internal partial class TableChildFactory : DataSourceChildFactoryBase
{
public override string GetNodePathName(object objectMetadata)
{
return base.GetNodePathName(objectMetadata);
}
}
}

View File

@@ -0,0 +1,79 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes;
using Microsoft.Kusto.ServiceLayer.DataSource;
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel
{
/// <summary>
/// A Node in the tree representing a SMO-based object
/// </summary>
public class DataSourceTreeNode : TreeNode
{
public static int FolderSortPriority = 0;
private static int _nextSortPriority = FolderSortPriority + 1; // 0 is reserved for folders
protected QueryContext context;
public DataSourceTreeNode(IDataSource dataSource, DataSourceObjectMetadata objectMetadata)
: base(dataSource, objectMetadata)
{
}
/// <summary>
/// Indicates which platforms a node is valid for
/// </summary>
public ValidForFlag ValidFor { get; set; }
/// <summary>
/// Gets an incrementing sort priority value to assist in automatically sorting
/// elements in a tree
/// </summary>
public static int NextSortPriority
{
get
{
return System.Threading.Interlocked.Increment(ref _nextSortPriority);
}
}
public virtual void CacheInfoFromModel(DataSourceObjectMetadata objectMetadata)
{
base.ObjectMetadata = objectMetadata;
NodeValue = objectMetadata.Name;
}
public virtual DataSourceObjectMetadata GetParentObjectMetadata()
{
if (ObjectMetadata != null)
{
return ObjectMetadata;
}
// Return the parent's object, or null if it's not set / not a OETreeNode
return ParentAs<DataSourceTreeNode>()?.GetParentObjectMetadata();
}
public override object GetContext()
{
EnsureContextInitialized();
return context;
}
protected virtual void EnsureContextInitialized()
{
if (context == null)
{
DataSourceObjectMetadata oeParent = GetParentObjectMetadata();
QueryContext parentContext = Parent?.GetContextAs<QueryContext>();
if (oeParent != null && parentContext != null)
{
context = parentContext.CopyWithParent(oeParent);
}
}
}
}
}

View File

@@ -0,0 +1,467 @@
<?xml version="1.0" encoding="utf-8" ?>
<ServerExplorerTree>
<Node Name="Server" LocLabel="SR.SchemaHierarchy_Server" Image="Server">
<Child Name="Databases"/>
<Child Name="ServerLevelSecurity"/>
<Child Name="ServerLevelServerObjects"/>
</Node>
<Node Name="Databases" LocLabel="SR.SchemaHierarchy_Databases" IsAsyncLoad="" BaseClass="ModelBased" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlDatabase" TreeNode="DatabaseTreeNode">
<Filters >
<Filter Property="IsSystemObject" Value="0" Type="bool" />
</Filters>
<Properties>
<Property Name="Status" ValidFor="All"/>
</Properties>
<Child Name="SystemDatabases" IsSystemObject="1"/>
</Node>
<Node Name="ServerLevelSecurity" LocLabel="SR.SchemaHierarchy_Security" BaseClass="ModelBased" ValidFor="All">
<Child Name="ServerLevelLinkedServerLogins"/>
<Child Name="ServerLevelLogins"/>
<Child Name="ServerLevelServerRoles"/>
<Child Name="ServerLevelCredentials"/>
<Child Name="ServerLevelCryptographicProviders"/>
<Child Name="ServerLevelServerAudits"/>
<Child Name="ServerLevelServerAuditSpecifications"/>
<!-- TODO Support XEvents in .Net Core SMO
<Child Name="ServerLevelEventSessions"/>
-->
</Node>
<Node Name="ServerLevelServerObjects" LocLabel="SR.SchemaHierarchy_ServerObjects" BaseClass="ModelBased" NodeType="ServerLevelServerObject" ValidFor="AllOnPrem">
<Child Name="ServerLevelEndpoints"/>
<Child Name="ServerLevelLinkedServers"/>
<Child Name="ServerLevelServerTriggers"/>
<Child Name="ServerLevelErrorMessages"/>
<!-- TODO Support XEvents in .Net Core SMO
<Child Name="ServerLevelEventNotifications"/>
-->
</Node>
<Node Name="SystemDatabases" LocLabel="SR.SchemaHierarchy_SystemDatabases" BaseClass="ModelBased" NodeType="SystemDatabase" ChildQuerierTypes="SqlDatabase" Strategy="MultipleElementsOfType" TreeNode="DatabaseTreeNode" ValidFor="All">
<Filters >
<Filter Property="IsSystemObject" Value="1" Type="bool" />
</Filters>
</Node>
<!-- TODO Support XEvents in .Net Core SMO
<Node Name="ServerLevelEventSessions" LocLabel="SR.SchemaHierarchy_EventSessions" BaseClass="ModelBased" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlEventSession" ValidFor="Sql2008|Sql2012|Sql2014|Sql2016|Sql2017"/>
<Node Name="ServerLevelEventNotifications" LocLabel="SR.SchemaHierarchy_ServerEventNotifications" BaseClass="ModelBased" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlServerEventNotification"/>
-->
<Node Name="ServerLevelLinkedServerLogins" LocLabel="SR.SchemaHierarchy_LinkedServerLogins" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="ServerLevelLinkedServerLogin" ChildQuerierTypes="SqlLinkedServerLogin" ValidFor="AllOnPrem"/>
<Node Name="ServerLevelLogins" LocLabel="SR.SchemaHierarchy_Logins" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="ServerLevelLogin" ChildQuerierTypes="SqlLogin"/>
<Node Name="ServerLevelServerRoles" LocLabel="SR.SchemaHierarchy_ServerRoles" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="ServerLevelServerRole" ChildQuerierTypes="SqlServerRole" ValidFor="AllOnPrem"/>
<Node Name="ServerLevelCredentials" LocLabel="SR.SchemaHierarchy_Credentials" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="ServerLevelCredential" ChildQuerierTypes="SqlCredential" ValidFor="AllOnPrem"/>
<Node Name="ServerLevelCryptographicProviders" LocLabel="SR.SchemaHierarchy_CryptographicProviders" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="ServerLevelCryptographicProvider" ChildQuerierTypes="SqlCryptographicProvider" ValidFor="AllOnPrem"/>
<Node Name="ServerLevelServerAudits" LocLabel="SR.SchemaHierarchy_ServerAudits" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="ServerLevelServerAudit" ChildQuerierTypes="SqlServerAudit" ValidFor="AllOnPrem"/>
<Node Name="ServerLevelServerAuditSpecifications" LocLabel="SR.SchemaHierarchy_ServerAuditSpecifications" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="ServerLevelServerAuditSpecification" ChildQuerierTypes="SqlServerAuditSpecification" ValidFor="AllOnPrem"/>
<Node Name="ServerLevelEndpoints" LocLabel="SR.SchemaHierarchy_Endpoints" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="ServerLevelEndpoint" ChildQuerierTypes="SqlEndpoint" ValidFor="AllOnPrem"/>
<Node Name="ServerLevelLinkedServers" LocLabel="SR.SchemaHierarchy_LinkedServers" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="ServerLevelLinkedServer" ChildQuerierTypes="SqlLinkedServer"/>
<Node Name="ServerLevelServerTriggers" LocLabel="SR.SchemaHierarchy_ServerTriggers" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="ServerLevelServerTrigger" ChildQuerierTypes="SqlServerDdlTrigger"/>
<Node Name="ServerLevelErrorMessages" LocLabel="SR.SchemaHierarchy_ErrorMessages" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="ServerLevelErrorMessage" ChildQuerierTypes="SqlErrorMessage"/>
<Node Name="Database" LocLabel="string.Empty" Image="Database" BaseClass="ModelBased" NodeType="Database" IsAsyncLoad="" Strategy="CreateModel">
<Child Name="Tables"/>
<Child Name="Views"/>
<Child Name="Synonyms"/>
<Child Name="Programmability"/>
<Child Name="ExternalResources"/>
<Child Name="ServiceBroker"/>
<Child Name="Storage"/>
<Child Name="Security"/>
</Node>
<Node Name="Tables" LocLabel="SR.SchemaHierarchy_Tables" BaseClass="ModelBased" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlTable" TreeNode="TableTreeNode">
<Filters >
<Filter Property="IsSystemObject" Value="0" Type="bool" />
<Filter Property="TemporalType" Type="Enum" ValidFor="Sql2016|Sql2017|AzureV12">
<Value>TableTemporalType.None</Value>
<Value>TableTemporalType.SystemVersioned</Value>
</Filter>
</Filters>
<Properties>
<Property Name="IsFileTable" ValidFor="Sql2012|Sql2014|Sql2016|Sql2017"/>
<Property Name="IsSystemVersioned" ValidFor="Sql2016|Sql2017|AzureV12"/>
<Property Name="TemporalType" ValidFor="Sql2016|Sql2017|AzureV12"/>
<Property Name="IsExternal" ValidFor="Sql2016|Sql2017|AzureV12"/>
</Properties>
<Child Name="SystemTables" IsSystemObject="1"/>
</Node>
<Node Name="Views" LocLabel="SR.SchemaHierarchy_Views" BaseClass="ModelBased" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlView" TreeNode="ViewTreeNode">
<Filters>
<Filter Property="IsSystemObject" Value="0" Type="bool" />
</Filters>
<Child Name="SystemViews" IsSystemObject="1"/>
</Node>
<Node Name="Synonyms" LocLabel="SR.SchemaHierarchy_Synonyms" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="Synonym" ChildQuerierTypes="SqlSynonym" ValidFor="Sql2005|Sql2008|Sql2012|Sql2014|Sql2016|Sql2017|AzureV12"/>
<Node Name="Programmability" LocLabel="SR.SchemaHierarchy_Programmability" BaseClass="ModelBased">
<Child Name="StoredProcedures"/>
<Child Name="Functions"/>
<Child Name="DatabaseTriggers"/>
<Child Name="Assemblies"/>
<Child Name="Types"/>
<!--
<Child Name="Rules"/>
<Child Name="Defaults"/>
-->
<Child Name="Sequences"/>
</Node>
<Node Name="ExternalResources" LocLabel="SR.SchemaHierarchy_ExternalResources" BaseClass="ModelBased" TreeNode="ExternalResourceTreeNode" ValidFor="Sql2016|Sql2017|AzureV12">
<Child Name="ExternalDataSources"/>
<Child Name="ExternalFileFormats"/>
</Node>
<Node Name="ServiceBroker" LocLabel="SR.SchemaHierarchy_ServiceBroker" BaseClass="ModelBased" ValidFor="AllOnPrem">
<Child Name="MessageTypes"/>
<Child Name="Contracts"/>
<Child Name="Queues"/>
<Child Name="Services"/>
<!--Child Name="Routes"/-->
<Child Name="DatabaseAndQueueEventNotifications"/>
<Child Name="RemoteServiceBindings"/>
<Child Name="BrokerPriorities"/>
</Node>
<Node Name="Storage" LocLabel="SR.SchemaHierarchy_Storage" BaseClass="ModelBased" ValidFor="AllOnPrem|AzureV12">
<Child Name="FileGroups"/>
<Child Name="FullTextCatalogs"/>
<Child Name="FullTextStopLists"/>
<Child Name="SqlLogFiles"/>
<Child Name="PartitionFunctions"/>
<Child Name="PartitionSchemes"/>
<Child Name="SearchPropertyLists"/>
</Node>
<Node Name="Security" LocLabel="SR.SchemaHierarchy_Security" BaseClass="ModelBased" >
<Child Name="Users"/>
<Child Name="Roles"/>
<Child Name="Schemas"/>
<Child Name="AsymmetricKeys"/>
<Child Name="Certificates"/>
<Child Name="SymmetricKeys"/>
<Child Name="DatabaseScopedCredentials"/>
<Child Name="DatabaseEncryptionKeys"/>
<Child Name="MasterKeys"/>
<Child Name="Signatures"/>
<Child Name="DatabaseAuditSpecifications"/>
<Child Name="SecurityPolicies"/>
<Child Name="AlwaysEncryptedKeys"/>
</Node>
<!-- Childs of Tables -->
<Node Name="SystemTables" LocLabel="SR.SchemaHierarchy_SystemTables" BaseClass="ModelBased" IsMsShippedOwned="true" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlTable" TreeNode="TableTreeNode">
<Filters >
<Filter Property="IsSystemObject" Value="1" Type="bool" />
</Filters>
</Node>
<!--
<Node Name="FileTables" LocLabel="SR.SchemaHierarchy_FileTables" BaseClass="ModelBased" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlTable" TreeNode="TableTreeNode" ValidFor="Sql2012|Sql2014|Sql2016|Sql2017">
<Filters >
<Filter Property="IsFileTable" Value="1" Type="bool" />
</Filters>
</Node>
<Node Name="ExternalTables" LocLabel="SR.SchemaHierarchy_ExternalTables" BaseClass="ModelBased" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlTable" TreeNode="ExternalTableTreeNode" ValidFor="Sql2016|Sql2017|AzureV12">
<Filters >
<Filter Property="IsExternal" Value="1" Type="bool" />
</Filters>
</Node>
-->
<Node Name="Table" LocLabel="string.Empty" BaseClass="ModelBased" IsAsyncLoad="" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlTable;SqlHistoryTable" TreeNode="HistoryTableTreeNode">
<Filters>
<Filter TypeToReverse="SqlHistoryTable" Property="TemporalType" Type="Enum" ValidFor="Sql2016|Sql2017|AzureV12">
<Value>TableTemporalType.HistoryTable</Value>
</Filter>
</Filters>
<Child Name="Columns"/>
<Child Name="Keys"/>
<Child Name="Constraints"/>
<Child Name="Triggers"/>
<Child Name="Indexes"/>
<Child Name="Statistics"/>
</Node>
<!-- TODO This should use display item not ChildQuerierTypes -->
<Node Name="HistoryTable" LocLabel="string.Empty" BaseClass="ModelBased" IsAsyncLoad="" Strategy="PopulateDetails" NodeType="Table" ValidFor="Sql2016|Sql2017|AzureV12">
<Child Name="Columns"/>
<Child Name="Constraints"/>
<Child Name="Indexes"/>
<Child Name="Statistics"/>
</Node>
<!-- TODO This should use display item not ChildQuerierTypes -->
<Node Name="ExternalTable" LocLabel="string.Empty" BaseClass="ModelBased" IsAsyncLoad="" Strategy="PopulateDetails" NodeType="Table" ChildQuerierTypes="SqlTable" ValidFor="Sql2016|Sql2017|AzureV12">
<Child Name="Columns"/>
<Child Name="Statistics"/>
</Node>
<Node Name="Columns" LocLabel="SR.SchemaHierarchy_Columns" BaseClass="ModelBased" Strategy="PopulateParentDetails" NodeType="Column" ChildQuerierTypes="SqlColumn" DisableSort=""/>
<Node Name="Keys" LocLabel="SR.SchemaHierarchy_Keys" BaseClass="ModelBased" Strategy="ElementsInRelationship" NodeType="Key" ChildQuerierTypes="SqlIndex;SqlForeignKeyConstraint" ValidFor="NotSqlDw">
<Filters>
<Filter TypeToReverse="SqlIndex" Property="IndexKeyType" Type="Enum" ValidFor="AllOnPrem|AzureV12">
<Value>IndexKeyType.DriPrimaryKey</Value>
<Value>IndexKeyType.DriUniqueKey</Value>
</Filter>
</Filters>
</Node>
<Node Name="Constraints" LocLabel="SR.SchemaHierarchy_Constraints" BaseClass="ModelBased" NodeType="Constraint" Strategy="ElementsInRelationship" ChildQuerierTypes="SqlDefaultConstraint;SqlCheck"/>
<Node Name="Triggers" LocLabel="SR.SchemaHierarchy_Triggers" BaseClass="ModelBased" Strategy="ElementsInRelationship" NodeType="Trigger" ChildQuerierTypes="SqlDmlTrigger" ValidFor="Sql2005|Sql2008|Sql2012|Sql2014|Sql2016|Sql2017|AzureV12"/>
<Node Name="Indexes" LocLabel="SR.SchemaHierarchy_Indexes" BaseClass="ModelBased" Strategy="ElementsInRelationship" NodeType="Index" ChildQuerierTypes="SqlIndex;SqlFullTextIndex">
<Filters>
<Filter TypeToReverse="SqlIndex" Property="IndexKeyType" Type="Enum" ValidFor="AllOnPrem|AzureV12">
<Value>IndexKeyType.None</Value>
<Value>IndexKeyType.DriPrimaryKey</Value>
<Value>IndexKeyType.DriUniqueKey</Value>
</Filter>
</Filters>
</Node>
<Node Name="Statistics" LocLabel="SR.SchemaHierarchy_Statistics" BaseClass="ModelBased" Strategy="ElementsInRelationship" NodeType="Statistic" ChildQuerierTypes="SqlStatistic"/>
<Node Name="SystemViews" LocLabel="SR.SchemaHierarchy_SystemViews" BaseClass="ModelBased" IsMsShippedOwned="true" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlView" TreeNode="ViewTreeNode">
<Filters>
<Filter Property="IsSystemObject" Value="1" Type="bool" />
</Filters>
</Node>
<Node Name="View" LocLabel="string.Empty" BaseClass="ModelBased" IsAsyncLoad="" NodeType="View" Strategy="PopulateDetails">
<Child Name="Columns"/>
<Child Name="Triggers"/>
<Child Name="Indexes"/>
<Child Name="Statistics"/>
</Node>
<Node Name="Functions" LocLabel="SR.SchemaHierarchy_Functions" BaseClass="ModelBased" >
<Child Name="SystemFunctions" IsSystemObject="1"/>
<Child Name="TableValuedFunctions"/>
<Child Name="ScalarValuedFunctions"/>
<Child Name="AggregateFunctions"/>
</Node>
<Node Name="SystemFunctions" LocLabel="SR.SchemaHierarchy_SystemFunctions" BaseClass="ModelBased" IsMsShippedOwned="true" Strategy="MultipleElementsOfType" TreeNode="TableValuedFunctionTreeNode">
<Child Name="SystemTableValuedFunctions" IsSystemObject="1"/>
<Child Name="SystemScalarValuedFunctions" IsSystemObject="1"/>
</Node>
<Node Name="DatabaseTriggers" LocLabel="SR.SchemaHierarchy_DatabaseTriggers" BaseClass="ModelBased" NodeType="DatabaseTrigger" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlDatabaseDdlTrigger" ValidFor="Sql2005|Sql2008|Sql2012|Sql2014|Sql2016|Sql2017|AzureV12"/>
<Node Name="Assemblies" LocLabel="SR.SchemaHierarchy_Assemblies" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="Assembly" ChildQuerierTypes="SqlAssembly" ValidFor="AllOnPrem|AzureV12"/>
<Node Name="Types" LocLabel="SR.SchemaHierarchy_Types" BaseClass="ModelBased" >
<Child Name="SystemDataTypes" IsSystemObject="1"/>
<Child Name="UserDefinedDataTypes"/>
<Child Name="UserDefinedTableTypes"/>
<Child Name="UserDefinedTypes"/>
<Child Name="XmlSchemaCollections"/>
</Node>
<!--==
<Node Name="Rules" LocLabel="SR.SchemaHierarchy_Rules" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="Rule" ChildQuerierTypes="SqlRule" ValidFor="AllOnPrem|AzureV12"/>
<Node Name="Defaults" LocLabel="SR.SchemaHierarchy_Defaults" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="Default" ChildQuerierTypes="SqlDefault" ValidFor="AllOnPrem|AzureV12"/>
-->
<Node Name="Sequences" LocLabel="SR.SchemaHierarchy_Sequences" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="Sequence" ChildQuerierTypes="SqlSequence" ValidFor="Sql2012|Sql2014|Sql2016|Sql2017|AzureV12"/>
<Node Name="SystemDataTypes" LocLabel="SR.SchemaHierarchy_SystemDataTypes" BaseClass="ModelBased" >
<Child Name="SystemExactNumerics"/>
<Child Name="SystemApproximateNumerics"/>
<Child Name="SystemDateAndTimes"/>
<Child Name="SystemCharacterStrings"/>
<Child Name="SystemUnicodeCharacterStrings"/>
<Child Name="SystemBinaryStrings"/>
<Child Name="SystemOtherDataTypes"/>
<Child Name="SystemClrDataTypes"/>
<Child Name="SystemSpatialDataTypes"/>
</Node>
<Node Name="UserDefinedDataTypes" LocLabel="SR.SchemaHierarchy_UserDefinedDataTypes" BaseClass="ModelBased" NodeType="UserDefinedDataType" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlUserDefinedDataType" ValidFor="Sql2005|Sql2008|Sql2012|Sql2014|Sql2016|Sql2017|AzureV12"/>
<Node Name="UserDefinedTableTypes" LocLabel="SR.SchemaHierarchy_UserDefinedTableTypes" BaseClass="ModelBased" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlUserDefinedTableType" TreeNode="UserDefinedTableTypeTreeNode" ValidFor="Sql2008|Sql2012|Sql2014|Sql2016|Sql2017|AzureV12"/>
<Node Name="UserDefinedTypes" LocLabel="SR.SchemaHierarchy_UserDefinedTypes" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="UserDefinedType" ChildQuerierTypes="SqlUserDefinedType" ValidFor="AllOnPrem|AzureV12"/>
<Node Name="XmlSchemaCollections" LocLabel="SR.SchemaHierarchy_XMLSchemaCollections" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="XmlSchemaCollection" ChildQuerierTypes="SqlXmlSchemaCollection" ValidFor="AllOnPrem|AzureV12"/>
<Node Name="UserDefinedTableType" LocLabel="string.Empty" BaseClass="ModelBased" ChildQuerierTypes="" NodeType="UserDefinedTableType" IsAsyncLoad="" Strategy="PopulateDetails">
<Child Name="UserDefinedTableTypeColumns"/>
<Child Name="UserDefinedTableTypeKeys"/>
<Child Name="UserDefinedTableTypeConstraints"/>
</Node>
<Node Name="UserDefinedTableTypeColumns" LocLabel="SR.SchemaHierarchy_Columns" BaseClass="ModelBased" NodeType="UserDefinedTableTypeColumn" Strategy="PopulateParentDetails" ChildQuerierTypes="SqlColumn" DisableSort=""/>
<Node Name="UserDefinedTableTypeKeys" LocLabel="SR.SchemaHierarchy_Keys" BaseClass="ModelBased" NodeType="UserDefinedTableTypeKey" Strategy="PopulateParentDetails" ChildQuerierTypes="SqlIndex">
<Filters>
<Filter TypeToReverse="SqlIndex" Property="IndexKeyType" Type="Enum" ValidFor="Sql2016|Sql2017|AzureV12">
<Value>IndexKeyType.DriPrimaryKey</Value>
<Value>IndexKeyType.DriUniqueKey</Value>
</Filter>
</Filters>
</Node>
<Node Name="UserDefinedTableTypeConstraints" LocLabel="SR.SchemaHierarchy_Constraints" BaseClass="ModelBased" NodeType="UserDefinedTableTypeConstraint" Strategy="PopulateParentDetails" ChildQuerierTypes="SqlDefaultConstraint;SqlCheck"/>/>
<Node Name="SystemExactNumerics" LocLabel="SR.SchemaHierarchy_SystemExactNumerics" BaseClass="ModelBased" NodeType="SystemExactNumeric" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlBuiltInType"/>
<Node Name="SystemApproximateNumerics" LocLabel="SR.SchemaHierarchy_SystemApproximateNumerics" BaseClass="ModelBased" NodeType="SystemApproximateNumeric" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlBuiltInType"/>
<Node Name="SystemDateAndTimes" LocLabel="SR.SchemaHierarchy_SystemDateAndTime" BaseClass="ModelBased" NodeType="SystemDateAndTime" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlBuiltInType"/>
<Node Name="SystemCharacterStrings" LocLabel="SR.SchemaHierarchy_SystemCharacterStrings" BaseClass="ModelBased" NodeType="SystemCharacterString" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlBuiltInType"/>
<Node Name="SystemUnicodeCharacterStrings" LocLabel="SR.SchemaHierarchy_SystemUnicodeCharacterStrings" BaseClass="ModelBased" NodeType="SystemUnicodeCharacterString" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlBuiltInType"/>
<Node Name="SystemBinaryStrings" LocLabel="SR.SchemaHierarchy_SystemBinaryStrings" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="SystemBinaryString" ChildQuerierTypes="SqlBuiltInType"/>
<Node Name="SystemOtherDataTypes" LocLabel="SR.SchemaHierarchy_SystemOtherDataTypes" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="SystemOtherDataType" ChildQuerierTypes="SqlBuiltInType"/>
<Node Name="SystemClrDataTypes" LocLabel="SR.SchemaHierarchy_SystemCLRDataTypes" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="SystemClrDataType" ChildQuerierTypes="SqlBuiltInType" ValidFor="All"/>
<Node Name="SystemSpatialDataTypes" LocLabel="SR.SchemaHierarchy_SystemSpatialDataTypes" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="SystemSpatialDataType" ChildQuerierTypes="SqlBuiltInType" ValidFor="Sql2008|Sql2012|Sql2014|Sql2016|Sql2017|AzureV12"/>
<!-- Childs of ExternalResources -->
<Node Name="ExternalDataSources" LocLabel="SR.SchemaHierarchy_ExternalDataSources" BaseClass="ModelBased" NodeType="ExternalDataSource" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlExternalDataSource" ValidFor="Sql2016|Sql2017|AzureV12"/>
<Node Name="ExternalFileFormats" LocLabel="SR.SchemaHierarchy_ExternalFileFormats" BaseClass="ModelBased" NodeType="ExternalFileFormat" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlExternalFileFormat" ValidFor="Sql2016|Sql2017"/>
<Node Name="StoredProcedures" LocLabel="SR.SchemaHierarchy_StoredProcedures" BaseClass="ModelBased" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlProcedure" TreeNode="StoredProcedureTreeNode">
<Filters >
<Filter Property="IsSystemObject" Value="0" Type="bool" />
</Filters>
<Child Name="SystemStoredProcedures" IsSystemObject="1"/>
</Node>
<Node Name="SystemStoredProcedures" LocLabel="SR.SchemaHierarchy_SystemStoredProcedures" BaseClass="ModelBased" IsMsShippedOwned="true" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlProcedure" TreeNode="StoredProcedureTreeNode">
<Filters >
<Filter Property="IsSystemObject" Value="1" Type="bool" />
</Filters>
</Node>
<Node Name="StoredProcedure" LocLabel="string.Empty" BaseClass="ModelBased" ChildQuerierTypes="" NodeType="StoredProcedure" IsAsyncLoad="" Strategy="PopulateDetails">
<Child Name="StoredProcedureParameters"/>
</Node>
<Node Name="StoredProcedureParameters" LocLabel="SR.SchemaHierarchy_Parameters" BaseClass="ModelBased" NodeType="StoredProcedureParameter" Strategy="StoredProcedureParameters" ChildQuerierTypes="SqlSubroutineParameter" DisableSort=""/>
<Node Name="TableValuedFunctions" LocLabel="SR.SchemaHierarchy_TableValuedFunctions" BaseClass="ModelBased" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlUserDefinedFunction" TreeNode="TableValuedFunctionTreeNode" ValidFor="NotSqlDw">
<Filters >
<Filter Property="FunctionType" Type="Enum">
<Value>UserDefinedFunctionType.Table</Value>
<Value>UserDefinedFunctionType.Inline</Value>
</Filter>
<Filter Property="IsSystemObject" Value="0" Type="bool" />
</Filters>
</Node>
<Node Name="SystemTableValuedFunctions" LocLabel="SR.SchemaHierarchy_TableValuedFunctions" BaseClass="ModelBased" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlUserDefinedFunction" TreeNode="TableValuedFunctionTreeNode" ValidFor="NotSqlDw">
<Filters >
<Filter Property="FunctionType" Type="Enum">
<Value>UserDefinedFunctionType.Table</Value>
<Value>UserDefinedFunctionType.Inline</Value>
</Filter>
<Filter Property="IsSystemObject" Value="1" Type="bool" />
</Filters>
</Node>
<Node Name="TableValuedFunction" LocLabel="string.Empty" BaseClass="ModelBased" ChildQuerierTypes="" NodeType="TableValuedFunction" IsAsyncLoad="" Strategy="PopulateDetails">
<Child Name="TableValuedFunctionParameters"/>
</Node>
<Node Name="TableValuedFunctionParameters" LocLabel="SR.SchemaHierarchy_Parameters" BaseClass="ModelBased" NodeType="TableValuedFunctionParameter" Strategy="FunctionParameters" ChildQuerierTypes="SqlSubroutineParameter" DisableSort="">
</Node>
<Node Name="ScalarValuedFunctions" LocLabel="SR.SchemaHierarchy_ScalarValuedFunctions" BaseClass="ModelBased" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlUserDefinedFunction" TreeNode="ScalarValuedFunctionTreeNode" >
<Filters>
<Filter Property="FunctionType" Type="Enum" ValidFor="NotSqlDw">
<Value>UserDefinedFunctionType.Scalar</Value>
</Filter>
<Filter Property="IsSystemObject" Value="0" Type="bool" />
</Filters>
</Node>
<Node Name="SystemScalarValuedFunctions" LocLabel="SR.SchemaHierarchy_ScalarValuedFunctions" BaseClass="ModelBased" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlUserDefinedFunction" TreeNode="ScalarValuedFunctionTreeNode" >
<Filters>
<Filter Property="FunctionType" Type="Enum" ValidFor="NotSqlDw">
<Value>UserDefinedFunctionType.Scalar</Value>
</Filter>
<Filter Property="IsSystemObject" Value="1" Type="bool" />
</Filters>
</Node>
<Node Name="ScalarValuedFunction" LocLabel="string.Empty" BaseClass="ModelBased" NodeType="ScalarValuedFunction" ChildQuerierTypes="" IsAsyncLoad="" Strategy="PopulateDetails">
<Child Name="ScalarValuedFunctionParameters"/>
</Node>
<Node Name="ScalarValuedFunctionParameters" LocLabel="SR.SchemaHierarchy_Parameters" NodeType="ScalarValuedFunctionParameter" BaseClass="ModelBased" Strategy="FunctionParameters" ChildQuerierTypes="SqlSubroutineParameter" DisableSort=""/>
<Node Name="AggregateFunctions" LocLabel="SR.SchemaHierarchy_AggregateFunctions" BaseClass="ModelBased" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlUserDefinedAggregate" TreeNode="AggregateFunctionTreeNode" ValidFor="AllOnPrem|AzureV12">
</Node>
<Node Name="AggregateFunction" LocLabel="string.Empty" BaseClass="ModelBased" ChildQuerierTypes="" NodeType="AggregateFunction" IsAsyncLoad="" Strategy="PopulateDetails">
<Child Name="AggregateFunctionParameters"/>
</Node>
<Node Name="AggregateFunctionParameters" LocLabel="SR.SchemaHierarchy_Parameters" BaseClass="ModelBased" NodeType="AggregateFunctionParameter" Strategy="PopulateParentDetails" ChildQuerierTypes="SqlSubroutineParameter" DisableSort=""/>
<!-- TODO Support Route in SMO
<Node Name="Routes" LocLabel="SR.SchemaHierarchy_Routes" BaseClass="ModelBased" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlRoute"/>
-->
<!-- TODO support events
<Node Name="DatabaseAndQueueEventNotifications" LocLabel="SR.SchemaHierarchy_EventNotifications" BaseClass="ModelBased" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlEventNotification"/>
-->
<Node Name="RemoteServiceBindings" LocLabel="SR.SchemaHierarchy_RemoteServiceBindings" BaseClass="ModelBased" NodeType="RemoteServiceBinding" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlRemoteServiceBinding"/>
<Node Name="BrokerPriorities" LocLabel="SR.SchemaHierarchy_BrokerPriorities" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="BrokerPriority" ChildQuerierTypes="SqlBrokerPriority" ValidFor="Sql2008|Sql2012|Sql2014|Sql2016|Sql2017"/>
<Node Name="FileGroups" LocLabel="SR.SchemaHierarchy_FileGroups" BaseClass="ModelBased" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlFileGroup" TreeNode="FileGroupTreeNode"/>
<Node Name="FullTextCatalogs" LocLabel="SR.SchemaHierarchy_FullTextCatalogs" BaseClass="ModelBased" NodeType="FullTextCatalog" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlFullTextCatalog"/>
<Node Name="FullTextStopLists" LocLabel="SR.SchemaHierarchy_FullTextStopLists" BaseClass="ModelBased" NodeType="FullTextStopList" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlFullTextStopList" ValidFor="Sql2008|Sql2012|Sql2014|Sql2016|Sql2017|AzureV12"/>
<Node Name="SqlLogFiles" LocLabel="SR.SchemaHierarchy_LogFiles" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="SqlLogFile" ChildQuerierTypes="SqlFile"/>
<Node Name="PartitionFunctions" LocLabel="SR.SchemaHierarchy_PartitionFunctions" BaseClass="ModelBased" NodeType="PartitionFunction" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlPartitionFunction"/>
<Node Name="PartitionSchemes" LocLabel="SR.SchemaHierarchy_PartitionSchemes" BaseClass="ModelBased" NodeType="PartitionScheme" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlPartitionScheme"/>
<Node Name="SearchPropertyLists" LocLabel="SR.SchemaHierarchy_SearchPropertyLists" BaseClass="ModelBased" NodeType="SearchPropertyList" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlSearchPropertyList" ValidFor="Sql2012|Sql2014|Sql2016|Sql2017|AzureV12"/>
<Node Name="FileGroup" LocLabel="string.Empty" BaseClass="ModelBased" ChildQuerierTypes="">
<Child Name="FileGroupFiles"/>
</Node>
<Node Name="FileGroupFiles" LocLabel="SR.SchemaHierarchy_FilegroupFiles" BaseClass="ModelBased" NodeType="FileGroupFile" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlFile" >
</Node>
<Node Name="Users" LocLabel="SR.SchemaHierarchy_Users" BaseClass="ModelBased" NodeType="User" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlUser"/>
<Node Name="Roles" LocLabel="SR.SchemaHierarchy_Roles" NodeType="Role" BaseClass="ModelBased" >
<Child Name="DatabaseRoles"/>
<Child Name="ApplicationRoles"/>
</Node>
<Node Name="Schemas" LocLabel="SR.SchemaHierarchy_Schemas" BaseClass="ModelBased" NodeType="Schema" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlSchema"/>
<Node Name="AsymmetricKeys" LocLabel="SR.SchemaHierarchy_AsymmetricKeys" BaseClass="ModelBased" NodeType="AsymmetricKey" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlAsymmetricKey" ValidFor="AllOnPrem"/>
<Node Name="Certificates" LocLabel="SR.SchemaHierarchy_Certificates" BaseClass="ModelBased" NodeType="Certificate" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlCertificate" ValidFor="AllOnPrem"/>
<Node Name="SymmetricKeys" LocLabel="SR.SchemaHierarchy_SymmetricKeys" BaseClass="ModelBased" NodeType="SymmetricKey" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlSymmetricKey" ValidFor="AllOnPrem"/>
<Node Name="DatabaseEncryptionKeys" LocLabel="SR.SchemaHierarchy_DatabaseEncryptionKeys" BaseClass="ModelBased" NodeType="DatabaseEncryptionKey" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlDatabaseEncryptionKey" ValidFor="Sql2008|Sql2012|Sql2014|Sql2016|Sql2017"/>
<Node Name="MasterKeys" LocLabel="SR.SchemaHierarchy_MasterKeys" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="MasterKey" ChildQuerierTypes="SqlMasterKey" ValidFor="AllOnPrem"/>
<!-- TODO Support signatures
<Node Name="Signatures" LocLabel="SR.SchemaHierarchy_Signatures" BaseClass="ModelBased" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlSignature" ValidFor="Sql2005|Sql2008|Sql2012|Sql2014|Sql2016|Sql2017"/>
-->
<Node Name="DatabaseAuditSpecifications" LocLabel="SR.SchemaHierarchy_DatabaseAuditSpecifications" BaseClass="ModelBased" NodeType="DatabaseAuditSpecification" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlDatabaseAuditSpecification" ValidFor="Sql2008|Sql2012|Sql2014|Sql2016|Sql2017"/>
<Node Name="SecurityPolicies" LocLabel="SR.SchemaHierarchy_SecurityPolicies" BaseClass="ModelBased" Strategy="MultipleElementsOfType" NodeType="SecurityPolicy" ChildQuerierTypes="SqlSecurityPolicy" ValidFor="Sql2016|Sql2017|AzureV12"/>
<Node Name="DatabaseScopedCredentials" LocLabel="SR.SchemaHierarchy_DatabaseScopedCredentials" BaseClass="ModelBased" NodeType="DatabaseScopedCredential" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlDatabaseCredential" ValidFor="Sql2016|Sql2017|AzureV12"/>
<Node Name="AlwaysEncryptedKeys" LocLabel="SR.SchemaHierarchy_AlwaysEncryptedKeys" BaseClass="ModelBased" ValidFor="Sql2016|Sql2017|AzureV12">
<Child Name="ColumnMasterKeys"/>
<Child Name="ColumnEncryptionKeys"/>
</Node>
<Node Name="DatabaseRoles" LocLabel="SR.SchemaHierarchy_DatabaseRoles" BaseClass="ModelBased" NodeType="DatabaseRole" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlRole"/>
<Node Name="ApplicationRoles" LocLabel="SR.SchemaHierarchy_ApplicationRoles" BaseClass="ModelBased" NodeType="ApplicationRole" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlApplicationRole" ValidFor="AllOnPrem|AzureV12"/>
<Node Name="ColumnMasterKeys" LocLabel="SR.SchemaHierarchy_ColumnMasterKeys" BaseClass="ModelBased" NodeType="ColumnMasterKey" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlColumnMasterKey" ValidFor="Sql2016|Sql2017|AzureV12"/>
<Node Name="ColumnEncryptionKeys" LocLabel="SR.SchemaHierarchy_ColumnEncryptionKeys" BaseClass="ModelBased" NodeType="ColumnEncryptionKey" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlColumnEncryptionKey" ValidFor="Sql2016|Sql2017|AzureV12"/>
<Node Name="MessageTypes" LocLabel="SR.SchemaHierarchy_MessageTypes" BaseClass="ModelBased" NodeType="MessageType" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlMessageType">
<Child Name="SystemMessageTypes" IsSystemObject="1"/>
</Node>
<Node Name="SystemMessageTypes" LocLabel="SR.SchemaHierarchy_SystemMessageTypes" BaseClass="ModelBased" NodeType="SystemMessageType" IsMsShippedOwned="true" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlMessageType"/>
<Node Name="Contracts" LocLabel="SR.SchemaHierarchy_Contracts" BaseClass="ModelBased" NodeType="Contract" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlContract">
<Child Name="SystemContracts" IsSystemObject="1"/>
</Node>
<Node Name="SystemContracts" LocLabel="SR.SchemaHierarchy_SystemContracts" BaseClass="ModelBased" NodeType="SystemContract" IsMsShippedOwned="true" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlContract"/>
<Node Name="Queues" LocLabel="SR.SchemaHierarchy_Queues" BaseClass="ModelBased" NodeType="Queue" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlQueue">
<Child Name="SystemQueues" IsSystemObject="1"/>
</Node>
<Node Name="SystemQueues" LocLabel="SR.SchemaHierarchy_SystemQueues" BaseClass="ModelBased" NodeType="SystemQueue" IsMsShippedOwned="true" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlQueue"/>
<Node Name="Services" LocLabel="SR.SchemaHierarchy_Services" BaseClass="ModelBased" NodeType="Service" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlService">
<Child Name="SystemServices" IsSystemObject="1"/>
</Node>
<Node Name="SystemServices" LocLabel="SR.SchemaHierarchy_SystemServices" BaseClass="ModelBased" NodeType="SystemService" IsMsShippedOwned="true" Strategy="MultipleElementsOfType" ChildQuerierTypes="SqlService"/>
<CodeGenOptions>
<UniqueTreeNode Name="DatabaseTreeNode"/>
<UniqueTreeNode Name="TableTreeNode"/>
<UniqueTreeNode Name="ViewTreeNode"/>
<UniqueTreeNode Name="UserDefinedTableTypeTreeNode"/>
<UniqueTreeNode Name="StoredProcedureTreeNode"/>
<UniqueTreeNode Name="TableValuedFunctionTreeNode"/>
<UniqueTreeNode Name="ScalarValuedFunctionTreeNode"/>
<UniqueTreeNode Name="AggregateFunctionTreeNode"/>
<UniqueTreeNode Name="FileGroupTreeNode"/>
<UniqueTreeNode Name="ExternalTableTreeNode"/>
<UniqueTreeNode Name="ExternalResourceTreeNode"/>
<UniqueTreeNode Name="HistoryTableTreeNode" />
</CodeGenOptions>
<!-- WARNING: Specifying reverse dependencies that could load large numbers of objects will be detrimental to performance. -->
<ReverseDependencyList>
<ReverseDependency Type="SqlUser" DependsOn="SqlRole;SqlRoleMembership"/>
</ReverseDependencyList>
</ServerExplorerTree>

View File

@@ -0,0 +1,564 @@
<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Xml.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Globalization" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
using System;
using System.Collections.Generic;
using System.Composition;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.Kusto.ServiceLayer;
using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes;
namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.SmoModel
{
<#
var directory = Path.GetDirectoryName(Host.TemplateFile);
string xmlFile = Path.Combine(directory, "TreeNodeDefinition.xml");
/////////
// TODO - is Generate all the ReverseDependencies needed?
/////////
// var allReverseDependencies = GetReverseDependencies(xmlFile);
// WriteLine(" internal static class TreeNodeRules");
// WriteLine(" {");
// WriteLine(" internal static Dictionary<Type, IList<Type>> TypeReverseDependencyMap = new Dictionary<Type, IList<Type>>()");
// WriteLine(" {");
// foreach (var reverseDependencyKey in allReverseDependencies.Keys)
// {
// bool isFirstDependentType = true;
// StringBuilder dependentListBuilder = new StringBuilder("{");
// foreach (var dependentType in allReverseDependencies[reverseDependencyKey])
// {
// if (isFirstDependentType)
// {
// isFirstDependentType = false;
// }
// else
// {
// dependentListBuilder.Append(",");
// }
//
// dependentListBuilder.Append(string.Format(CultureInfo.InvariantCulture, " typeof({0})", dependentType));
// }
// dependentListBuilder.Append(" }");
//
// WriteLine(string.Format(CultureInfo.InvariantCulture, " {{ typeof({0}), new List<Type> {1} }}", reverseDependencyKey, dependentListBuilder.ToString()));
// }
// WriteLine(" };");
// WriteLine(" }");
// WriteLine("");
/////////
// First generate all the TreeNodes
/////////
var allTreeNodes = GetUniqueTreeNodes(xmlFile);
foreach (var TreeNode in allTreeNodes)
{
var name = TreeNode.GetAttribute("Name");
WriteLine(string.Format(" internal sealed partial class {0} : OETreeNode", name));
WriteLine(" {");
WriteLine(string.Format(" public {0}() : base()", name));
WriteLine(" {");
WriteLine(" NodeValue = string.Empty;");
WriteLine(string.Format(" this.NodeType = \"{0}\";", name.Replace("TreeNode", string.Empty)));
WriteLine(string.Format(" this.NodeTypeId = NodeTypes.{0};", name.Replace("TreeNode", string.Empty)));
WriteLine(" OnInitialize();");
WriteLine(" }");
WriteLine(" }");
WriteLine("");
}
/////////
// Now generate all the ChildFactories
/////////
var allNodes = GetNodes(xmlFile);
foreach (var type in allNodes)
{
XmlElement nodeElement = GetNodeElement(xmlFile, type);
var imageAttr = nodeElement.GetAttribute("Image");
var isAlwaysLeaf = nodeElement.GetAttributeNode("IsAlwaysLeaf");
var baseClass = nodeElement.GetAttribute("BaseClass");
var strategy = nodeElement.GetAttribute("Strategy");
var nodeType = nodeElement.GetAttribute("NodeType");
var ChildQuerierTypes = nodeElement.GetAttribute("ChildQuerierTypes");
var TreeNode = nodeElement.GetAttribute("TreeNode");
var isAsync = nodeElement.GetAttributeNode("IsAsyncLoad");
var disableSort = nodeElement.GetAttributeNode("DisableSort");
string childFactoryBaseClass = "SmoChildFactoryBase";
// TODO Will we need alternative child factories? If so, add code here to support this
if (isAlwaysLeaf == null)
{
WriteLine(" [Export(typeof(ChildFactory))]");
WriteLine(" [Shared]");
WriteLine(string.Format(" internal partial class {0}ChildFactory : {1}", type, childFactoryBaseClass));
WriteLine(" {");
WriteLine(string.Format(" public override IEnumerable<string> ApplicableParents() {{ return new[] {{ \"{0}\" }}; }}", type));
List<XmlElement> children = GetChildren(xmlFile, type);
List<XmlElement> filters = GetNodeFilters(xmlFile, type);
List<XmlElement> smoProperties = GetNodeSmoProperties(xmlFile, type);
if (filters.Count > 0)
{
WriteLine("");
WriteLine(" public override IEnumerable<NodeFilter> Filters");
WriteLine(" {");
WriteLine(" get");
WriteLine(" {");
WriteLine(" var filters = new List<NodeFilter>();");
foreach (var filter in filters)
{
var propertyName = filter.GetAttribute("Property");
var propertyType = filter.GetAttribute("Type");
var propertyValue = filter.GetAttribute("Value");
var validFor = filter.GetAttribute("ValidFor");
var typeToReverse = filter.GetAttribute("TypeToReverse");
List<XmlElement> filterValues = GetNodeFilterValues(xmlFile, type, propertyName);
WriteLine(" filters.Add(new NodeFilter");
WriteLine(" {");
WriteLine(string.Format(" Property = \"{0}\",", propertyName));
WriteLine(string.Format(" Type = typeof({0}),", propertyType));
if (!string.IsNullOrWhiteSpace(typeToReverse))
{
WriteLine(string.Format(" TypeToReverse = typeof({0}Querier),", typeToReverse));
}
if (!string.IsNullOrWhiteSpace(validFor))
{
WriteLine(string.Format(" ValidFor = {0},", GetValidForFlags(validFor)));
}
if (propertyValue != null && (filterValues == null || filterValues.Count == 0))
{
WriteLine(string.Format(" Values = new List<object> {{ {0} }},", propertyValue));
}
if (filterValues != null && filterValues.Count > 0)
{
string filterValueType = "object";
if (propertyType == "Enum")
{
}
WriteLine(string.Format(" Values = new List<object>"));
WriteLine(string.Format(" {{"));
for(int i = 0; i < filterValues.Count; i++)
{
string separator = "";
if (i != filterValues.Count - 1)
{
separator = ",";
}
var filterValue = filterValues[i];
WriteLine(string.Format(" {{ {0} }}{1}", filterValue.InnerText, separator ));
}
WriteLine(string.Format(" }}"));
}
WriteLine(" });");
}
WriteLine(" return filters;");
WriteLine(" }");
WriteLine(" }");
}
if (smoProperties.Count > 0)
{
WriteLine("");
WriteLine(" public override IEnumerable<NodeSmoProperty> SmoProperties");
WriteLine(" {");
WriteLine(" get");
WriteLine(" {");
WriteLine(" var properties = new List<NodeSmoProperty>();");
foreach (var smoPropertiy in smoProperties)
{
var propertyName = smoPropertiy.GetAttribute("Name");
var validFor = smoPropertiy.GetAttribute("ValidFor");
WriteLine(" properties.Add(new NodeSmoProperty");
WriteLine(" {");
WriteLine(string.Format(" Name = \"{0}\",", propertyName));
if (!string.IsNullOrWhiteSpace(validFor))
{
WriteLine(string.Format(" ValidFor = {0}", GetValidForFlags(validFor)));
}
WriteLine(" });");
}
WriteLine(" return properties;");
WriteLine(" }");
WriteLine(" }");
}
if (children.Count > 0)
{
WriteLine("");
WriteLine(" protected override void OnExpandPopulateFolders(IList<TreeNode> currentChildren, TreeNode parent)");
WriteLine(" {");
foreach (var child in children)
{
XmlElement childAsXmlElement = GetNodeElement(xmlFile, child.GetAttribute("Name"));
if (childAsXmlElement == null)
{
// TODO SHould we error with clear message that this needs to be fixed?
continue;
}
string childImage = childAsXmlElement.GetAttribute("Image");
var msShippedOwned = childAsXmlElement.GetAttributeNode("IsMsShippedOwned");
var validFor = childAsXmlElement.GetAttribute("ValidFor");
if (TreeNodeExists(xmlFile, child.GetAttribute("Name") + "TreeNode"))
{
WriteLine(string.Format(" currentChildren.Add(new {0}TreeNode {{ SortPriority = OETreeNode.NextSortPriority }} );", child.GetAttribute("Name")));
}
else
{
WriteLine(" currentChildren.Add(new FolderNode {");
WriteLine(string.Format(" NodeValue = {0},", childAsXmlElement.GetAttribute("LocLabel")));
WriteLine(string.Format(" NodeType = \"{0}\",", "Folder"));
WriteLine(string.Format(" NodeTypeId = NodeTypes.{0},", child.GetAttribute("Name")));
WriteLine(string.Format(" IsSystemObject = {0},", child.GetAttribute("IsSystemObject") == "1" ? "true" : "false"));
if (msShippedOwned != null)
{
WriteLine(" IsMsShippedOwned = true,");
}
if (!string.IsNullOrWhiteSpace(validFor))
{
WriteLine(string.Format(" ValidFor = {0},", GetValidForFlags(validFor)));
}
WriteLine(" SortPriority = OETreeNode.NextSortPriority,");
WriteLine(" });");
}
}
WriteLine(" }");
}
if (!string.IsNullOrWhiteSpace(strategy))
{
string[] allTypes = ChildQuerierTypes.Split(new [] { ';' }, StringSplitOptions.RemoveEmptyEntries);
WriteLine("");
WriteLine(" internal override Type[] ChildQuerierTypes");
WriteLine(" {");
WriteLine(" get");
WriteLine(" {");
if (!string.IsNullOrWhiteSpace(ChildQuerierTypes))
{
Write(" return new [] {");
foreach (var typeToRe in allTypes)
{
Write(string.Format(" typeof({0}Querier),", typeToRe));
}
WriteLine(" };");
}
else
{
Write(" return new Type[0];");
}
WriteLine(" }");
WriteLine(" }");
WriteLine("");
WriteLine(" public override TreeNode CreateChild(TreeNode parent, object context)");
WriteLine(" {");
if (string.IsNullOrWhiteSpace(TreeNode))
{
WriteLine(" var child = new OETreeNode();");
WriteLine(" child.IsAlwaysLeaf = true;");
if (!string.IsNullOrEmpty(nodeType))
{
WriteLine(string.Format(" child.NodeType = \"{0}\";", nodeType));
}
}
else
{
var modelNodeChildren = GetNodeElement(xmlFile, TreeNode.Replace("TreeNode",string.Empty));
WriteLine(string.Format(" var child = new {0}();", TreeNode));
if (modelNodeChildren.ChildNodes.Count == 0)
{
WriteLine(" child.IsAlwaysLeaf = true;");
}
}
if (disableSort != null)
{
WriteLine(" child.SortPriority = OETreeNode.NextSortPriority;");
}
WriteLine(" InitializeChild(parent, child, context);");
WriteLine(" return child;");
WriteLine(" }");
}
else if (baseClass == "ModelBased")
{
WriteLine("");
WriteLine(" internal override Type[] ChildQuerierTypes { get {return null;} }");
WriteLine("");
// TODO Is reverse engineering strategy every needed?
// WriteLine(" protected override ReverseEngineeringStrategy Strategy { get {return ReverseEngineeringStrategy.None;} }");
WriteLine("");
WriteLine(" public override TreeNode CreateChild(TreeNode parent, object context)");
WriteLine(" {");
WriteLine(" return null;");
WriteLine(" }");
}
WriteLine(" }");
WriteLine("");
}
}
#>
}
<#+
public static string GetValidForFlags(string validForStr)
{
List<string> flags = new List<string>();
if (validForStr.Contains("Sql2005"))
{
flags.Add("ValidForFlag.Sql2005");
}
if (validForStr.Contains("Sql2008"))
{
flags.Add("ValidForFlag.Sql2008");
}
if (validForStr.Contains("Sql2012"))
{
flags.Add("ValidForFlag.Sql2012");
}
if (validForStr.Contains("Sql2014"))
{
flags.Add("ValidForFlag.Sql2014");
}
if (validForStr.Contains("Sql2016"))
{
flags.Add("ValidForFlag.Sql2016");
}
if (validForStr.Contains("Sql2017"))
{
flags.Add("ValidForFlag.Sql2017");
}
if (validForStr.Contains("AzureV12"))
{
flags.Add("ValidForFlag.AzureV12");
}
if (validForStr.Contains("AllOnPrem"))
{
flags.Add("ValidForFlag.AllOnPrem");
}
if (validForStr.Contains("AllAzure"))
{
flags.Add("ValidForFlag.AllAzure");
}
if (validForStr.Contains("NotSqlDw"))
{
flags.Add("ValidForFlag.NotSqlDw");
}
if (validForStr == "All")
{
flags.Add("ValidForFlag.All");
}
return string.Join("|", flags);
}
public static string[] GetNodes(string xmlFile)
{
List<string> typesList = new List<string>();
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
XmlNodeList treeTypes = doc.SelectNodes("/ServerExplorerTree/Node");
if (treeTypes != null)
{
foreach (var type in treeTypes)
{
XmlElement element = type as XmlElement;
if (element != null)
{
typesList.Add(element.GetAttribute("Name"));
}
}
}
return typesList.ToArray();
}
public static Dictionary<string, List<string>> GetReverseDependencies(string xmlFile)
{
Dictionary<string, List<string>> dependencyMap = new Dictionary<string, List<string>>();
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
XmlNodeList treeTypes = doc.SelectNodes("/ServerExplorerTree/ReverseDependencyList/ReverseDependency");
if (treeTypes != null)
{
foreach (var type in treeTypes)
{
XmlElement element = type as XmlElement;
if (element != null)
{
string typeName = element.GetAttribute("Type");
string dependency = element.GetAttribute("DependsOn");
List<string> dependenciesForType;
if (dependencyMap.TryGetValue(typeName, out dependenciesForType))
{
dependenciesForType.Add(dependency);
}
else
{
string[] allDepedencies = dependency.Split(new [] { ';' }, StringSplitOptions.RemoveEmptyEntries);
dependenciesForType = new List<string>();
dependenciesForType.AddRange(allDepedencies);
dependencyMap.Add(typeName, dependenciesForType);
}
}
}
}
return dependencyMap;
}
public static XmlElement GetNodeElement(string xmlFile, string nodeName)
{
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
return (XmlElement)doc.SelectSingleNode(string.Format("/ServerExplorerTree/Node[@Name='{0}']", nodeName));
}
public static bool TreeNodeExists(string xmlFile, string TreeNode)
{
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
var found = (XmlElement)doc.SelectSingleNode(string.Format("/ServerExplorerTree/CodeGenOptions/UniqueTreeNode[@Name='{0}']", TreeNode));
return (found != null);
}
public static List<XmlElement> GetUniqueTreeNodes(string xmlFile)
{
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
List<XmlElement> retElements = new List<XmlElement>();
XmlNodeList nodeList = doc.SelectNodes("/ServerExplorerTree/CodeGenOptions/UniqueTreeNode");
foreach (var item in nodeList)
{
XmlElement itemAsElement = item as XmlElement;
if (itemAsElement != null)
{
retElements.Add(itemAsElement);
}
}
return retElements;
}
public static List<XmlElement> GetChildren(string xmlFile, string parentName)
{
XmlElement nodeElement = GetNodeElement(xmlFile, parentName);
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
List<XmlElement> retElements = new List<XmlElement>();
XmlNodeList nodeList = doc.SelectNodes(string.Format("/ServerExplorerTree/Node[@Name='{0}']/Child", parentName));
foreach (var item in nodeList)
{
XmlElement itemAsElement = item as XmlElement;
if (itemAsElement != null)
{
retElements.Add(itemAsElement);
}
}
return retElements;
}
public static List<XmlElement> GetNodeFilters(string xmlFile, string parentName)
{
XmlElement nodeElement = GetNodeElement(xmlFile, parentName);
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
List<XmlElement> retElements = new List<XmlElement>();
XmlNodeList nodeList = doc.SelectNodes(string.Format("/ServerExplorerTree/Node[@Name='{0}']/Filters/Filter", parentName));
foreach (var item in nodeList)
{
XmlElement itemAsElement = item as XmlElement;
if (itemAsElement != null)
{
retElements.Add(itemAsElement);
}
}
return retElements;
}
public static List<XmlElement> GetNodeSmoProperties(string xmlFile, string parentName)
{
XmlElement nodeElement = GetNodeElement(xmlFile, parentName);
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
List<XmlElement> retElements = new List<XmlElement>();
XmlNodeList nodeList = doc.SelectNodes(string.Format("/ServerExplorerTree/Node[@Name='{0}']/Properties/Property", parentName));
foreach (var item in nodeList)
{
XmlElement itemAsElement = item as XmlElement;
if (itemAsElement != null)
{
retElements.Add(itemAsElement);
}
}
return retElements;
}
public static List<XmlElement> GetNodeFilterValues(string xmlFile, string parentName, string filterProperty)
{
XmlElement nodeElement = GetNodeElement(xmlFile, parentName);
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
List<XmlElement> retElements = new List<XmlElement>();
XmlNodeList nodeList = doc.SelectNodes(string.Format("/ServerExplorerTree/Node[@Name='{0}']/Filters/Filter[@Property='{1}']/Value", parentName, filterProperty));
foreach (var item in nodeList)
{
XmlElement itemAsElement = item as XmlElement;
if (itemAsElement != null)
{
retElements.Add(itemAsElement);
}
}
return retElements;
}
#>