Adding like filter and removing contains to OE filtering (#2105)

* Adding startswith and like filter

* Adding ends with

* Adding tests

* Remove null and not null

* Fixing string

* Update test/Microsoft.SqlTools.ServiceLayer.UnitTests/ObjectExplorer/NodeFilterTests.cs

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

* Update test/Microsoft.SqlTools.ServiceLayer.UnitTests/ObjectExplorer/NodeFilterTests.cs

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

* Adding back contains, starts with and ends with

* Properly escaping chars for like based filters

* Adding some comments regarding escape characters

* Using generated regex

* removing additional class

* Adding extra auth type that was causing the tests to error out

* Fixing regex

* Adding integration tests

* Fixing unit tests

* Making fluent assertions

---------

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>
This commit is contained in:
Aasim Khan
2023-06-28 16:17:20 -07:00
committed by GitHub
parent 2a30a648f7
commit 6b251bd24a
6 changed files with 535 additions and 46 deletions

View File

@@ -157,6 +157,10 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts
NotBetween = 7,
Contains = 8,
NotContains = 9,
StartsWith = 10,
NotStartsWith = 11,
EndsWith = 12,
NotEndsWith = 13
}
/// <summary>

View File

@@ -8,13 +8,16 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.SqlTools.ServiceLayer.Management;
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
{
/// <summary>
/// Has information for filtering a SMO object by properties
/// </summary>
public class NodePropertyFilter : INodeFilter
public partial class NodePropertyFilter : INodeFilter
{
/// <summary>
/// Property name
@@ -182,7 +185,25 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
object propertyValue = value;
if (Type == typeof(string))
{
propertyValue = $"'{propertyValue}'";
//Replacing quotes with double quotes
var escapedString = CUtils.EscapeStringSQuote(propertyValue.ToString());
if (this.FilterType == FilterType.STARTSWITH || this.FilterType == FilterType.ENDSWITH)
{
escapedString = EscapeLikeURNRegex().Replace(escapedString, "[$0]");
if (this.FilterType == FilterType.STARTSWITH)
{
propertyValue = $"'{escapedString}%'";
}
else if (this.FilterType == FilterType.ENDSWITH)
{
propertyValue = $"'%{escapedString}'";
}
}
else
{
propertyValue = $"'{escapedString}'";
}
}
else if (Type == typeof(Enum))
{
@@ -211,15 +232,19 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
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;
case FilterType.CONTAINS:
filterText = $"contains(@{Property}, {propertyValue})";
break;
case FilterType.STARTSWITH:
case FilterType.ENDSWITH:
filterText = $"like(@{Property}, {propertyValue})";
break;
}
}
@@ -261,13 +286,17 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
return false;
}
}
// For filters that use the LIKE operator, we need to escape the following characters: %, _, [, ^
// we do this by wrapping them in square brackets eg: [%], [_], [[], [^]
[GeneratedRegexAttribute(@"%|_|\[|\^")]
public static partial Regex EscapeLikeURNRegex();
}
public enum FilterType
{
EQUALS,
DATETIME,
CONTAINS,
FALSE,
ISNULL,
NOTEQUALS,
@@ -276,6 +305,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
LESSTHANOREQUAL,
GREATERTHANOREQUAL,
BETWEEN,
NOTBETWEEN
NOTBETWEEN,
CONTAINS,
STARTSWITH,
ENDSWITH
}
}

View File

@@ -129,13 +129,6 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
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;
@@ -143,9 +136,29 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
filterType = FilterType.NOTBETWEEN;
isNotFilter = true;
break;
case NodeFilterOperator.Contains:
filterType = FilterType.CONTAINS;
break;
case NodeFilterOperator.NotContains:
filterType = FilterType.CONTAINS;
isNotFilter = true;
break;
case NodeFilterOperator.StartsWith:
filterType = FilterType.STARTSWITH;
break;
case NodeFilterOperator.NotStartsWith:
filterType = FilterType.STARTSWITH;
isNotFilter = true;
break;
case NodeFilterOperator.EndsWith:
filterType = FilterType.ENDSWITH;
break;
case NodeFilterOperator.NotEndsWith:
filterType = FilterType.ENDSWITH;
isNotFilter = true;
break;
}
if (filter.Operator == NodeFilterOperator.Between || filter.Operator == NodeFilterOperator.NotBetween)
{
if (filterProperty.Type == NodeFilterPropertyDataType.Number)

View File

@@ -293,6 +293,95 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectExplorer
});
}
[Test]
public async Task VerifyOEFilters()
{
string query = @"
Create table ""table['^__']"" (id int);
Create table ""table['^__']2"" (id int);
Create table ""table['^%%2"" (id int);
Create table ""testTable"" (id int);
";
string databaseName = "#testDb#";
await RunTest(databaseName, query, "Testdb", async (testDbName, session) =>
{
var databaseNode = session.Root.ToNodeInfo();
var databaseChildren = await _service.ExpandNode(session, databaseNode.NodePath);
Assert.True(databaseChildren.Nodes.Any(t => t.Label == SR.SchemaHierarchy_Tables), "Tables node should be found in database node");
var tablesNode = databaseChildren.Nodes.First(t => t.Label == SR.SchemaHierarchy_Tables);
var NameProperty = tablesNode.FilterableProperties.First(t => t.Name == "Name");
Assert.True(NameProperty != null, "Name property should be found in tables node");
// Testing contains operator
NodeFilter filter = new NodeFilter()
{
Name = NameProperty.Name,
Value = "table",
Operator = NodeFilterOperator.Contains
};
var tablesChildren = await _service.ExpandNode(session, tablesNode.NodePath, true, null, new NodeFilter[] { filter });
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.testTable"), "testTable node should be found in tables node");
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.table['^__']"), "table['^__'] node should be found in tables node");
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.table['^__']2"), "table['^__']2 node should be found in tables node");
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.table['^%%2"), "table['^%%2 node should be found in tables node");
// Testing starts with operator
filter = new NodeFilter()
{
Name = NameProperty.Name,
Value = "table['^__']",
Operator = NodeFilterOperator.StartsWith
};
tablesChildren = await _service.ExpandNode(session, tablesNode.NodePath, true, null, new NodeFilter[] { filter });
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.table['^__']"), "table['^__'] node should be found in tables node");
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.table['^__']2"), "table['^__']2 node should be found in tables node");
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.testTable") == false, "testTable node should not be found in tables node");
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.table['^%%2") == false, "table['^%%2 node should not be found in tables node");
// Testing starts with operator
filter = new NodeFilter()
{
Name = NameProperty.Name,
Value = "table['^%%2",
Operator = NodeFilterOperator.StartsWith
};
tablesChildren = await _service.ExpandNode(session, tablesNode.NodePath, true, null, new NodeFilter[] { filter });
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.table['^%%2"), "table['^%%2 node should be found in tables node");
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.table['^__']") == false, "table['^__'] node should not be found in tables node");
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.table['^__']2") == false, "table['^__']2 node should not be found in tables node");
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.testTable") == false, "testTable node should not be found in tables node");
// Testing ends with operator
filter = new NodeFilter()
{
Name = NameProperty.Name,
Value = "table['^__']",
Operator = NodeFilterOperator.EndsWith
};
tablesChildren = await _service.ExpandNode(session, tablesNode.NodePath, true, null, new NodeFilter[] { filter });
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.table['^__']"), "table['^__'] node should be found in tables node");
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.table['^__']2") == false, "table['^__']2 node should not be found in tables node");
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.testTable") == false, "testTable node should not be found in tables node");
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.table['^%%2") == false, "table['^%%2 node should not be found in tables node");
// Testing equals operator
filter = new NodeFilter()
{
Name = NameProperty.Name,
Value = "table['^__']",
Operator = NodeFilterOperator.Equals
};
tablesChildren = await _service.ExpandNode(session, tablesNode.NodePath, true, null, new NodeFilter[] { filter });
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.table['^__']"), "table['^__'] node should be found in tables node");
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.table['^__']2") == false, "table['^__']2 node should not be found in tables node");
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.testTable") == false, "testTable node should not be found in tables node");
Assert.That(tablesChildren.Nodes.Any(t => t.Label == "dbo.table['^%%2") == false, "table['^%%2 node should not be found in tables node");
});
}
private async Task VerifyRefresh(ObjectExplorerSession session, string tablePath, string tableName, bool deleted = true)
{
//Refresh Root

View File

@@ -29,6 +29,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common
public enum AuthenticationType
{
Integrated,
SqlLogin
SqlLogin,
AzureMFA
}
}

View File

@@ -7,11 +7,14 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts;
using NUnit.Framework;
using Newtonsoft.Json.Linq;
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
{
@@ -241,7 +244,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
};
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");
Assert.That(filterString, Is.EqualTo("[(@CreateDate >= datetime('2021-01-01 00:00:00.000') and @CreateDate <= datetime('2021-01-01 23:59:59.999'))]"), "Error parsing date filter with equals operator");
// Testing date filter with less than
@@ -259,7 +262,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
};
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");
Assert.That(filterString, Is.EqualTo("[(@CreateDate < datetime('2021-01-01 00:00:00.000'))]"), "Error parsing date filter with less than operator");
// Testing date filter with greater than
filterList = new List<NodePropertyFilter>
@@ -276,7 +279,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
};
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");
Assert.That(filterString, Is.EqualTo("[(@CreateDate > datetime('2021-01-01 23:59:59.999'))]"), "Error parsing date filter with greater than operator");
// Testing date filter with between
filterList = new List<NodePropertyFilter>
@@ -293,7 +296,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
};
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");
Assert.That(filterString, Is.EqualTo("[(@CreateDate >= datetime('2021-01-01 00:00:00.000') and @CreateDate <= datetime('2021-01-02 23:59:59.999'))]"), "Error parsing date filter with between operator");
// Testing date filter with not equals
@@ -311,7 +314,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
};
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");
Assert.That(filterString, Is.EqualTo("[(not(@CreateDate >= datetime('2021-01-01 00:00:00.000') and @CreateDate <= datetime('2021-01-01 23:59:59.999')))]"), "Error parsing date filter with not equals operator");
// Testing date filter with not between
@@ -328,7 +331,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
}
};
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");
Assert.That(filterString, Is.EqualTo("[(not(@CreateDate >= datetime('2021-01-01 00:00:00.000') and @CreateDate <= datetime('2021-01-02 23:59:59.999')))]"), "Error parsing date filter with not between operator");
// Testing date filter LessThanOrEquals
filterList = new List<NodePropertyFilter>
@@ -344,7 +347,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
}
};
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");
Assert.That(filterString, Is.EqualTo("[(@CreateDate <= datetime('2021-01-01 23:59:59.999'))]"), "Error parsing date filter with LessThanOrEquals operator");
// Testing date filter GreaterThanOrEquals
filterList = new List<NodePropertyFilter>
@@ -360,7 +363,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
}
};
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");
Assert.That(filterString, Is.EqualTo("[(@CreateDate >= datetime('2021-01-01 00:00:00.000'))]"), "Error parsing date filter with GreaterThanOrEquals operator");
// Testing date filter with invalid date
@@ -438,7 +441,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
};
string filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@RowCount = 100)]", filterString, "Error parsing numeric filter with equals operator");
Assert.That(filterString, Is.EqualTo("[(@RowCount = 100)]"), "Error parsing numeric filter with equals operator");
// Testing numeric filter with less than
filterList = new List<NodePropertyFilter>
@@ -455,7 +458,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@RowCount < 100)]", filterString, "Error parsing numeric filter with less than operator");
Assert.That(filterString, Is.EqualTo("[(@RowCount < 100)]"), "Error parsing numeric filter with less than operator");
// Testing numeric filter with greater than
filterList = new List<NodePropertyFilter>
@@ -472,7 +475,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@RowCount > 100)]", filterString, "Error parsing numeric filter with greater than operator");
Assert.That(filterString, Is.EqualTo("[(@RowCount > 100)]"), "Error parsing numeric filter with greater than operator");
// Testing numeric filter with between
filterList = new List<NodePropertyFilter>
@@ -488,7 +491,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
}
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@RowCount >= 100 and @RowCount <= 200)]", filterString, "Error parsing numeric filter with between operator");
Assert.That(filterString, Is.EqualTo("[(@RowCount >= 100 and @RowCount <= 200)]"), "Error parsing numeric filter with between operator");
// Testing numeric filter with not equals
filterList = new List<NodePropertyFilter>
@@ -504,7 +507,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
}
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@RowCount != 100)]", filterString, "Error parsing numeric filter with not equals operator");
Assert.That(filterString, Is.EqualTo("[(@RowCount != 100)]"), "Error parsing numeric filter with not equals operator");
// Testing numeric filter with not between
filterList = new List<NodePropertyFilter>
@@ -520,7 +523,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
}
};
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");
Assert.That(filterString, Is.EqualTo("[(not(@RowCount >= 100 and @RowCount <= 200))]"), "Error parsing numeric filter with not between operator");
// Testing numeric filter LessThanOrEquals
filterList = new List<NodePropertyFilter>
@@ -536,7 +539,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
}
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@RowCount <= 100)]", filterString, "Error parsing numeric filter with LessThanOrEquals operator");
Assert.That(filterString, Is.EqualTo("[(@RowCount <= 100)]"), "Error parsing numeric filter with LessThanOrEquals operator");
// Testing numeric filter GreaterThanOrEquals
filterList = new List<NodePropertyFilter>
@@ -552,7 +555,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
}
};
filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.AreEqual("[(@RowCount >= 100)]", filterString, "Error parsing numeric filter with GreaterThanOrEquals operator");
Assert.That(filterString, Is.EqualTo("[(@RowCount >= 100)]"), filterString, "Error parsing numeric filter with GreaterThanOrEquals operator");
// Testing numeric filter with invalid value
filterList = new List<NodePropertyFilter>
@@ -610,5 +613,352 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
};
Assert.Throws<IndexOutOfRangeException>(() => INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All), "Error not thrown when the array contains single value for between operator");
}
[Test]
public void TestContainsFilter()
{
// Testing text filter with ends with operator
var filterList = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "Name",
Type = typeof(string),
ValidFor = ValidForFlag.All,
Values = new List<object> { "test" },
FilterType = FilterType.CONTAINS,
IsDateTime = false
}
};
var filterString = INodeFilter.GetPropertyFilter(filterList, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.That(filterString, Is.EqualTo("[(contains(@Name, 'test'))]"), "Error parsing text filter with contains operator");
}
public static IEnumerable<TestCaseData> ConvertExpandNodeFilterToNodeFilterTestCases
{
get
{
// Test case for equals operator
yield return new TestCaseData(
new NodeFilter()
{
Name = "Name",
Operator = NodeFilterOperator.Equals,
Value = "test"
},
new NodeFilterProperty()
{
Name = "Name",
Type = NodeFilterPropertyDataType.String
},
new NodePropertyFilter()
{
Property = "Name",
Type = typeof(string),
Values = new List<object> { "test" },
IsNotFilter = false,
FilterType = FilterType.EQUALS,
IsDateTime = false
}
);
// Test case for not equals operator
yield return new TestCaseData(
new NodeFilter()
{
Name = "Name",
Operator = NodeFilterOperator.NotEquals,
Value = "test"
},
new NodeFilterProperty()
{
Name = "Name",
Type = NodeFilterPropertyDataType.String
},
new NodePropertyFilter()
{
Property = "Name",
Type = typeof(string),
Values = new List<object> { "test" },
IsNotFilter = true,
FilterType = FilterType.EQUALS,
IsDateTime = false
}
);
// Test case for like operator with string value
yield return new TestCaseData(
new NodeFilter()
{
Name = "Name",
Operator = NodeFilterOperator.Contains,
Value = "test"
},
new NodeFilterProperty()
{
Name = "Name",
Type = NodeFilterPropertyDataType.String
},
new NodePropertyFilter()
{
Property = "Name",
Type = typeof(string),
Values = new List<object> { "test" },
IsNotFilter = false,
FilterType = FilterType.CONTAINS,
IsDateTime = false
}
);
// Test case for not like operator with string value
yield return new TestCaseData(
new NodeFilter()
{
Name = "Name",
Operator = NodeFilterOperator.NotContains,
Value = "test"
},
new NodeFilterProperty()
{
Name = "Name",
Type = NodeFilterPropertyDataType.String
},
new NodePropertyFilter()
{
Property = "Name",
Type = typeof(string),
Values = new List<object> { "test" },
IsNotFilter = true,
FilterType = FilterType.CONTAINS,
IsDateTime = false
}
);
// Test case for date filter with equals operator
yield return new TestCaseData(
new NodeFilter()
{
Name = "Date",
Operator = NodeFilterOperator.Equals,
Value = "2020-01-01"
},
new NodeFilterProperty()
{
Name = "Date",
Type = NodeFilterPropertyDataType.Date
},
new NodePropertyFilter()
{
Property = "Date",
Type = typeof(string),
Values = new List<object> { "2020-01-01" },
IsNotFilter = false,
FilterType = FilterType.EQUALS,
IsDateTime = true
}
);
// test case for date with between operator
yield return new TestCaseData(
new NodeFilter()
{
Name = "Date",
Operator = NodeFilterOperator.Between,
Value = JArray.FromObject(new string[] { "2020-01-01", "2020-01-02" })
},
new NodeFilterProperty()
{
Name = "Date",
Type = NodeFilterPropertyDataType.Date
},
new NodePropertyFilter()
{
Property = "Date",
Type = typeof(string),
Values = new List<object> { new string[] { "2020-01-01", "2020-01-02" } },
IsNotFilter = false,
FilterType = FilterType.BETWEEN,
IsDateTime = true
}
);
// test case for date with not between operator
yield return new TestCaseData(
new NodeFilter()
{
Name = "Date",
Operator = NodeFilterOperator.NotBetween,
Value = JArray.FromObject(new string[] { "2020-01-01", "2020-01-02" })
},
new NodeFilterProperty()
{
Name = "Date",
Type = NodeFilterPropertyDataType.Date
},
new NodePropertyFilter()
{
Property = "Date",
Type = typeof(string),
Values = new List<object> { new string[] { "2020-01-01", "2020-01-02" } },
IsNotFilter = true,
FilterType = FilterType.NOTBETWEEN,
IsDateTime = true
}
);
// test case for date with starts with operator
yield return new TestCaseData(
new NodeFilter()
{
Name = "Name",
Operator = NodeFilterOperator.StartsWith,
Value = "test"
},
new NodeFilterProperty()
{
Name = "Name",
Type = NodeFilterPropertyDataType.String
},
new NodePropertyFilter()
{
Property = "Name",
Type = typeof(string),
Values = new List<object> { "test" },
IsNotFilter = false,
FilterType = FilterType.STARTSWITH,
IsDateTime = false
}
);
// test case for date with not starts with operator
yield return new TestCaseData(
new NodeFilter()
{
Name = "Name",
Operator = NodeFilterOperator.NotStartsWith,
Value = "test"
},
new NodeFilterProperty()
{
Name = "Name",
Type = NodeFilterPropertyDataType.String
},
new NodePropertyFilter()
{
Property = "Name",
Type = typeof(string),
Values = new List<object> { "test" },
IsNotFilter = true,
FilterType = FilterType.STARTSWITH,
IsDateTime = false
}
);
// test case for date with ends with operator
yield return new TestCaseData(
new NodeFilter()
{
Name = "Name",
Operator = NodeFilterOperator.EndsWith,
Value = "test"
},
new NodeFilterProperty()
{
Name = "Name",
Type = NodeFilterPropertyDataType.String
},
new NodePropertyFilter()
{
Property = "Name",
Type = typeof(string),
Values = new List<object> { "test" },
IsNotFilter = false,
FilterType = FilterType.ENDSWITH,
IsDateTime = false
}
);
// test case for date with not ends with operator
yield return new TestCaseData(
new NodeFilter()
{
Name = "Name",
Operator = NodeFilterOperator.NotEndsWith,
Value = "test"
},
new NodeFilterProperty()
{
Name = "Name",
Type = NodeFilterPropertyDataType.String
},
new NodePropertyFilter()
{
Property = "Name",
Type = typeof(string),
Values = new List<object> { "test" },
IsNotFilter = true,
FilterType = FilterType.ENDSWITH,
IsDateTime = false
}
);
}
}
[Test]
[TestCaseSource("ConvertExpandNodeFilterToNodeFilterTestCases")]
public void TestConvertExpandNodeFilterToNodeFilter(NodeFilter filter, NodeFilterProperty prop, INodeFilter expectedParsedFilter)
{
INodeFilter actualParsedFilter = ObjectExplorerUtils.ConvertExpandNodeFilterToNodeFilter(filter, prop);
Assert.That(
JsonConvert.SerializeObject(actualParsedFilter),
Is.EqualTo(JsonConvert.SerializeObject(expectedParsedFilter)),
$"Error parsing node filter '{prop.Name} ({prop.Type.ToString()})' with operator '{filter.Operator.ToString()}' and value '{filter.Value}'"
);
}
[Test]
[TestCase("test''test", "[(@Name = 'test''''test')]", "[(like(@Name, 'test''''test%'))]")]
[TestCase("test'test", "[(@Name = 'test''test')]", "[(like(@Name, 'test''test%'))]")]
[TestCase("test'test'test", "[(@Name = 'test''test''test')]", "[(like(@Name, 'test''test''test%'))]")]
[TestCase("test'[test]test", "[(@Name = 'test''[test]test')]", "[(like(@Name, 'test''[[]test]test%'))]")]
[TestCase("test^][%test", "[(@Name = 'test^][%test')]", "[(like(@Name, 'test[^]][[][%]test%'))]")]
[TestCase("test%test", "[(@Name = 'test%test')]", "[(like(@Name, 'test[%]test%'))]")]
[TestCase("test[test", "[(@Name = 'test[test')]", "[(like(@Name, 'test[[]test%'))]")]
[TestCase("test]test", "[(@Name = 'test]test')]", "[(like(@Name, 'test]test%'))]")]
[TestCase("test%%'%%test", "[(@Name = 'test%%''%%test')]", "[(like(@Name, 'test[%][%]''[%][%]test%'))]")]
public void TestFilterValuesWithSpecialCharacters(string input, string expectedFilterValue, string expectedLikeFilterValue)
{
var nonLikeFilter = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "Name",
Type = typeof(string),
ValidFor = ValidForFlag.All,
Values = new List<object> { input },
FilterType = FilterType.EQUALS,
IsDateTime = false
}
};
var actualFilterValue = INodeFilter.GetPropertyFilter(nonLikeFilter, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.That(actualFilterValue, Is.EqualTo(expectedFilterValue));
var likeFilter = new List<NodePropertyFilter>
{
new NodePropertyFilter()
{
Property = "Name",
Type = typeof(string),
ValidFor = ValidForFlag.All,
Values = new List<object> { input },
FilterType = FilterType.STARTSWITH,
IsDateTime = false
}
};
var actualLikeFilterValue = INodeFilter.GetPropertyFilter(likeFilter, typeof(SqlHistoryTableQuerier), ValidForFlag.All);
Assert.That(actualLikeFilterValue, Is.EqualTo(expectedLikeFilterValue));
}
}
}