Or Filtering on Object Explorer Nodes (#1608)

support for a more robust filtering system in the Object Explorer xml, allowing for or-ing filter properties together for use in URN querying for objects

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>
This commit is contained in:
Jordan Hays
2022-07-29 18:35:37 -04:00
committed by GitHub
parent 40df024dbc
commit 3294a52ad9
10 changed files with 1229 additions and 827 deletions

View File

@@ -36,7 +36,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
/// <summary>
/// The list of filters that should be applied on the smo object list
/// </summary>
public abstract IEnumerable<NodeFilter> Filters { get; }
public abstract IEnumerable<INodeFilter> Filters { get; }
/// <summary>
/// The list of properties to be loaded with the object

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.Generic;
//using System.Linq;
using System.Text;
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
{
/// <summary>
/// Has information for filtering a SMO object by properties
/// </summary>
public interface INodeFilter
{
/// <summary>
/// Returns true if the filter can be apply to the given type and Server type
/// </summary>
/// <param name="type">Type of the querier</param>
/// <param name="validForFlag">Server Type</param>
/// <returns></returns>
bool CanApplyFilter(Type type, ValidForFlag validForFlag);
/// <summary>
/// Creates a string from the filter property and values to be used in the Urn to query the SQL objects
/// Example of the output:[@ IsSystemObject = 0]
/// </summary>
/// <returns></returns>
string ToPropertyFilterString(Type type, ValidForFlag validForFlag);
/// <summary>
/// Creates a fully paramaterized property filter string for the URN query for SQL objects.
/// Example of the output:[@ IsSystemObject = 0]
/// </summary>
/// <returns></returns>
public static string GetPropertyFilter(IEnumerable<INodeFilter> filters, Type type, ValidForFlag validForFlag)
{
StringBuilder filter = new StringBuilder();
foreach (var value in filters)
{
string andPrefix = filter.Length == 0 ? string.Empty : " and ";
var filterString = value.ToPropertyFilterString(type, validForFlag);
if (filterString != string.Empty) {
filter.Append($"{andPrefix}{filterString}");
}
}
if (filter.Length != 0)
{
return "[" + filter.ToString() + "]";
}
return string.Empty;
}
}
}

View File

@@ -0,0 +1,58 @@
//
// 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.Text;
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
{
/// <summary>
/// Has information for filtering a SMO object by properties
/// </summary>
public class NodeOrFilter : INodeFilter
{
/// <summary>
/// Filter values
/// </summary>
public List<NodePropertyFilter> FilterList { get; set; }
/// <summary>
/// Returns true if any of the filters within the FilterList apply to the type and server type.
/// </summary>
/// <param name="type">Type of the querier</param>
/// <param name="validForFlag">Server Type</param>
public bool CanApplyFilter(Type type, ValidForFlag validForFlag) {
return this.FilterList.Exists(f => f.CanApplyFilter(type, validForFlag));
}
/// <summary>
/// Creates a string representation of a node "or" filter, which is combined in the INodeFilter interface to construct the filter used in the URN to query the SQL objects.
/// Example of the output: ((@TableTemporalType = 1) or (@LedgerTableType = 1))
/// </summary>
/// <returns></returns>
public string ToPropertyFilterString(Type type, ValidForFlag validForFlag)
{
StringBuilder filter = new StringBuilder();
foreach (var nodeFilter in FilterList)
{
string orPrefix = filter.Length == 0 ? string.Empty : " or ";
// For "or" filter, have to check each node as it's processed for whether it's valid.
var filterString = nodeFilter.ToPropertyFilterString(type, validForFlag);
if (filterString != string.Empty)
{
filter.Append($"{orPrefix}{filterString}");
}
}
if (filter.Length != 0)
{
return "(" + filter.ToString() + ")";
}
return string.Empty;
}
}
}

View File

@@ -5,14 +5,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
{
/// <summary>
/// Has information for filtering a SMO object by properties
/// </summary>
public class NodeFilter
public class NodePropertyFilter : INodeFilter
{
/// <summary>
/// Property name
@@ -55,52 +55,40 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
}
/// <summary>
/// Creates a string from the filter property and values to be used in the Urn to query the SQL objects
/// Example of the output:[@ IsSystemObject = 0]
/// Creates a string representation of a given node filter, which is combined in the INodeFilter interface to construct the filter used in the URN to query the SQL objects.
/// Example of the output: (@ IsSystemObject = 0)
/// </summary>
/// <returns></returns>
public string ToPropertyFilterString()
public string ToPropertyFilterString(Type type, ValidForFlag validForFlag)
{
string filter = "";
List<object> values = Values;
if (values != null)
// check first if the filter can be applied; if not just return empty string
if (!CanApplyFilter(type, validForFlag))
{
for (int i = 0; i < values.Count; i++)
return string.Empty;
}
StringBuilder filter = new StringBuilder();
foreach (var value in Values)
{
object propertyValue = value;
if (Type == typeof(string))
{
var value = values[i];
object propertyValue = value;
if (Type == typeof(string))
{
propertyValue = $"'{propertyValue}'";
}
if (Type == typeof(Enum))
{
propertyValue = (int)Convert.ChangeType(value, Type);
}
string orPrefix = i == 0 ? string.Empty : "or";
filter = $"{filter} {orPrefix} @{Property} = {propertyValue}";
propertyValue = $"'{propertyValue}'";
}
else if (Type == typeof(Enum))
{
propertyValue = (int)Convert.ChangeType(value, Type);
}
string orPrefix = filter.Length == 0 ? string.Empty : " or ";
filter.Append($"{orPrefix}@{Property} = {propertyValue}");
}
filter = $"({filter})";
return filter;
}
public static string ConcatProperties(IEnumerable<NodeFilter> filters)
{
string filter = "";
var list = filters.ToList();
for (int i = 0; i < list.Count; i++)
if (filter.Length != 0)
{
var value = list[i];
string andPrefix = i == 0 ? string.Empty : "and";
filter = $"{filter} {andPrefix} {value.ToPropertyFilterString()}";
return "(" + filter.ToString() + ")";
}
filter = $"[{filter}]";
return filter;
return string.Empty;
}
}
}