Merge pull request #49 from SuperGouge/negation-operator

Added support for negated operators
This commit is contained in:
Biarity 2019-01-09 20:34:32 +10:00 committed by GitHub
commit aecc436b44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 35 additions and 8 deletions

View File

@ -11,6 +11,10 @@ namespace Sieve.Models
private const string EscapedPipePattern = @"(?<!($|[^\\])(\\\\)*?\\)\|"; private const string EscapedPipePattern = @"(?<!($|[^\\])(\\\\)*?\\)\|";
private static readonly string[] Operators = new string[] { private static readonly string[] Operators = new string[] {
"!@=*",
"!_=*",
"!@=",
"!_=",
"==*", "==*",
"@=*", "@=*",
"_=*", "_=*",
@ -34,7 +38,8 @@ namespace Sieve.Models
Values = filterSplits.Length > 1 ? Regex.Split(filterSplits[1], EscapedPipePattern).Select(t => t.Trim()).ToArray() : null; Values = filterSplits.Length > 1 ? Regex.Split(filterSplits[1], EscapedPipePattern).Select(t => t.Trim()).ToArray() : null;
Operator = Array.Find(Operators, o => value.Contains(o)) ?? "=="; Operator = Array.Find(Operators, o => value.Contains(o)) ?? "==";
OperatorParsed = GetOperatorParsed(Operator); OperatorParsed = GetOperatorParsed(Operator);
OperatorIsCaseInsensitive = Operator.Contains("*"); OperatorIsCaseInsensitive = Operator.EndsWith("*");
OperatorIsNegated = OperatorParsed != FilterOperator.NotEquals && Operator.StartsWith("!");
} }
} }
@ -47,12 +52,11 @@ namespace Sieve.Models
public string Operator { get; private set; } public string Operator { get; private set; }
private FilterOperator GetOperatorParsed(string Operator) private FilterOperator GetOperatorParsed(string @operator)
{ {
switch (Operator.Trim().ToLower()) switch (@operator.TrimEnd('*'))
{ {
case "==": case "==":
case "==*":
return FilterOperator.Equals; return FilterOperator.Equals;
case "!=": case "!=":
return FilterOperator.NotEquals; return FilterOperator.NotEquals;
@ -65,10 +69,10 @@ namespace Sieve.Models
case "<=": case "<=":
return FilterOperator.LessThanOrEqualTo; return FilterOperator.LessThanOrEqualTo;
case "@=": case "@=":
case "@=*": case "!@=":
return FilterOperator.Contains; return FilterOperator.Contains;
case "_=": case "_=":
case "_=*": case "!_=":
return FilterOperator.StartsWith; return FilterOperator.StartsWith;
default: default:
return FilterOperator.Equals; return FilterOperator.Equals;
@ -77,6 +81,8 @@ namespace Sieve.Models
public bool OperatorIsCaseInsensitive { get; private set; } public bool OperatorIsCaseInsensitive { get; private set; }
public bool OperatorIsNegated { get; private set; }
public bool Equals(FilterTerm other) public bool Equals(FilterTerm other)
{ {
return Names.SequenceEqual(other.Names) return Names.SequenceEqual(other.Names)

View File

@ -6,6 +6,7 @@
string[] Names { get; } string[] Names { get; }
string Operator { get; } string Operator { get; }
bool OperatorIsCaseInsensitive { get; } bool OperatorIsCaseInsensitive { get; }
bool OperatorIsNegated { get; }
FilterOperator OperatorParsed { get; } FilterOperator OperatorParsed { get; }
string[] Values { get; } string[] Values { get; }
} }

View File

@ -203,13 +203,20 @@ namespace Sieve.Services
.First(m => m.Name == "ToUpper" && m.GetParameters().Length == 0)); .First(m => m.Name == "ToUpper" && m.GetParameters().Length == 0));
} }
var expression = GetExpression(filterTerm, filterValue, propertyValue);
if (filterTerm.OperatorIsNegated)
{
expression = Expression.Not(expression);
}
if (innerExpression == null) if (innerExpression == null)
{ {
innerExpression = GetExpression(filterTerm, filterValue, propertyValue); innerExpression = expression;
} }
else else
{ {
innerExpression = Expression.Or(innerExpression, GetExpression(filterTerm, filterValue, propertyValue)); innerExpression = Expression.Or(innerExpression, expression);
} }
} }
} }

View File

@ -101,6 +101,19 @@ namespace SieveUnitTests
Assert.IsTrue(result.Count() == 0); Assert.IsTrue(result.Count() == 0);
} }
[TestMethod]
public void NotContainsWorks()
{
var model = new SieveModel()
{
Filters = "Title!@=D",
};
var result = _processor.Apply(model, _posts);
Assert.IsTrue(result.Count() == 3);
}
[TestMethod] [TestMethod]
public void CanFilterBools() public void CanFilterBools()
{ {