Adding filtering support to OE (#2039)

* Init push

* Fixing filters

* Fixing more filters

* Fixing display strings

* Fixing boolean filter

* Adding comments

* Fixing function name

* Making nullables

* Separating filter parsing logic

* Adding tests

* Update src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/ObjectExplorerUtils.cs

Co-authored-by: Cheena Malhotra <13396919+cheenamalhotra@users.noreply.github.com>

* Update src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/ObjectExplorerUtils.cs

Co-authored-by: Cheena Malhotra <13396919+cheenamalhotra@users.noreply.github.com>

* Update src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Contracts/NodeInfo.cs

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>

* Update src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Contracts/NodeInfo.cs

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>

* Update src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/Nodes/TreeNode.cs

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>

* Adding comments

* Fixing whitespace

* Adding more  comments and changing to IEnumerable

* Fixing code comments

* Fixing tests adding more filters

---------

Co-authored-by: Cheena Malhotra <13396919+cheenamalhotra@users.noreply.github.com>
Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>
This commit is contained in:
Aasim Khan
2023-05-05 13:22:42 -07:00
committed by GitHub
parent 1b5f774741
commit 46e6b484a3
18 changed files with 2013 additions and 81 deletions

View File

@@ -2381,6 +2381,134 @@ namespace Microsoft.SqlTools.ServiceLayer
}
}
public static string FilterName
{
get
{
return Keys.GetString(Keys.FilterName);
}
}
public static string FilterNameDescription
{
get
{
return Keys.GetString(Keys.FilterNameDescription);
}
}
public static string FilterSchema
{
get
{
return Keys.GetString(Keys.FilterSchema);
}
}
public static string FilterSchemaDescription
{
get
{
return Keys.GetString(Keys.FilterSchemaDescription);
}
}
public static string FilterOwner
{
get
{
return Keys.GetString(Keys.FilterOwner);
}
}
public static string FilterOwnerDescription
{
get
{
return Keys.GetString(Keys.FilterOwnerDescription);
}
}
public static string FilterDurabilityType
{
get
{
return Keys.GetString(Keys.FilterDurabilityType);
}
}
public static string FilterDurabilityTypeDescription
{
get
{
return Keys.GetString(Keys.FilterDurabilityTypeDescription);
}
}
public static string FilterIsMemoryOptimized
{
get
{
return Keys.GetString(Keys.FilterIsMemoryOptimized);
}
}
public static string FilterIsMemoryOptimizedDescription
{
get
{
return Keys.GetString(Keys.FilterIsMemoryOptimizedDescription);
}
}
public static string FilterCreateDate
{
get
{
return Keys.GetString(Keys.FilterCreateDate);
}
}
public static string FilterCreateDateDescription
{
get
{
return Keys.GetString(Keys.FilterCreateDateDescription);
}
}
public static string FilterIsNativelyCompiled
{
get
{
return Keys.GetString(Keys.FilterIsNativelyCompiled);
}
}
public static string FilterIsNativelyCompiledDescription
{
get
{
return Keys.GetString(Keys.FilterIsNativelyCompiledDescription);
}
}
public static string FilterInPrimaryKey
{
get
{
return Keys.GetString(Keys.FilterInPrimaryKey);
}
}
public static string FilterInPrimaryKeyDescription
{
get
{
return Keys.GetString(Keys.FilterInPrimaryKeyDescription);
}
}
public static string ScriptingParams_ConnectionString_Property_Invalid
{
get
@@ -12045,6 +12173,54 @@ namespace Microsoft.SqlTools.ServiceLayer
public const string DatabaseNotAccessible = "DatabaseNotAccessible";
public const string FilterName = "FilterName";
public const string FilterNameDescription = "FilterNameDescription";
public const string FilterSchema = "FilterSchema";
public const string FilterSchemaDescription = "FilterSchemaDescription";
public const string FilterOwner = "FilterOwner";
public const string FilterOwnerDescription = "FilterOwnerDescription";
public const string FilterDurabilityType = "FilterDurabilityType";
public const string FilterDurabilityTypeDescription = "FilterDurabilityTypeDescription";
public const string FilterIsMemoryOptimized = "FilterIsMemoryOptimized";
public const string FilterIsMemoryOptimizedDescription = "FilterIsMemoryOptimizedDescription";
public const string FilterCreateDate = "FilterCreateDate";
public const string FilterCreateDateDescription = "FilterCreateDateDescription";
public const string FilterIsNativelyCompiled = "FilterIsNativelyCompiled";
public const string FilterIsNativelyCompiledDescription = "FilterIsNativelyCompiledDescription";
public const string FilterInPrimaryKey = "FilterInPrimaryKey";
public const string FilterInPrimaryKeyDescription = "FilterInPrimaryKeyDescription";
public const string ScriptingParams_ConnectionString_Property_Invalid = "ScriptingParams_ConnectionString_Property_Invalid";

View File

@@ -1458,6 +1458,70 @@
<value>The database {0} is not accessible.</value>
<comment></comment>
</data>
<data name="FilterName" xml:space="preserve">
<value>Name</value>
<comment></comment>
</data>
<data name="FilterNameDescription" xml:space="preserve">
<value>Include or exclude objects based on the name or part of a name.</value>
<comment></comment>
</data>
<data name="FilterSchema" xml:space="preserve">
<value>Schema</value>
<comment></comment>
</data>
<data name="FilterSchemaDescription" xml:space="preserve">
<value> Include or exclude objects based on the schema or part of a schema name.</value>
<comment></comment>
</data>
<data name="FilterOwner" xml:space="preserve">
<value>Owner</value>
<comment></comment>
</data>
<data name="FilterOwnerDescription" xml:space="preserve">
<value>Include or exclude objects based on the owner or part of an owner name.</value>
<comment></comment>
</data>
<data name="FilterDurabilityType" xml:space="preserve">
<value>Durability Type</value>
<comment></comment>
</data>
<data name="FilterDurabilityTypeDescription" xml:space="preserve">
<value>Include or exclude objects based on the durability type.</value>
<comment></comment>
</data>
<data name="FilterIsMemoryOptimized" xml:space="preserve">
<value>Is Memory Optimized</value>
<comment></comment>
</data>
<data name="FilterIsMemoryOptimizedDescription" xml:space="preserve">
<value>Include or exclude objects based on whether the object is memory optimized.</value>
<comment></comment>
</data>
<data name="FilterCreateDate" xml:space="preserve">
<value>Create Date</value>
<comment></comment>
</data>
<data name="FilterCreateDateDescription" xml:space="preserve">
<value>Select or type a creation date to include or exclude objects created at any time on that date, or enter a starting and ending date to include or exclude objects created in that inclusive date range.</value>
<comment></comment>
</data>
<data name="FilterIsNativelyCompiled" xml:space="preserve">
<value>Is Natively Compiled</value>
<comment></comment>
</data>
<data name="FilterIsNativelyCompiledDescription" xml:space="preserve">
<value>Include or exclude objects based on whether the object is natively compiled.</value>
<comment></comment>
</data>
<data name="FilterInPrimaryKey" xml:space="preserve">
<value>In Primary Key</value>
<comment></comment>
</data>
<data name="FilterInPrimaryKeyDescription" xml:space="preserve">
<value>Include or exclude objects based on whether the column is in a primary key.</value>
<comment></comment>
</data>
<data name="ScriptingParams_ConnectionString_Property_Invalid" xml:space="preserve">
<value>Error parsing ScriptingParams.ConnectionString property.</value>
<comment></comment>

View File

@@ -720,6 +720,22 @@ FileTable_LabelPart = File Table
DatabaseNotAccessible = The database {0} is not accessible.
FilterName = Name
FilterNameDescription = Include or exclude objects based on the name or part of a name.
FilterSchema = Schema
FilterSchemaDescription = Include or exclude objects based on the schema or part of a schema name.
FilterOwner = Owner
FilterOwnerDescription = Include or exclude objects based on the owner or part of an owner name.
FilterDurabilityType = Durability Type
FilterDurabilityTypeDescription = Include or exclude objects based on the durability type.
FilterIsMemoryOptimized = Is Memory Optimized
FilterIsMemoryOptimizedDescription = Include or exclude objects based on whether the object is memory optimized.
FilterCreateDate = Create Date
FilterCreateDateDescription = Select or type a creation date to include or exclude objects created at any time on that date, or enter a starting and ending date to include or exclude objects created in that inclusive date range.
FilterIsNativelyCompiled = Is Natively Compiled
FilterIsNativelyCompiledDescription = Include or exclude objects based on whether the object is natively compiled.
FilterInPrimaryKey = In Primary Key
FilterInPrimaryKeyDescription = Include or exclude objects based on whether the column is in a primary key.
############################################################################
# Scripting Service

View File

@@ -7137,6 +7137,76 @@ The Query Processor estimates that implementing the following index could improv
<target state="new">Impersonate Any Login</target>
<note></note>
</trans-unit>
<trans-unit id="FilterName">
<source>Name</source>
<target state="new">Name</target>
<note></note>
</trans-unit>
<trans-unit id="FilterNameDescription">
<source>Include or exclude objects based on the name or part of a name.</source>
<target state="new">Include or exclude objects based on the name or part of a name.</target>
<note></note>
</trans-unit>
<trans-unit id="FilterSchema">
<source>Schema</source>
<target state="new">Schema</target>
<note></note>
</trans-unit>
<trans-unit id="FilterSchemaDescription">
<source> Include or exclude objects based on the schema or part of a schema name.</source>
<target state="new"> Include or exclude objects based on the schema or part of a schema name.</target>
<note></note>
</trans-unit>
<trans-unit id="FilterOwner">
<source>Owner</source>
<target state="new">Owner</target>
<note></note>
</trans-unit>
<trans-unit id="FilterOwnerDescription">
<source>Include or exclude objects based on the owner or part of an owner name.</source>
<target state="new">Include or exclude objects based on the owner or part of an owner name.</target>
<note></note>
</trans-unit>
<trans-unit id="FilterDurabilityType">
<source>Durability Type</source>
<target state="new">Durability Type</target>
<note></note>
</trans-unit>
<trans-unit id="FilterDurabilityTypeDescription">
<source>Include or exclude objects based on the durability type.</source>
<target state="new">Include or exclude objects based on the durability type.</target>
<note></note>
</trans-unit>
<trans-unit id="FilterIsMemoryOptimized">
<source>Is Memory Optimized</source>
<target state="new">Is Memory Optimized</target>
<note></note>
</trans-unit>
<trans-unit id="FilterIsMemoryOptimizedDescription">
<source>Include or exclude objects based on whether the object is memory optimized.</source>
<target state="new">Include or exclude objects based on whether the object is memory optimized.</target>
<note></note>
</trans-unit>
<trans-unit id="FilterCreateDate">
<source>Create Date</source>
<target state="new">Create Date</target>
<note></note>
</trans-unit>
<trans-unit id="FilterCreateDateDescription">
<source>Select or type a creation date to include or exclude objects created at any time on that date, or enter a starting and ending date to include or exclude objects created in that inclusive date range.</source>
<target state="new">Select or type a creation date to include or exclude objects created at any time on that date, or enter a starting and ending date to include or exclude objects created in that inclusive date range.</target>
<note></note>
</trans-unit>
<trans-unit id="FilterIsNativelyCompiled">
<source>Is Natively Compiled</source>
<target state="new">Is Natively Compiled</target>
<note></note>
</trans-unit>
<trans-unit id="FilterIsNativelyCompiledDescription">
<source>Include or exclude objects based on whether the object is natively compiled.</source>
<target state="new">Include or exclude objects based on whether the object is natively compiled.</target>
<note></note>
</trans-unit>
<trans-unit id="ServiceProviderNotSet">
<source>SetServiceProvider() was not called to establish the required service provider</source>
<target state="new">SetServiceProvider() was not called to establish the required service provider</target>
@@ -7147,6 +7217,16 @@ The Query Processor estimates that implementing the following index could improv
<target state="new">Service {0} was not found in the service provider</target>
<note></note>
</trans-unit>
<trans-unit id="FilterInPrimaryKey">
<source>In Primary Key</source>
<target state="new">In Primary Key</target>
<note></note>
</trans-unit>
<trans-unit id="FilterInPrimaryKeyDescription">
<source>Include or exclude objects based on whether the column is in a primary key.</source>
<target state="new">Include or exclude objects based on whether the column is in a primary key.</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -57,6 +57,11 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts
/// Security token for AzureMFA authentication for refresing access token on connection.
/// </summary>
public SecurityToken? SecurityToken { get; set; }
///<summary>
/// Filters to apply to the expand request
///</summary>
public NodeFilter[]? Filters { get; set; }
}
/// <summary>

View File

@@ -6,6 +6,7 @@
#nullable disable
using Microsoft.SqlTools.ServiceLayer.Metadata.Contracts;
using Newtonsoft.Json.Linq;
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts
{
@@ -71,5 +72,86 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts
/// The object type of the node. e.g. Database, Server, Tables...
/// </summary>
public string ObjectType { get; set; }
/// <summary>
/// Filterable properties that this node supports
/// </summary>
public NodeFilterProperty[] FilterableProperties { get; set; }
}
/// <summary>
/// The filterable properties that a node supports
/// </summary>
public class NodeFilterProperty
{
/// <summary>
/// The name of the filter property
/// </summary>
public string Name { get; set; }
/// <summary>
/// The name of the filter property displayed to the user
/// </summary>
public string DisplayName { get; set; }
/// <summary>
/// The description of the filter property
/// </summary>
public string Description { get; set; }
/// <summary>
/// The data type of the filter property
/// </summary>
public NodeFilterPropertyDataType Type { get; set; }
/// <summary>
/// The list of choices for the filter property if the type is choice
/// </summary>
public string[] Choices { get; set; }
}
/// <summary>
/// The data type of the filter property. Matches NodeFilterPropertyDataType enum in ADS : https://github.com/microsoft/azuredatastudio/blob/main/src/sql/azdata.proposed.d.ts#L1847-L1853
/// </summary>
public enum NodeFilterPropertyDataType
{
String = 0,
Number = 1,
Boolean = 2,
Date = 3,
Choice = 4
}
/// <summary>
/// The operator of the filter property. Matches NodeFilterOperator enum in ADS: https://github.com/microsoft/azuredatastudio/blob/main/src/sql/azdata.proposed.d.ts#L1855-L1868
/// </summary>
public enum NodeFilterOperator
{
Equals = 0,
NotEquals = 1,
LessThan = 2,
LessThanOrEquals = 3,
GreaterThan = 4,
GreaterThanOrEquals = 5,
Between = 6,
NotBetween = 7,
Contains = 8,
NotContains = 9,
}
/// <summary>
/// The filters that can be used to filter the nodes in an expand request.
/// </summary>
public class NodeFilter
{
/// <summary>
/// The name of the filter property
/// </summary>
public string DisplayName { get; set; }
/// <summary>
/// The operator of the filter property
/// </summary>
public NodeFilterOperator Operator { get; set; }
/// <summary>
/// The applied values of the filter property
/// </summary>
public JToken Value { get; set; }
}
}

View File

@@ -7,6 +7,7 @@
using System.Collections.Generic;
using System.Threading;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel;
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
@@ -31,9 +32,11 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
/// </summary>
/// <param name="parent">Parent Node</param>
/// <param name="refresh">force to refresh</param>
/// <param name="refresh">name of the sql object to filter</param>
/// <returns></returns>
public abstract IEnumerable<TreeNode> Expand(TreeNode parent, bool refresh, string name, bool includeSystemObjects, CancellationToken cancellationToken);
/// <param name="name">name of the sql object to filter</param>
/// <param name="includeSystemObjects">include system objects</param>
/// <param name="cancellationToken">cancellation token</param>
/// <param name="filters">filters to apply</param>
public abstract IEnumerable<TreeNode> Expand(TreeNode parent, bool refresh, string name, bool includeSystemObjects, CancellationToken cancellationToken, IEnumerable<NodeFilter>? filters);
/// <summary>
/// The list of filters that should be applied on the smo object list

View File

@@ -46,6 +46,11 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
/// </summary>
public bool IsNotFilter { get; set; } = false;
/// <summary>
/// Indicates if the values are for type datetime
/// </summary>
public bool IsDateTime { get; set; } = false;
/// <summary>
/// Indicates the type of the filter. It can be EQUALS, DATETIME, FALSE or CONTAINS
/// More information can be found here:
@@ -82,36 +87,140 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
}
StringBuilder filter = new StringBuilder();
foreach (var value in Values)
{
object propertyValue = value;
if (Type == typeof(string))
{
propertyValue = $"'{propertyValue}'";
}
else if (Type == typeof(Enum))
{
propertyValue = (int)Convert.ChangeType(value, Type);
}
string filterText = string.Empty;
switch (FilterType)
if (IsDateTime)
{
case FilterType.EQUALS:
filterText = $"@{Property} = {propertyValue}";
break;
case FilterType.DATETIME:
filterText = $"@{Property} = datetime({propertyValue})";
break;
case FilterType.CONTAINS:
filterText = $"contains(@{Property}, {propertyValue})";
break;
case FilterType.FALSE:
filterText = $"@{Property} = false()";
break;
case FilterType.ISNULL:
filterText = $"isnull(@{Property})";
break;
string Value1;
string Value2;
switch (FilterType)
{
case FilterType.BETWEEN:
string[] betweenValues = (string[])value;
Value1 = DateTime.Parse((string)betweenValues[0]).ToString("yyyy-MM-dd 00:00:00.000");
Value2 = DateTime.Parse((string)betweenValues[1]).ToString("yyyy-MM-dd 23:59:59.999");
filterText = $"@{Property} >= datetime('{Value1}') and @{Property} <= datetime('{Value2}')";
break;
case FilterType.NOTBETWEEN:
IsNotFilter = true;
string[] notBetweenValues = (string[])value;
Value1 = DateTime.Parse((string)notBetweenValues[0]).ToString("yyyy-MM-dd 00:00:00.000");
Value2 = DateTime.Parse((string)notBetweenValues[1]).ToString("yyyy-MM-dd 23:59:59.999");
filterText = $"@{Property} >= datetime('{Value1}') and @{Property} <= datetime('{Value2}')";
break;
case FilterType.EQUALS:
Value1 = DateTime.Parse((string)value).ToString("yyyy-MM-dd 00:00:00.000");
Value2 = DateTime.Parse((string)value).ToString("yyyy-MM-dd 23:59:59.999");
filterText = $"@{Property} >= datetime('{Value1}') and @{Property} <= datetime('{Value2}')";
break;
case FilterType.GREATERTHAN:
Value1 = DateTime.Parse((string)value).ToString("yyyy-MM-dd 23:59:59.999");
filterText = $"@{Property} > datetime('{Value1}')";
break;
case FilterType.LESSTHAN:
Value1 = DateTime.Parse((string)value).ToString("yyyy-MM-dd 00:00:00.000");
filterText = $"@{Property} < datetime('{Value1}')";
break;
case FilterType.GREATERTHANOREQUAL:
Value1 = DateTime.Parse((string)value).ToString("yyyy-MM-dd 00:00:00.000");
filterText = $"@{Property} >= datetime('{Value1}')";
break;
case FilterType.LESSTHANOREQUAL:
Value1 = DateTime.Parse((string)value).ToString("yyyy-MM-dd 23:59:59.999");
filterText = $"@{Property} <= datetime('{Value1}')";
break;
case FilterType.NOTEQUALS:
IsNotFilter = true;
Value1 = DateTime.Parse((string)value).ToString("yyyy-MM-dd 00:00:00.000");
Value2 = DateTime.Parse((string)value).ToString("yyyy-MM-dd 23:59:59.999");
filterText = $"@{Property} >= datetime('{Value1}') and @{Property} <= datetime('{Value2}')";
break;
default:
break;
}
}
else if (IsNumericType(Type))
{
switch (FilterType)
{
case FilterType.BETWEEN:
object[] betweenValues = (object[])value;
filterText = $"@{Property} >= {Decimal.Parse(betweenValues[0].ToString())} and @{Property} <= {Decimal.Parse(betweenValues[1].ToString())}";
break;
case FilterType.NOTBETWEEN:
IsNotFilter = true;
object[] notBetweenValues = (object[])value;
filterText = $"@{Property} >= {Decimal.Parse(notBetweenValues[0].ToString())} and @{Property} <= {Decimal.Parse(notBetweenValues[1].ToString())}";
break;
case FilterType.EQUALS:
filterText = $"@{Property} = {Decimal.Parse(value.ToString())}";
break;
case FilterType.GREATERTHAN:
filterText = $"@{Property} > {Decimal.Parse(value.ToString())}";
break;
case FilterType.LESSTHAN:
filterText = $"@{Property} < {Decimal.Parse(value.ToString())}";
break;
case FilterType.GREATERTHANOREQUAL:
filterText = $"@{Property} >= {Decimal.Parse(value.ToString())}";
break;
case FilterType.LESSTHANOREQUAL:
filterText = $"@{Property} <= {Decimal.Parse(value.ToString())}";
break;
case FilterType.NOTEQUALS:
filterText = $"@{Property} != {Decimal.Parse(value.ToString())}";
break;
default:
break;
}
}
else
{
object propertyValue = value;
if (Type == typeof(string))
{
propertyValue = $"'{propertyValue}'";
}
else if (Type == typeof(Enum))
{
propertyValue = (int)Convert.ChangeType(value, Type);
}
switch (FilterType)
{
case FilterType.EQUALS:
filterText = $"@{Property} = {propertyValue}";
break;
case FilterType.NOTEQUALS:
filterText = $"@{Property} != {propertyValue}";
break;
case FilterType.LESSTHAN:
filterText = $"@{Property} < {propertyValue}";
break;
case FilterType.GREATERTHAN:
filterText = $"@{Property} > {propertyValue}";
break;
case FilterType.LESSTHANOREQUAL:
filterText = $"@{Property} <= {propertyValue}";
break;
case FilterType.GREATERTHANOREQUAL:
filterText = $"@{Property} >= {propertyValue}";
break;
case FilterType.DATETIME:
filterText = $"@{Property} = datetime({propertyValue})";
break;
case FilterType.CONTAINS:
filterText = $"contains(@{Property}, {propertyValue})";
break;
case FilterType.FALSE:
filterText = $"@{Property} = false()";
break;
case FilterType.ISNULL:
filterText = $"isnull(@{Property})";
break;
}
}
string orPrefix = filter.Length == 0 ? string.Empty : " or ";
@@ -131,6 +240,27 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
}
return string.Empty;
}
public static bool IsNumericType(Type type)
{
switch (Type.GetTypeCode(type))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
default:
return false;
}
}
}
public enum FilterType
@@ -139,6 +269,13 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
DATETIME,
CONTAINS,
FALSE,
ISNULL
ISNULL,
NOTEQUALS,
LESSTHAN,
GREATERTHAN,
LESSTHANOREQUAL,
GREATERTHANOREQUAL,
BETWEEN,
NOTBETWEEN
}
}

View File

@@ -120,6 +120,8 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
/// </summary>
public string NodeStatus { get; set; }
public NodeFilterProperty[] FilterProperties { get; set; }
/// <summary>
/// Label to display to the user, describing this node.
/// If not explicitly set this will fall back to the <see cref="NodeValue"/> but
@@ -235,7 +237,8 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
NodeStatus = this.NodeStatus,
NodeSubType = this.NodeSubType,
ErrorMessage = this.ErrorMessage,
ObjectType = this.NodeTypeId.ToString()
ObjectType = this.NodeTypeId.ToString(),
FilterableProperties = this.FilterProperties
};
}
@@ -243,14 +246,14 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
/// Expands this node and returns its children
/// </summary>
/// <returns>Children as an IList. This is the raw children collection, not a copy</returns>
public IList<TreeNode> Expand(string name, CancellationToken cancellationToken, string? accessToken = null)
public IList<TreeNode> Expand(string name, CancellationToken cancellationToken, string? accessToken = null, IEnumerable<NodeFilter>? filters = null)
{
// TODO consider why solution explorer has separate Children and Items options
if (children.IsInitialized)
{
return children;
}
PopulateChildren(false, name, cancellationToken, accessToken);
PopulateChildren(false, name, cancellationToken, accessToken, filters);
return children;
}
@@ -258,19 +261,19 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
/// Expands this node and returns its children
/// </summary>
/// <returns>Children as an IList. This is the raw children collection, not a copy</returns>
public IList<TreeNode> Expand(CancellationToken cancellationToken, string? accessToken = null)
public IList<TreeNode> Expand(CancellationToken cancellationToken, string? accessToken = null, IEnumerable<NodeFilter>? filters = null)
{
return Expand(null, cancellationToken, accessToken);
return Expand(null, cancellationToken, accessToken, filters);
}
/// <summary>
/// Refresh this node and returns its children
/// </summary>
/// <returns>Children as an IList. This is the raw children collection, not a copy</returns>
public virtual IList<TreeNode> Refresh(CancellationToken cancellationToken, string? accessToken = null)
public virtual IList<TreeNode> Refresh(CancellationToken cancellationToken, string? accessToken = null, IEnumerable<NodeFilter>? filters = null)
{
// TODO consider why solution explorer has separate Children and Items options
PopulateChildren(true, null, cancellationToken, accessToken);
PopulateChildren(true, null, cancellationToken, accessToken, filters);
return children;
}
@@ -322,7 +325,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
return Parent as T;
}
protected virtual void PopulateChildren(bool refresh, string name, CancellationToken cancellationToken, string? accessToken = null)
protected virtual void PopulateChildren(bool refresh, string name, CancellationToken cancellationToken, string? accessToken = null, IEnumerable<NodeFilter>? filters = null)
{
Logger.Write(TraceEventType.Verbose, string.Format(CultureInfo.InvariantCulture, "Populating oe node :{0}", this.GetNodePath()));
Debug.Assert(IsAlwaysLeaf == false);
@@ -353,7 +356,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
try
{
Logger.Verbose($"Begin populate children for {this.GetNodePath()} using {factory.GetType()} factory");
IEnumerable<TreeNode> items = factory.Expand(this, refresh, name, includeSystemObjects, cancellationToken);
IEnumerable<TreeNode> items = factory.Expand(this, refresh, name, includeSystemObjects, cancellationToken, filters);
Logger.Verbose($"End populate children for {this.GetNodePath()} using {factory.GetType()} factory");
if (items != null)
{

View File

@@ -378,12 +378,12 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
}
internal Task<ExpandResponse> ExpandNode(ObjectExplorerSession session, string nodePath, bool forceRefresh = false, SecurityToken? securityToken = null)
internal Task<ExpandResponse> ExpandNode(ObjectExplorerSession session, string nodePath, bool forceRefresh = false, SecurityToken? securityToken = null, NodeFilter[]? filters = null)
{
return Task.Run(() => QueueExpandNodeRequest(session, nodePath, forceRefresh, securityToken));
return Task.Run(() => QueueExpandNodeRequest(session, nodePath, forceRefresh, securityToken, filters));
}
internal ExpandResponse QueueExpandNodeRequest(ObjectExplorerSession session, string nodePath, bool forceRefresh = false, SecurityToken? securityToken = null)
internal ExpandResponse QueueExpandNodeRequest(ObjectExplorerSession session, string nodePath, bool forceRefresh = false, SecurityToken? securityToken = null, NodeFilter[]? filters = null)
{
NodeInfo[] nodes = null;
TreeNode? node = session.Root.FindNodeByPath(nodePath);
@@ -448,12 +448,12 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
if (forceRefresh)
{
Logger.Verbose($"Forcing refresh for {nodePath}");
nodes = node.Refresh(cancelToken, securityToken?.Token).Select(x => x.ToNodeInfo()).ToArray();
nodes = node.Refresh(cancelToken, securityToken?.Token, filters).Select(x => x.ToNodeInfo()).ToArray();
}
else
{
Logger.Verbose($"Expanding {nodePath}");
nodes = node.Expand(cancelToken, securityToken?.Token).Select(x => x.ToNodeInfo()).ToArray();
nodes = node.Expand(cancelToken, securityToken?.Token, filters).Select(x => x.ToNodeInfo()).ToArray();
}
response.Nodes = nodes;
response.ErrorMessage = node.ErrorMessage;
@@ -649,7 +649,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
private async Task ExpandNodeAsync(ObjectExplorerSession session, ExpandParams expandParams, CancellationToken cancellationToken, bool forceRefresh = false)
{
ExpandResponse response = null;
response = await ExpandNode(session, expandParams.NodePath, forceRefresh, expandParams.SecurityToken);
response = await ExpandNode(session, expandParams.NodePath, forceRefresh, expandParams.SecurityToken, expandParams.Filters);
if (cancellationToken.IsCancellationRequested)
{
Logger.Write(TraceEventType.Verbose, "OE expand canceled");

View File

@@ -8,6 +8,8 @@
using System;
using System.Threading;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts;
using System.Collections.Generic;
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
{
@@ -53,7 +55,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
/// <returns>A Tree Node that matches the condition, or null if no matching node could be found</returns>
public static TreeNode? FindNode(TreeNode node, Predicate<TreeNode> condition, Predicate<TreeNode> filter, bool expandIfNeeded = false)
{
if(node == null)
if (node == null)
{
return null;
}
@@ -76,5 +78,95 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
}
return null;
}
public static INodeFilter ConvertExpandNodeFilterToNodeFilter(NodeFilter filter, NodeFilterProperty filterProperty)
{
Type type = typeof(string);
var IsDateTime = filterProperty.Type == NodeFilterPropertyDataType.Date;
FilterType filterType = FilterType.EQUALS;
bool isNotFilter = false;
object filterValue = null;
switch (filterProperty.Type)
{
case NodeFilterPropertyDataType.String:
case NodeFilterPropertyDataType.Date:
case NodeFilterPropertyDataType.Choice:
type = typeof(string);
filterValue = filter.Value.ToString();
break;
case NodeFilterPropertyDataType.Number:
type = typeof(int);
filterValue = filter.Value.ToObject<int>();
break;
case NodeFilterPropertyDataType.Boolean:
type = typeof(bool);
filterValue = filter.Value.ToObject<bool>() ? 1 : 0;
break;
}
switch (filter.Operator)
{
case NodeFilterOperator.Equals:
filterType = FilterType.EQUALS;
break;
case NodeFilterOperator.NotEquals:
filterType = FilterType.EQUALS;
isNotFilter = true;
break;
case NodeFilterOperator.LessThan:
filterType = FilterType.LESSTHAN;
break;
case NodeFilterOperator.LessThanOrEquals:
filterType = FilterType.LESSTHANOREQUAL;
break;
case NodeFilterOperator.GreaterThan:
filterType = FilterType.GREATERTHAN;
break;
case NodeFilterOperator.GreaterThanOrEquals:
filterType = FilterType.GREATERTHANOREQUAL;
break;
case NodeFilterOperator.Contains:
filterType = FilterType.CONTAINS;
break;
case NodeFilterOperator.NotContains:
filterType = FilterType.CONTAINS;
isNotFilter = true;
break;
case NodeFilterOperator.Between:
filterType = FilterType.BETWEEN;
break;
case NodeFilterOperator.NotBetween:
filterType = FilterType.NOTBETWEEN;
isNotFilter = true;
break;
}
if (filter.Operator == NodeFilterOperator.Between || filter.Operator == NodeFilterOperator.NotBetween)
{
if (filterProperty.Type == NodeFilterPropertyDataType.Number)
{
filterValue = filter.Value.ToObject<int[]>();
}
else if (filterProperty.Type == NodeFilterPropertyDataType.Date)
{
filterValue = filter.Value.ToObject<string[]>();
}
}
return new NodePropertyFilter
{
Property = filterProperty.Name,
Type = type,
Values = new List<object> { filterValue },
IsNotFilter = isNotFilter,
FilterType = filterType,
IsDateTime = IsDateTime
};
}
}
}

View File

@@ -7,11 +7,13 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Threading;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts;
using Microsoft.SqlTools.Utility;
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
@@ -54,12 +56,12 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
}
}
protected override void PopulateChildren(bool refresh, string name, CancellationToken cancellationToken, string? accessToken = null)
protected override void PopulateChildren(bool refresh, string name, CancellationToken cancellationToken, string? accessToken = null, IEnumerable<NodeFilter>? filters = null)
{
var smoQueryContext = this.GetContextAs<SmoQueryContext>();
if (IsAccessible(smoQueryContext))
{
base.PopulateChildren(refresh, name, cancellationToken, accessToken);
base.PopulateChildren(refresh, name, cancellationToken, accessToken, filters);
}
else
{

View File

@@ -12,6 +12,7 @@ using System.Globalization;
using System.Linq;
using System.Threading;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes;
using Microsoft.SqlTools.Utility;
@@ -20,12 +21,13 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
public class SmoChildFactoryBase : 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)
public override IEnumerable<TreeNode> Expand(TreeNode parent, bool refresh, string name, bool includeSystemObjects, CancellationToken cancellationToken, IEnumerable<NodeFilter>? filters = null)
{
List<TreeNode> allChildren = new List<TreeNode>();
@@ -33,7 +35,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
{
if (this.PutFoldersAfterNodes)
{
OnExpandPopulateNonFolders(allChildren, parent, refresh, name, cancellationToken);
OnExpandPopulateNonFolders(allChildren, parent, refresh, name, cancellationToken, filters);
OnExpandPopulateFoldersAndFilter(allChildren, parent, includeSystemObjects);
RemoveFoldersFromInvalidSqlServerVersions(allChildren, parent);
}
@@ -41,7 +43,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
{
OnExpandPopulateFoldersAndFilter(allChildren, parent, includeSystemObjects);
RemoveFoldersFromInvalidSqlServerVersions(allChildren, parent);
OnExpandPopulateNonFolders(allChildren, parent, refresh, name, cancellationToken);
OnExpandPopulateNonFolders(allChildren, parent, refresh, name, cancellationToken, filters);
}
OnBeginAsyncOperations(parent);
@@ -110,7 +112,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
/// </summary>
/// <param name="allChildren">List to which nodes should be added</param>
/// <param name="parent">Parent the nodes are being added to</param>
protected virtual void OnExpandPopulateNonFolders(IList<TreeNode> allChildren, TreeNode parent, bool refresh, string name, CancellationToken cancellationToken)
protected virtual void OnExpandPopulateNonFolders(IList<TreeNode> allChildren, TreeNode parent, bool refresh, string name, CancellationToken cancellationToken, IEnumerable<NodeFilter>? appliedFilters = null)
{
Logger.Write(TraceEventType.Verbose, string.Format(CultureInfo.InvariantCulture, "child factory parent :{0}", parent.GetNodePath()));
@@ -131,6 +133,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
IEnumerable<SmoQuerier> queriers = context.ServiceProvider.GetServices<SmoQuerier>(IsCompatibleQuerier);
var filters = this.Filters.ToList();
var smoProperties = this.SmoProperties.Where(p => ServerVersionHelper.IsValidFor(serverValidFor, p.ValidFor)).Select(x => x.Name);
var filterDefinitions = parent.FilterProperties;
if (!string.IsNullOrEmpty(name))
{
filters.Add(new NodePropertyFilter
@@ -140,6 +143,15 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
Values = new List<object> { name },
});
}
if (appliedFilters != null)
{
foreach (var f in appliedFilters)
{
NodeFilterProperty filterProperty = filterDefinitions.FirstOrDefault(x => x.DisplayName == f.DisplayName);
filters.Add(ObjectExplorerUtils.ConvertExpandNodeFilterToNodeFilter(f, filterProperty));
}
}
foreach (var querier in queriers)
{
cancellationToken.ThrowIfCancellationRequested();

View File

@@ -14,9 +14,11 @@ using System.Collections.Generic;
using System.Composition;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts;
using Microsoft.SqlTools.ServiceLayer.SqlContext;
using Microsoft.SqlTools.ServiceLayer.Workspace;
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
{
@@ -176,6 +178,30 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
NodeTypeId = NodeTypes.Databases,
IsSystemObject = false,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "Owner",
DisplayName = SR.FilterOwner,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterOwnerDescription,
},
new NodeFilterProperty
{
Name = "CreateDate",
DisplayName = SR.FilterCreateDate,
Type = NodeFilterPropertyDataType.Date,
Description = SR.FilterCreateDateDescription,
},
}
});
currentChildren.Add(new FolderNode {
NodeValue = SR.SchemaHierarchy_Security,
@@ -761,6 +787,55 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
NodeTypeId = NodeTypes.Tables,
IsSystemObject = false,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "Schema",
DisplayName = SR.FilterSchema,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterSchemaDescription,
},
new NodeFilterProperty
{
Name = "Owner",
DisplayName = SR.FilterOwner,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterOwnerDescription,
},
new NodeFilterProperty
{
Name = "DurabilityType",
DisplayName = SR.FilterDurabilityType,
Type = NodeFilterPropertyDataType.Choice,
Description = SR.FilterDurabilityTypeDescription,
Choices = new string[] {
"SchemaAndData",
"SchemaOnly",
}
},
new NodeFilterProperty
{
Name = "IsMemoryOptimized",
DisplayName = SR.FilterIsMemoryOptimized,
Type = NodeFilterPropertyDataType.Boolean,
Description = SR.FilterIsMemoryOptimizedDescription,
},
new NodeFilterProperty
{
Name = "CreateDate",
DisplayName = SR.FilterCreateDate,
Type = NodeFilterPropertyDataType.Date,
Description = SR.FilterCreateDateDescription,
},
}
});
}
if (!WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings.SqlTools.ObjectExplorer.GroupBySchema)
@@ -770,6 +845,37 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
NodeTypeId = NodeTypes.Views,
IsSystemObject = false,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "Schema",
DisplayName = SR.FilterSchema,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterSchemaDescription,
},
new NodeFilterProperty
{
Name = "Owner",
DisplayName = SR.FilterOwner,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterOwnerDescription,
},
new NodeFilterProperty
{
Name = "CreateDate",
DisplayName = SR.FilterCreateDate,
Type = NodeFilterPropertyDataType.Date,
Description = SR.FilterCreateDateDescription,
},
}
});
}
if (!WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings.SqlTools.ObjectExplorer.GroupBySchema)
@@ -951,12 +1057,92 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
NodeTypeId = NodeTypes.Tables,
IsSystemObject = false,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "Schema",
DisplayName = SR.FilterSchema,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterSchemaDescription,
},
new NodeFilterProperty
{
Name = "Owner",
DisplayName = SR.FilterOwner,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterOwnerDescription,
},
new NodeFilterProperty
{
Name = "DurabilityType",
DisplayName = SR.FilterDurabilityType,
Type = NodeFilterPropertyDataType.Choice,
Description = SR.FilterDurabilityTypeDescription,
Choices = new string[] {
"SchemaAndData",
"SchemaOnly",
}
},
new NodeFilterProperty
{
Name = "IsMemoryOptimized",
DisplayName = SR.FilterIsMemoryOptimized,
Type = NodeFilterPropertyDataType.Boolean,
Description = SR.FilterIsMemoryOptimizedDescription,
},
new NodeFilterProperty
{
Name = "CreateDate",
DisplayName = SR.FilterCreateDate,
Type = NodeFilterPropertyDataType.Date,
Description = SR.FilterCreateDateDescription,
},
}
});
currentChildren.Add(new FolderNode {
NodeValue = SR.SchemaHierarchy_Views,
NodeTypeId = NodeTypes.Views,
IsSystemObject = false,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "Schema",
DisplayName = SR.FilterSchema,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterSchemaDescription,
},
new NodeFilterProperty
{
Name = "Owner",
DisplayName = SR.FilterOwner,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterOwnerDescription,
},
new NodeFilterProperty
{
Name = "CreateDate",
DisplayName = SR.FilterCreateDate,
Type = NodeFilterPropertyDataType.Date,
Description = SR.FilterCreateDateDescription,
},
}
});
currentChildren.Add(new FolderNode {
NodeValue = SR.SchemaHierarchy_Synonyms,
@@ -1094,6 +1280,55 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
IsSystemObject = true,
IsMsShippedOwned = true,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "Schema",
DisplayName = SR.FilterSchema,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterSchemaDescription,
},
new NodeFilterProperty
{
Name = "Owner",
DisplayName = SR.FilterOwner,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterOwnerDescription,
},
new NodeFilterProperty
{
Name = "DurabilityType",
DisplayName = SR.FilterDurabilityType,
Type = NodeFilterPropertyDataType.Choice,
Description = SR.FilterDurabilityTypeDescription,
Choices = new string[] {
"SchemaAndData",
"SchemaOnly",
}
},
new NodeFilterProperty
{
Name = "IsMemoryOptimized",
DisplayName = SR.FilterIsMemoryOptimized,
Type = NodeFilterPropertyDataType.Boolean,
Description = SR.FilterIsMemoryOptimizedDescription,
},
new NodeFilterProperty
{
Name = "CreateDate",
DisplayName = SR.FilterCreateDate,
Type = NodeFilterPropertyDataType.Date,
Description = SR.FilterCreateDateDescription,
},
}
});
currentChildren.Add(new FolderNode {
NodeValue = SR.SchemaHierarchy_DroppedLedgerTables,
@@ -1101,6 +1336,55 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
IsSystemObject = false,
ValidFor = ValidForFlag.Sql2022OrHigher|ValidForFlag.AzureV12,
SortPriority = Int32.MaxValue,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "Schema",
DisplayName = SR.FilterSchema,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterSchemaDescription,
},
new NodeFilterProperty
{
Name = "Owner",
DisplayName = SR.FilterOwner,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterOwnerDescription,
},
new NodeFilterProperty
{
Name = "DurabilityType",
DisplayName = SR.FilterDurabilityType,
Type = NodeFilterPropertyDataType.Choice,
Description = SR.FilterDurabilityTypeDescription,
Choices = new string[] {
"SchemaAndData",
"SchemaOnly",
}
},
new NodeFilterProperty
{
Name = "IsMemoryOptimized",
DisplayName = SR.FilterIsMemoryOptimized,
Type = NodeFilterPropertyDataType.Boolean,
Description = SR.FilterIsMemoryOptimizedDescription,
},
new NodeFilterProperty
{
Name = "CreateDate",
DisplayName = SR.FilterCreateDate,
Type = NodeFilterPropertyDataType.Date,
Description = SR.FilterCreateDateDescription,
},
}
});
}
@@ -1178,6 +1462,37 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
IsMsShippedOwned = true,
ValidFor = ValidForFlag.Sql2022OrHigher|ValidForFlag.AzureV12,
SortPriority = Int32.MaxValue,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "Schema",
DisplayName = SR.FilterSchema,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterSchemaDescription,
},
new NodeFilterProperty
{
Name = "Owner",
DisplayName = SR.FilterOwner,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterOwnerDescription,
},
new NodeFilterProperty
{
Name = "CreateDate",
DisplayName = SR.FilterCreateDate,
Type = NodeFilterPropertyDataType.Date,
Description = SR.FilterCreateDateDescription,
},
}
});
}
@@ -1236,6 +1551,44 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
NodeTypeId = NodeTypes.StoredProcedures,
IsSystemObject = false,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "Schema",
DisplayName = SR.FilterSchema,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterSchemaDescription,
},
new NodeFilterProperty
{
Name = "Owner",
DisplayName = SR.FilterOwner,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterOwnerDescription,
},
new NodeFilterProperty
{
Name = "IsNativelyCompiled",
DisplayName = SR.FilterIsNativelyCompiled,
Type = NodeFilterPropertyDataType.Boolean,
Description = SR.FilterIsNativelyCompiledDescription,
},
new NodeFilterProperty
{
Name = "CreateDate",
DisplayName = SR.FilterCreateDate,
Type = NodeFilterPropertyDataType.Date,
Description = SR.FilterCreateDateDescription,
},
}
});
}
if (!WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings.SqlTools.ObjectExplorer.GroupBySchema)
@@ -1280,6 +1633,37 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
IsSystemObject = false,
ValidFor = ValidForFlag.Sql2012OrHigher|ValidForFlag.AzureV12,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "Schema",
DisplayName = SR.FilterSchema,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterSchemaDescription,
},
new NodeFilterProperty
{
Name = "Owner",
DisplayName = SR.FilterOwner,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterOwnerDescription,
},
new NodeFilterProperty
{
Name = "CreateDate",
DisplayName = SR.FilterCreateDate,
Type = NodeFilterPropertyDataType.Date,
Description = SR.FilterCreateDateDescription,
},
}
});
}
}
@@ -1306,6 +1690,44 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
NodeTypeId = NodeTypes.StoredProcedures,
IsSystemObject = false,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "Schema",
DisplayName = SR.FilterSchema,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterSchemaDescription,
},
new NodeFilterProperty
{
Name = "Owner",
DisplayName = SR.FilterOwner,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterOwnerDescription,
},
new NodeFilterProperty
{
Name = "IsNativelyCompiled",
DisplayName = SR.FilterIsNativelyCompiled,
Type = NodeFilterPropertyDataType.Boolean,
Description = SR.FilterIsNativelyCompiledDescription,
},
new NodeFilterProperty
{
Name = "CreateDate",
DisplayName = SR.FilterCreateDate,
Type = NodeFilterPropertyDataType.Date,
Description = SR.FilterCreateDateDescription,
},
}
});
currentChildren.Add(new FolderNode {
NodeValue = SR.SchemaHierarchy_Functions,
@@ -1327,6 +1749,37 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
IsSystemObject = false,
ValidFor = ValidForFlag.Sql2012OrHigher|ValidForFlag.AzureV12,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "Schema",
DisplayName = SR.FilterSchema,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterSchemaDescription,
},
new NodeFilterProperty
{
Name = "Owner",
DisplayName = SR.FilterOwner,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterOwnerDescription,
},
new NodeFilterProperty
{
Name = "CreateDate",
DisplayName = SR.FilterCreateDate,
Type = NodeFilterPropertyDataType.Date,
Description = SR.FilterCreateDateDescription,
},
}
});
}
@@ -1747,6 +2200,23 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
NodeTypeId = NodeTypes.Columns,
IsSystemObject = false,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "InPrimaryKey",
DisplayName = SR.FilterInPrimaryKey,
Type = NodeFilterPropertyDataType.Boolean,
Description = SR.FilterInPrimaryKeyDescription,
},
}
});
currentChildren.Add(new FolderNode {
NodeValue = SR.SchemaHierarchy_Keys,
@@ -1774,6 +2244,23 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
IsSystemObject = false,
ValidFor = ValidForFlag.NotSqlDemand,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "IsMemoryOptimized",
DisplayName = SR.FilterIsMemoryOptimized,
Type = NodeFilterPropertyDataType.Boolean,
Description = SR.FilterIsMemoryOptimizedDescription,
},
}
});
currentChildren.Add(new FolderNode {
NodeValue = SR.SchemaHierarchy_Statistics,
@@ -1813,6 +2300,23 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
NodeTypeId = NodeTypes.Columns,
IsSystemObject = false,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "InPrimaryKey",
DisplayName = SR.FilterInPrimaryKey,
Type = NodeFilterPropertyDataType.Boolean,
Description = SR.FilterInPrimaryKeyDescription,
},
}
});
currentChildren.Add(new FolderNode {
NodeValue = SR.SchemaHierarchy_Constraints,
@@ -1826,6 +2330,23 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
IsSystemObject = false,
ValidFor = ValidForFlag.NotSqlDemand,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "IsMemoryOptimized",
DisplayName = SR.FilterIsMemoryOptimized,
Type = NodeFilterPropertyDataType.Boolean,
Description = SR.FilterIsMemoryOptimizedDescription,
},
}
});
currentChildren.Add(new FolderNode {
NodeValue = SR.SchemaHierarchy_Statistics,
@@ -1867,6 +2388,23 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
NodeTypeId = NodeTypes.Columns,
IsSystemObject = false,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "InPrimaryKey",
DisplayName = SR.FilterInPrimaryKey,
Type = NodeFilterPropertyDataType.Boolean,
Description = SR.FilterInPrimaryKeyDescription,
},
}
});
currentChildren.Add(new FolderNode {
NodeValue = SR.SchemaHierarchy_Statistics,
@@ -2238,6 +2776,23 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
NodeTypeId = NodeTypes.Columns,
IsSystemObject = false,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "InPrimaryKey",
DisplayName = SR.FilterInPrimaryKey,
Type = NodeFilterPropertyDataType.Boolean,
Description = SR.FilterInPrimaryKeyDescription,
},
}
});
currentChildren.Add(new FolderNode {
NodeValue = SR.SchemaHierarchy_Triggers,
@@ -2252,6 +2807,23 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
IsSystemObject = false,
ValidFor = ValidForFlag.NotSqlDemand,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "IsMemoryOptimized",
DisplayName = SR.FilterIsMemoryOptimized,
Type = NodeFilterPropertyDataType.Boolean,
Description = SR.FilterIsMemoryOptimizedDescription,
},
}
});
currentChildren.Add(new FolderNode {
NodeValue = SR.SchemaHierarchy_Statistics,
@@ -2301,12 +2873,88 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
IsSystemObject = false,
ValidFor = ValidForFlag.NotSqlDw,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "Schema",
DisplayName = SR.FilterSchema,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterSchemaDescription,
},
new NodeFilterProperty
{
Name = "Owner",
DisplayName = SR.FilterOwner,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterOwnerDescription,
},
new NodeFilterProperty
{
Name = "IsNativelyCompiled",
DisplayName = SR.FilterIsNativelyCompiled,
Type = NodeFilterPropertyDataType.Boolean,
Description = SR.FilterIsNativelyCompiledDescription,
},
new NodeFilterProperty
{
Name = "CreateDate",
DisplayName = SR.FilterCreateDate,
Type = NodeFilterPropertyDataType.Date,
Description = SR.FilterCreateDateDescription,
},
}
});
currentChildren.Add(new FolderNode {
NodeValue = SR.SchemaHierarchy_ScalarValuedFunctions,
NodeTypeId = NodeTypes.ScalarValuedFunctions,
IsSystemObject = false,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "Schema",
DisplayName = SR.FilterSchema,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterSchemaDescription,
},
new NodeFilterProperty
{
Name = "Owner",
DisplayName = SR.FilterOwner,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterOwnerDescription,
},
new NodeFilterProperty
{
Name = "IsNativelyCompiled",
DisplayName = SR.FilterIsNativelyCompiled,
Type = NodeFilterPropertyDataType.Boolean,
Description = SR.FilterIsNativelyCompiledDescription,
},
new NodeFilterProperty
{
Name = "CreateDate",
DisplayName = SR.FilterCreateDate,
Type = NodeFilterPropertyDataType.Date,
Description = SR.FilterCreateDateDescription,
},
}
});
currentChildren.Add(new FolderNode {
NodeValue = SR.SchemaHierarchy_AggregateFunctions,
@@ -2314,6 +2962,37 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
IsSystemObject = false,
ValidFor = ValidForFlag.AllOnPrem|ValidForFlag.AzureV12,
SortPriority = SmoTreeNode.NextSortPriority,
FilterProperties = new NodeFilterProperty[]
{
new NodeFilterProperty
{
Name = "Name",
DisplayName = SR.FilterName,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterNameDescription,
},
new NodeFilterProperty
{
Name = "Schema",
DisplayName = SR.FilterSchema,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterSchemaDescription,
},
new NodeFilterProperty
{
Name = "Owner",
DisplayName = SR.FilterOwner,
Type = NodeFilterPropertyDataType.String,
Description = SR.FilterOwnerDescription,
},
new NodeFilterProperty
{
Name = "CreateDate",
DisplayName = SR.FilterCreateDate,
Type = NodeFilterPropertyDataType.Date,
Description = SR.FilterCreateDateDescription,
},
}
});
}

View File

@@ -25,9 +25,11 @@ using System.Collections.Generic;
using System.Composition;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts;
using Microsoft.SqlTools.ServiceLayer.SqlContext;
using Microsoft.SqlTools.ServiceLayer.Workspace;
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
{
@@ -128,7 +130,6 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
List<XmlElement> children = GetChildren(xmlFile, type);
List<XmlElement> smoProperties = GetNodeSmoProperties(xmlFile, type);
// Load and parse Filters node
// A <Filters> node is comprised of <Or> and <Filter> nodes
// - A <Filter> node defines the properties to construct a NodePropertyFilter object
@@ -299,6 +300,57 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
WriteLine(" ValidFor = {0},", GetValidForFlags(validFor));
}
WriteLine(" SortPriority = {0},", sortPriority);
List<XmlElement> filterProperties = GetFilterProperties(xmlFile, childName);
if(filterProperties.Count > 0)
{
WriteLine(" FilterProperties = new NodeFilterProperty[]");
WriteLine(" {");
foreach (var filterDef in filterProperties)
{
var filterName = filterDef.GetAttribute("Name");
var filterDisplayName = filterDef.GetAttribute("LocLabel");
var filterType = filterDef.GetAttribute("Type");
var enumString = "NodeFilterPropertyDataType";
switch (filterType)
{
case "string":
enumString += ".String";
break;
case "bool":
enumString += ".Boolean";
break;
case "date":
enumString += ".Date";
break;
case "choice":
enumString += ".Choice";
break;
}
var filterDescription = filterDef.GetAttribute("Description");
WriteLine(" new NodeFilterProperty");
WriteLine(" {");
WriteLine(" Name = \"{0}\",", filterName);
WriteLine(" DisplayName = {0},", filterDisplayName);
WriteLine(" Type = {0},", enumString);
WriteLine(" Description = {0},", filterDescription);
if(filterType == "choice")
{
var enumValues = filterDef.ChildNodes;
WriteLine(" Choices = new string[] {");
foreach (XmlElement enumValue in enumValues)
{
var enumValueName = enumValue.GetAttribute("Name");
WriteLine(" \"{0}\",", enumValueName);
}
WriteLine(" }");
}
WriteLine(" },");
}
WriteLine(" }");
}
WriteLine(" });");
}
@@ -580,6 +632,33 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
return retElements;
}
public static List<XmlElement> GetFilterProperties(string xmlFile, string nodeType)
{
XmlElement nodeElement = GetNodeElement(xmlFile, nodeType);
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
List<XmlElement> retElements = new List<XmlElement>();
XmlNodeList nodeList = doc.SelectNodes(string.Format("/ServerExplorerTree/FilterProperties[@NodeName='{0}']/Property", nodeType));
foreach (XmlNode item in nodeList)
{
var filterName = item.InnerText;
XmlNodeList filterPropertyList = doc.SelectNodes(string.Format("/ServerExplorerTree/FilterProperty[@Name='{0}']", filterName));
foreach (var filterProperty in filterPropertyList)
{
XmlElement itemAsElement = filterProperty as XmlElement;
if (itemAsElement != null)
{
retElements.Add(itemAsElement);
}
}
}
return retElements;
}
public static List<XmlElement> GetNodeFilterValues(string xmlFile, string parentName, string filterProperty, bool orFilter = false)
{
XmlElement nodeElement = GetNodeElement(xmlFile, parentName);

View File

@@ -565,4 +565,113 @@
<ReverseDependencyList>
<ReverseDependency Type="SqlUser" DependsOn="SqlRole;SqlRoleMembership"/>
</ReverseDependencyList>
<FilterProperties NodeName="Databases">
<Property>Name</Property>
<Property>Owner</Property>
<Property>CreateDate</Property>
</FilterProperties>
<FilterProperties NodeName="Tables">
<Property>Name</Property>
<Property>Schema</Property>
<Property>Owner</Property>
<Property>DurabilityType</Property>
<Property>IsMemoryOptimized</Property>
<Property>CreateDate</Property>
</FilterProperties>
<FilterProperties NodeName="SystemTables">
<Property>Name</Property>
<Property>Schema</Property>
<Property>Owner</Property>
<Property>DurabilityType</Property>
<Property>IsMemoryOptimized</Property>
<Property>CreateDate</Property>
</FilterProperties>
<FilterProperties NodeName="DroppedLedgerTables">
<Property>Name</Property>
<Property>Schema</Property>
<Property>Owner</Property>
<Property>DurabilityType</Property>
<Property>IsMemoryOptimized</Property>
<Property>CreateDate</Property>
</FilterProperties>
<FilterProperties NodeName="Views">
<Property>Name</Property>
<Property>Schema</Property>
<Property>Owner</Property>
<Property>CreateDate</Property>
</FilterProperties>
<FilterProperties NodeName="DroppedLedgerViews">
<Property>Name</Property>
<Property>Schema</Property>
<Property>Owner</Property>
<Property>CreateDate</Property>
</FilterProperties>
<FilterProperties NodeName="StoredProcedures">
<Property>Name</Property>
<Property>Schema</Property>
<Property>Owner</Property>
<Property>IsNativelyCompiled</Property>
<Property>CreateDate</Property>
</FilterProperties>
<FilterProperties NodeName="TableValuedFunctions">
<Property>Name</Property>
<Property>Schema</Property>
<Property>Owner</Property>
<Property>IsNativelyCompiled</Property>
<Property>CreateDate</Property>
</FilterProperties>
<FilterProperties NodeName="ScalarValuedFunctions">
<Property>Name</Property>
<Property>Schema</Property>
<Property>Owner</Property>
<Property>IsNativelyCompiled</Property>
<Property>CreateDate</Property>
</FilterProperties>
<FilterProperties NodeName="AggregateFunctions">
<Property>Name</Property>
<Property>Schema</Property>
<Property>Owner</Property>
<Property>CreateDate</Property>
</FilterProperties>
<FilterProperties NodeName="Sequences">
<Property>Name</Property>
<Property>Schema</Property>
<Property>Owner</Property>
<Property>CreateDate</Property>
</FilterProperties>
<FilterProperties NodeName="Indexes">
<Property>Name</Property>
<Property>IsMemoryOptimized</Property>
</FilterProperties>
<FilterProperties NodeName="Columns">
<Property>Name</Property>
<Property>InPrimaryKey</Property>
</FilterProperties>
<FilterProperty Name="Name" LocLabel="SR.FilterName" Type="string" Description="SR.FilterNameDescription"/>
<FilterProperty Name="Schema" LocLabel="SR.FilterSchema" Type="string" Description="SR.FilterSchemaDescription"/>
<FilterProperty Name="Owner" LocLabel="SR.FilterOwner" Type="string" Description="SR.FilterOwnerDescription"/>
<FilterProperty Name="DurabilityType" LocLabel="SR.FilterDurabilityType" Type="choice" Description="SR.FilterDurabilityTypeDescription">
<Value Name="SchemaAndData" LocLabel="SR.SchemaAndData"/>
<Value Name="SchemaOnly" LocLabel="SR.SchemaOnly"/>
</FilterProperty>
<FilterProperty Name="IsMemoryOptimized" LocLabel="SR.FilterIsMemoryOptimized" Type="bool" Description="SR.FilterIsMemoryOptimizedDescription"/>
<FilterProperty Name="CreateDate" LocLabel="SR.FilterCreateDate" Type="date" Description="SR.FilterCreateDateDescription"/>
<FilterProperty Name="IsNativelyCompiled" LocLabel="SR.FilterIsNativelyCompiled" Type="bool" Description="SR.FilterIsNativelyCompiledDescription"/>
<FilterProperty Name="InPrimaryKey" LocLabel="SR.FilterInPrimaryKey" Type="bool" Description="SR.FilterInPrimaryKeyDescription"/>
</ServerExplorerTree>

View File

@@ -19,39 +19,39 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
{
// Basic PropertyFilter definitions to use in tests
public NodePropertyFilter TemporalFilter =
public NodePropertyFilter TemporalFilter =
new NodePropertyFilter
{
Property = "TemporalType",
Type = typeof(Enum),
TypeToReverse = typeof(SqlHistoryTableQuerier),
ValidFor = ValidForFlag.Sql2016|ValidForFlag.Sql2017|ValidForFlag.Sql2019|ValidForFlag.Sql2022OrHigher|ValidForFlag.AzureV12,
Values = new List<object>
{
Property = "TemporalType",
Type = typeof(Enum),
TypeToReverse = typeof(SqlHistoryTableQuerier),
ValidFor = ValidForFlag.Sql2016 | ValidForFlag.Sql2017 | ValidForFlag.Sql2019 | ValidForFlag.Sql2022OrHigher | ValidForFlag.AzureV12,
Values = new List<object>
{
{ TableTemporalType.HistoryTable }
}
};
};
public NodePropertyFilter LedgerHistoryFilter =
public NodePropertyFilter LedgerHistoryFilter =
new NodePropertyFilter
{
Property = "LedgerType",
Type = typeof(Enum),
TypeToReverse = typeof(SqlHistoryTableQuerier),
ValidFor = ValidForFlag.Sql2022OrHigher|ValidForFlag.AzureV12,
Values = new List<object>
{
Property = "LedgerType",
Type = typeof(Enum),
TypeToReverse = typeof(SqlHistoryTableQuerier),
ValidFor = ValidForFlag.Sql2022OrHigher | ValidForFlag.AzureV12,
Values = new List<object>
{
{ LedgerTableType.HistoryTable }
}
};
};
public NodePropertyFilter SystemObjectFilter =
new NodePropertyFilter
{
Property = "IsSystemObject",
Type = typeof(bool),
Values = new List<object> { 1 },
};
{
Property = "IsSystemObject",
Type = typeof(bool),
Values = new List<object> { 1 },
};
/// <summary>
/// Validates the output of the ToPropertyFilterString for the NodeOrFilter class
@@ -59,7 +59,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
[Test]
public void NodeOrFilterReturnsProperString()
{
var orNode = new NodeOrFilter {
var orNode = new NodeOrFilter
{
FilterList = new List<NodePropertyFilter> {
TemporalFilter,
LedgerHistoryFilter
@@ -127,7 +128,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
[Test]
public void GetPropertyFilterWithNodePropertyAndNodeOrFilters()
{
var orNode = new NodeOrFilter {
var orNode = new NodeOrFilter
{
FilterList = new List<NodePropertyFilter> {
TemporalFilter,
LedgerHistoryFilter
@@ -145,7 +147,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
string sql2016ServerVersion = INodeFilter.GetPropertyFilter(nodeList, typeof(SqlHistoryTableQuerier), ValidForFlag.Sql2016);
string expectedSql2016Filters = "[((@TemporalType = 1)) and (@IsSystemObject = 1)]";
Assert.That(sql2016ServerVersion, Is.EqualTo(expectedSql2016Filters), "GetPropertyFilter did not construct the URN filter string as expected when excluding filters that aren't valid for the given server type.");
Assert.That(sql2016ServerVersion, Is.EqualTo(expectedSql2016Filters), "GetPropertyFilter did not construct the URN filter string as expected when excluding filters that aren't valid for the given server type.");
string invalidQuerierType = INodeFilter.GetPropertyFilter(nodeList, typeof(SqlTableQuerier), ValidForFlag.Sql2022OrHigher);
string expectedTableQuerierFilters = "[(@IsSystemObject = 1)]";
@@ -160,14 +162,16 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
public void GetPropertyFilterWithMixedFilters()
{
// All these filters together are nonsense, but it's just testing the logic for constructing the filter string
var orNode = new NodeOrFilter {
var orNode = new NodeOrFilter
{
FilterList = new List<NodePropertyFilter> {
TemporalFilter,
LedgerHistoryFilter
}
};
var orNode2 = new NodeOrFilter {
var orNode2 = new NodeOrFilter
{
FilterList = new List<NodePropertyFilter> {
SystemObjectFilter,
LedgerHistoryFilter,
@@ -200,7 +204,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
TemporalFilter,
LedgerHistoryFilter
};
var nodeList = new List<INodeFilter> {
new NodePropertyFilter(){
Property = "Schema",
@@ -218,5 +222,393 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
string expectedNewUrn = "[(@TemporalType = 1) and (@LedgerType = 1) and (@Schema = 'jsdafl983!@$#%535343]]]][[[')]";
Assert.That(newUrn, Is.EqualTo(expectedNewUrn), "GetPropertyFilter did not construct the URN filter string as expected");
}
[Test]
public void TestDateFilters()
{
// Testing date filter with equals
var filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "CreateDate",
Type = typeof(string),
ValidFor = ValidForFlag.All,
Values = new List<object> { "2021-01-01" },
FilterType = FilterType.EQUALS,
IsDateTime = true
}
};
string filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@CreateDate >= datetime('2021-01-01 00:00:00.000') and @CreateDate <= datetime('2021-01-01 23:59:59.999'))]", filterString, "Error parsing date filter with equals operator");
// Testing date filter with less than
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "CreateDate",
Type = typeof(string),
ValidFor = ValidForFlag.All,
Values = new List<object> { "2021-01-01" },
FilterType = FilterType.LESSTHAN,
IsDateTime = true
}
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@CreateDate < datetime('2021-01-01 00:00:00.000'))]", filterString, "Error parsing date filter with less than operator");
// Testing date filter with greater than
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "CreateDate",
Type = typeof(string),
ValidFor = ValidForFlag.All,
Values = new List<object> { "2021-01-01" },
FilterType = FilterType.GREATERTHAN,
IsDateTime = true
}
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@CreateDate > datetime('2021-01-01 23:59:59.999'))]", filterString, "Error parsing date filter with greater than operator");
// Testing date filter with between
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "CreateDate",
Type = typeof(string),
ValidFor = ValidForFlag.All,
Values = new List<object> { new string[] {"2021-01-01", "2021-01-02"}},
FilterType = FilterType.BETWEEN,
IsDateTime = true
}
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@CreateDate >= datetime('2021-01-01 00:00:00.000') and @CreateDate <= datetime('2021-01-02 23:59:59.999'))]", filterString, "Error parsing date filter with between operator");
// Testing date filter with not equals
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "CreateDate",
Type = typeof(string),
ValidFor = ValidForFlag.All,
Values = new List<object> { "2021-01-01" },
FilterType = FilterType.NOTEQUALS,
IsDateTime = true,
}
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(not(@CreateDate >= datetime('2021-01-01 00:00:00.000') and @CreateDate <= datetime('2021-01-01 23:59:59.999')))]", filterString, "Error parsing date filter with not equals operator");
// Testing date filter with not between
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "CreateDate",
Type = typeof(string),
ValidFor = ValidForFlag.All,
Values = new List<object> { new string[] {"2021-01-01", "2021-01-02"}},
FilterType = FilterType.NOTBETWEEN,
IsDateTime = true
}
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(not(@CreateDate >= datetime('2021-01-01 00:00:00.000') and @CreateDate <= datetime('2021-01-02 23:59:59.999')))]", filterString, "Error parsing date filter with not between operator");
// Testing date filter LessThanOrEquals
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "CreateDate",
Type = typeof(string),
ValidFor = ValidForFlag.All,
Values = new List<object> { "2021-01-01" },
FilterType = FilterType.LESSTHANOREQUAL,
IsDateTime = true
}
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@CreateDate <= datetime('2021-01-01 23:59:59.999'))]", filterString, "Error parsing date filter with LessThanOrEquals operator");
// Testing date filter GreaterThanOrEquals
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "CreateDate",
Type = typeof(string),
ValidFor = ValidForFlag.All,
Values = new List<object> { "2021-01-01" },
FilterType = FilterType.GREATERTHANOREQUAL,
IsDateTime = true
}
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@CreateDate >= datetime('2021-01-01 00:00:00.000'))]", filterString, "Error parsing date filter with GreaterThanOrEquals operator");
// Testing date filter with invalid date
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "CreateDate",
Type = typeof(string),
ValidFor = ValidForFlag.All,
Values = new List<object> { "invalid value" },
FilterType = FilterType.EQUALS,
IsDateTime = true
}
};
Assert.Throws<FormatException>(() => INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All), "Error not thrown for creating a date sfc filter with invalid date");
// Testing date filter with invalid date for between operator
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "CreateDate",
Type = typeof(string),
ValidFor = ValidForFlag.All,
Values = new List<object> { new string[] {"invalid value", "2021-01-02"}},
FilterType = FilterType.BETWEEN,
IsDateTime = true
}
};
Assert.Throws<FormatException>(() => INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All), "Error not thrown when value array contains invalid date value for between operator");
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "CreateDate",
Type = typeof(string),
ValidFor = ValidForFlag.All,
Values = new List<object> {"2021-01-02"},
FilterType = FilterType.BETWEEN,
IsDateTime = true
}
};
Assert.Throws<InvalidCastException>(() => INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All), "Error not thrown when only one date value is provided for between operator");
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "CreateDate",
Type = typeof(string),
ValidFor = ValidForFlag.All,
Values = new List<object> { new string[] {"2021-01-02"}},
FilterType = FilterType.BETWEEN,
IsDateTime = true
}
};
Assert.Throws<IndexOutOfRangeException>(() => INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All), "Error not thrown when only one value is provided in date array for between operator");
}
[Test]
public void TextNumericFilters()
{
// Testing numeric filter with equals
var filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "RowCount",
Type = typeof(int),
ValidFor = ValidForFlag.All,
Values = new List<object> { "100" },
FilterType = FilterType.EQUALS,
IsDateTime = false
}
};
string filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@RowCount = 100)]", filterString, "Error parsing numeric filter with equals operator");
// Testing numeric filter with less than
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "RowCount",
Type = typeof(int),
ValidFor = ValidForFlag.All,
Values = new List<object> { 100 },
FilterType = FilterType.LESSTHAN,
IsDateTime = false
}
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@RowCount < 100)]", filterString, "Error parsing numeric filter with less than operator");
// Testing numeric filter with greater than
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "RowCount",
Type = typeof(int),
ValidFor = ValidForFlag.All,
Values = new List<object> { 100 },
FilterType = FilterType.GREATERTHAN,
IsDateTime = false
}
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@RowCount > 100)]", filterString, "Error parsing numeric filter with greater than operator");
// Testing numeric filter with between
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "RowCount",
Type = typeof(int),
ValidFor = ValidForFlag.All,
Values = new List<object> { new object[] {100, 200}},
FilterType = FilterType.BETWEEN,
IsDateTime = false
}
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@RowCount >= 100 and @RowCount <= 200)]", filterString, "Error parsing numeric filter with between operator");
// Testing numeric filter with not equals
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "RowCount",
Type = typeof(int),
ValidFor = ValidForFlag.All,
Values = new List<object> { 100 },
FilterType = FilterType.NOTEQUALS,
IsDateTime = false,
}
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@RowCount != 100)]", filterString, "Error parsing numeric filter with not equals operator");
// Testing numeric filter with not between
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "RowCount",
Type = typeof(int),
ValidFor = ValidForFlag.All,
Values = new List<object> { new object[] {100, 200}},
FilterType = FilterType.NOTBETWEEN,
IsDateTime = false
}
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(not(@RowCount >= 100 and @RowCount <= 200))]", filterString, "Error parsing numeric filter with not between operator");
// Testing numeric filter LessThanOrEquals
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "RowCount",
Type = typeof(int),
ValidFor = ValidForFlag.All,
Values = new List<object> { 100 },
FilterType = FilterType.LESSTHANOREQUAL,
IsDateTime = false
}
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@RowCount <= 100)]", filterString, "Error parsing numeric filter with LessThanOrEquals operator");
// Testing numeric filter GreaterThanOrEquals
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "RowCount",
Type = typeof(int),
ValidFor = ValidForFlag.All,
Values = new List<object> { 100 },
FilterType = FilterType.GREATERTHANOREQUAL,
IsDateTime = false
}
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@RowCount >= 100)]", filterString, "Error parsing numeric filter with GreaterThanOrEquals operator");
// Testing numeric filter with invalid value
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "RowCount",
Type = typeof(int),
ValidFor = ValidForFlag.All,
Values = new List<object> { "invalid value" },
FilterType = FilterType.EQUALS,
IsDateTime = false
}
};
Assert.Throws<FormatException>(() => INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All), "Error not thrown for creating a numeric sfc filter with invalid number");
// Testing numeric filter with invalid value for between operator
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "RowCount",
Type = typeof(int),
ValidFor = ValidForFlag.All,
Values = new List<object> { new object[] {"invalid value", 200}},
FilterType = FilterType.BETWEEN,
IsDateTime = false
}
};
Assert.Throws<FormatException>(() => INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All), "Error not thrown for creating a numberic sfc filter with invalid array for between operator");
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "RowCount",
Type = typeof(int),
ValidFor = ValidForFlag.All,
Values = new List<object> {200},
FilterType = FilterType.BETWEEN,
IsDateTime = false
}
};
Assert.Throws<InvalidCastException>(() => INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All), "Error not thrown when a single value is passed for between operator");
filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "RowCount",
Type = typeof(int),
ValidFor = ValidForFlag.All,
Values = new List<object> { new object[] {200}},
FilterType = FilterType.BETWEEN,
IsDateTime = false
}
};
Assert.Throws<IndexOutOfRangeException>(() => INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All), "Error not thrown when the array contains single value for between operator");
}
}
}

View File

@@ -6,6 +6,7 @@
#nullable disable
using System;
using System.Collections.Generic;
using Microsoft.Data.SqlClient;
using System.Linq;
using System.Threading;
@@ -297,7 +298,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
public void FindNodeCanExpandParentNodes()
{
var mockTreeNode = new Mock<TreeNode>();
object[] populateChildrenArguments = { ItExpr.Is<bool>(x => x == false), ItExpr.IsNull<string>(), new CancellationToken(), ItExpr.IsNull<string>() };
object[] populateChildrenArguments = { ItExpr.Is<bool>(x => x == false), ItExpr.IsNull<string>(), new CancellationToken(), ItExpr.IsNull<string>(), ItExpr.IsNull<IEnumerable<NodeFilter>>() };
mockTreeNode.Protected().Setup("PopulateChildren", populateChildrenArguments);
mockTreeNode.Object.IsAlwaysLeaf = false;