feature: implement new regex equals operator for JsonPath Query expression. Example: Blah[?( @.name =~'/hi/i' )]

This commit is contained in:
Minh Nguyen
2017-07-20 18:03:55 +10:00
parent bbbddf0031
commit 865b2076c2
4 changed files with 119 additions and 1 deletions
@@ -314,6 +314,17 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
Assert.AreEqual("h\\i", (string)(JToken)expressions.Right);
}
[Test]
public void SinglePropertyAndFilterWithRegex()
{
JPath path = new JPath("Blah[ ?( @.name=~'/hi/i' ) ]");
Assert.AreEqual(2, path.Filters.Count);
Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[1]).Expression;
Assert.AreEqual(QueryOperator.RegExEquals, expressions.Operator);
Assert.AreEqual("/hi/i", (string)(JToken)expressions.Right);
}
[Test]
public void SinglePropertyAndFilterWithUnknownEscape()
{
@@ -157,6 +157,70 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
Assert.IsFalse(compositeExpression.IsMatch(o3, o3));
}
[Test]
public void BooleanExpressionTest_RegExEqualsOperator()
{
BooleanQueryExpression e1 = new BooleanQueryExpression
{
Operator = QueryOperator.RegExEquals,
Right = new JValue("/foo.*d/"),
Left = new List<PathFilter>
{
new ArrayIndexFilter()
}
};
Assert.IsTrue(e1.IsMatch(null, new JArray("food")));
Assert.IsTrue(e1.IsMatch(null, new JArray("fooood and drink")));
Assert.IsFalse(e1.IsMatch(null, new JArray("FOOD")));
Assert.IsFalse(e1.IsMatch(null, new JArray("foo", "foog", "good")));
BooleanQueryExpression e2 = new BooleanQueryExpression
{
Operator = QueryOperator.RegExEquals,
Right = new JValue("/Foo.*d/i"),
Left = new List<PathFilter>
{
new ArrayIndexFilter()
}
};
Assert.IsTrue(e2.IsMatch(null, new JArray("food")));
Assert.IsTrue(e2.IsMatch(null, new JArray("fooood and drink")));
Assert.IsTrue(e2.IsMatch(null, new JArray("FOOD")));
Assert.IsFalse(e2.IsMatch(null, new JArray("foo", "foog", "good")));
}
[Test]
public void BooleanExpressionTest_RegExEqualsOperator_CornerCase()
{
BooleanQueryExpression e1 = new BooleanQueryExpression
{
Operator = QueryOperator.RegExEquals,
Right = new JValue("/// comment/"),
Left = new List<PathFilter>
{
new ArrayIndexFilter()
}
};
Assert.IsTrue(e1.IsMatch(null, new JArray("// comment")));
Assert.IsFalse(e1.IsMatch(null, new JArray("//comment", "/ comment")));
BooleanQueryExpression e2 = new BooleanQueryExpression
{
Operator = QueryOperator.RegExEquals,
Right = new JValue("/<tag>.*</tag>/i"),
Left = new List<PathFilter>
{
new ArrayIndexFilter()
}
};
Assert.IsTrue(e2.IsMatch(null, new JArray("<Tag>Test</Tag>", "")));
Assert.IsFalse(e2.IsMatch(null, new JArray("<tag>Test<tag>")));
}
[Test]
public void BooleanExpressionTest()
@@ -728,6 +728,12 @@ namespace Newtonsoft.Json.Linq.JsonPath
{
return QueryOperator.Equals;
}
if (Match("=~"))
{
return QueryOperator.RegExEquals;
}
if (Match("!=") || Match("<>"))
{
return QueryOperator.NotEquals;
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
#if !HAVE_LINQ
using Newtonsoft.Json.Utilities.LinqBridge;
#else
@@ -22,7 +23,8 @@ namespace Newtonsoft.Json.Linq.JsonPath
GreaterThan = 6,
GreaterThanOrEquals = 7,
And = 8,
Or = 9
Or = 9,
RegExEquals = 10
}
internal abstract class QueryExpression
@@ -131,6 +133,12 @@ namespace Newtonsoft.Json.Linq.JsonPath
{
switch (Operator)
{
case QueryOperator.RegExEquals:
if (RegExEquals(leftValue, rightValue))
{
return true;
}
break;
case QueryOperator.Equals:
if (EqualsWithStringCoercion(leftValue, rightValue))
{
@@ -186,6 +194,35 @@ namespace Newtonsoft.Json.Linq.JsonPath
return false;
}
private bool RegExEquals(JValue value, JValue queryValue)
{
if (queryValue.Type != JTokenType.String || value.Type != JTokenType.String)
{
return false;
}
var regExArray = ((string)queryValue.Value).Split('/');
if (regExArray.Length < 3)
{
throw new Exception("Syntax error when using regex compare");
}
var trimFirstAndLastMember = regExArray.Skip(1).Take(regExArray.Length - 2).ToArray();
var regExQuery = string.Join("/", trimFirstAndLastMember);
if (regExArray.Last() == string.Empty)
{
return Regex.IsMatch((string)value.Value, regExQuery);
}
if (regExArray.Last() == "i")
{
return Regex.IsMatch((string)value.Value, regExQuery, RegexOptions.IgnoreCase);
}
throw new Exception("Syntax error when using regex compare");
}
private bool EqualsWithStringCoercion(JValue value, JValue queryValue)
{
if (value.Equals(queryValue))