mirror of
				https://github.com/Biarity/Sieve.git
				synced 2025-10-31 08:49:15 +01:00 
			
		
		
		
	add a new operator adapt sieve processor update regex operator to split received filter value add unit tests & adjust existing ones Co-authored-by: Erwan RAULO <Erwan.RAULO@vinci-energies.net>
This commit is contained in:
		| @@ -208,10 +208,13 @@ You can replace this DSL with your own (eg. use JSON instead) by implementing an | ||||
| | `<=`       | Less than or equal to    | | ||||
| | `@=`       | Contains                 | | ||||
| | `_=`       | Starts with              | | ||||
| | `_-=`      | Ends with                | | ||||
| | `!@=`      | Does not Contains        | | ||||
| | `!_=`      | Does not Starts with     | | ||||
| | `!_-=`     | Does not Ends with       | | ||||
| | `@=*`      | Case-insensitive string Contains | | ||||
| | `_=*`      | Case-insensitive string Starts with | | ||||
| | `_-=*`     | Case-insensitive string Ends with | | ||||
| | `==*`      | Case-insensitive string Equals | | ||||
| | `!=*`      | Case-insensitive string Not equals | | ||||
| | `!@=*`     | Case-insensitive string does not Contains | | ||||
|   | ||||
| @@ -10,5 +10,6 @@ | ||||
|         LessThanOrEqualTo, | ||||
|         Contains, | ||||
|         StartsWith, | ||||
|         EndsWith, | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -8,7 +8,7 @@ namespace Sieve.Models | ||||
|     public class FilterTerm : IFilterTerm, IEquatable<FilterTerm> | ||||
|     { | ||||
|         private const string EscapedPipePattern = @"(?<!($|[^\\]|^)(\\\\)*?\\)\|"; | ||||
|         private const string OperatorsRegEx = @"(!@=\*|!_=\*|!=\*|!@=|!_=|==\*|@=\*|_=\*|==|!=|>=|<=|>|<|@=|_=)"; | ||||
|         private const string OperatorsRegEx = @"(!@=\*|!_=\*|!_-=\*|!=\*|!@=|!_=|!_-=|==\*|@=\*|_=\*|_-=\*|==|!=|>=|<=|>|<|@=|_=|_-=)"; | ||||
|         private const string EscapeNegPatternForOper = @"(?<!\\)" + OperatorsRegEx; | ||||
|         private const string EscapePosPatternForOper = @"(?<=\\)" + OperatorsRegEx; | ||||
|  | ||||
| @@ -22,13 +22,13 @@ namespace Sieve.Models | ||||
|         { | ||||
|             set | ||||
|             { | ||||
|                 var filterSplits = Regex.Split(value,EscapeNegPatternForOper).Select(t => t.Trim()).ToArray(); | ||||
|                 var filterSplits = Regex.Split(value, EscapeNegPatternForOper).Select(t => t.Trim()).ToArray(); | ||||
|  | ||||
|                 Names = Regex.Split(filterSplits[0], EscapedPipePattern).Select(t => t.Trim()).ToArray(); | ||||
|  | ||||
|                 if (filterSplits.Length > 2) | ||||
|                 { | ||||
|                     foreach (var match in Regex.Matches(filterSplits[2],EscapePosPatternForOper)) | ||||
|                     foreach (var match in Regex.Matches(filterSplits[2], EscapePosPatternForOper)) | ||||
|                     { | ||||
|                         var matchStr = match.ToString(); | ||||
|                         filterSplits[2] = filterSplits[2].Replace('\\' + matchStr, matchStr); | ||||
| @@ -39,7 +39,7 @@ namespace Sieve.Models | ||||
|                         .ToArray(); | ||||
|                 } | ||||
|  | ||||
|                 Operator = Regex.Match(value,EscapeNegPatternForOper).Value; | ||||
|                 Operator = Regex.Match(value, EscapeNegPatternForOper).Value; | ||||
|                 OperatorParsed = GetOperatorParsed(Operator); | ||||
|                 OperatorIsCaseInsensitive = Operator.EndsWith("*"); | ||||
|                 OperatorIsNegated = OperatorParsed != FilterOperator.NotEquals && Operator.StartsWith("!"); | ||||
| @@ -80,6 +80,9 @@ namespace Sieve.Models | ||||
|                 case "_=": | ||||
|                 case "!_=": | ||||
|                     return FilterOperator.StartsWith; | ||||
|                 case "_-=": | ||||
|                 case "!_-=": | ||||
|                     return FilterOperator.EndsWith; | ||||
|                 default: | ||||
|                     return FilterOperator.Equals; | ||||
|             } | ||||
|   | ||||
| @@ -339,6 +339,9 @@ namespace Sieve.Services | ||||
|                 FilterOperator.StartsWith => Expression.Call(propertyValue, | ||||
|                     typeof(string).GetMethods().First(m => m.Name == "StartsWith" && m.GetParameters().Length == 1), | ||||
|                     filterValue), | ||||
|                 FilterOperator.EndsWith => Expression.Call(propertyValue, | ||||
|                 typeof(string).GetMethods().First(m => m.Name == "EndsWith" && m.GetParameters().Length == 1), | ||||
|                 filterValue), | ||||
|                 _ => Expression.Equal(propertyValue, filterValue) | ||||
|             }; | ||||
|         } | ||||
|   | ||||
| @@ -73,6 +73,16 @@ namespace SieveUnitTests | ||||
|                     CategoryId = 2, | ||||
|                     TopComment = new Comment { Id = 1, Text = "D1" }, | ||||
|                     FeaturedComment = new Comment { Id = 7, Text = "D2" } | ||||
|                 }, | ||||
|                 new Post | ||||
|                 { | ||||
|                     Id = 4, | ||||
|                     Title = "Yen", | ||||
|                     LikeCount = 5, | ||||
|                     IsDraft = true, | ||||
|                     CategoryId = 5, | ||||
|                     TopComment = new Comment { Id = 4, Text = "Yen3" }, | ||||
|                     FeaturedComment = new Comment { Id = 8, Text = "Yen4" } | ||||
|                 } | ||||
|             }.AsQueryable(); | ||||
|  | ||||
| @@ -124,7 +134,43 @@ namespace SieveUnitTests | ||||
|             var result = _processor.Apply(model, _posts); | ||||
|  | ||||
|             Assert.Equal(1, result.First().Id); | ||||
|             Assert.True(result.Count() == 3); | ||||
|             Assert.True(result.Count() == 4); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void EndsWithWorks() | ||||
|         { | ||||
|             var model = new SieveModel | ||||
|             { | ||||
|                 Filters = "Title_-=n" | ||||
|             }; | ||||
|  | ||||
|             _testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Values.ToString()); | ||||
|             _testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Operator); | ||||
|             _testOutputHelper.WriteLine(model.GetFiltersParsed()[0].OperatorParsed.ToString()); | ||||
|  | ||||
|             var result = _processor.Apply(model, _posts); | ||||
|  | ||||
|             Assert.Equal(4, result.First().Id); | ||||
|             Assert.True(result.Count() == 1); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void EndsWithCanBeCaseInsensitive() | ||||
|         { | ||||
|             var model = new SieveModel | ||||
|             { | ||||
|                 Filters = "Title_-=*N" | ||||
|             }; | ||||
|  | ||||
|             _testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Values.ToString()); | ||||
|             _testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Operator); | ||||
|             _testOutputHelper.WriteLine(model.GetFiltersParsed()[0].OperatorParsed.ToString()); | ||||
|  | ||||
|             var result = _processor.Apply(model, _posts); | ||||
|  | ||||
|             Assert.Equal(4, result.First().Id); | ||||
|             Assert.True(result.Count() == 1); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
| @@ -150,7 +196,7 @@ namespace SieveUnitTests | ||||
|  | ||||
|             var result = _processor.Apply(model, _posts); | ||||
|  | ||||
|             Assert.True(result.Count() == 3); | ||||
|             Assert.True(result.Count() == 4); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
| @@ -205,8 +251,8 @@ namespace SieveUnitTests | ||||
|             var result = _processor.Apply(model, _posts); | ||||
|             var nullableResult = _nullableProcessor.Apply(model, _posts); | ||||
|  | ||||
|             Assert.True(result.Count() == 1); | ||||
|             Assert.True(nullableResult.Count() == 2); | ||||
|             Assert.True(result.Count() == 2); | ||||
|             Assert.True(nullableResult.Count() == 3); | ||||
|         } | ||||
|  | ||||
|         [Theory] | ||||
| @@ -255,7 +301,7 @@ namespace SieveUnitTests | ||||
|             var result = _processor.Apply(model, _posts); | ||||
|  | ||||
|             Assert.False(result.Any(p => p.Id == 0)); | ||||
|             Assert.True(result.Count() == 3); | ||||
|             Assert.True(result.Count() == 4); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
| @@ -474,11 +520,12 @@ namespace SieveUnitTests | ||||
|             }; | ||||
|  | ||||
|             var result = _processor.Apply(model, _posts); | ||||
|             Assert.Equal(3, result.Count()); | ||||
|             Assert.Equal(4, result.Count()); | ||||
|             var posts = result.ToList(); | ||||
|             Assert.Contains("B", posts[0].TopComment.Text); | ||||
|             Assert.Contains("C", posts[1].TopComment.Text); | ||||
|             Assert.Contains("D", posts[2].TopComment.Text); | ||||
|             Assert.Contains("Yen", posts[3].TopComment.Text); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
| @@ -490,12 +537,13 @@ namespace SieveUnitTests | ||||
|             }; | ||||
|  | ||||
|             var result = _processor.Apply(model, _posts); | ||||
|             Assert.Equal(4, result.Count()); | ||||
|             Assert.Equal(5, result.Count()); | ||||
|             var posts = result.ToList(); | ||||
|             Assert.Equal(0, posts[0].Id); | ||||
|             Assert.Equal(3, posts[1].Id); | ||||
|             Assert.Equal(2, posts[2].Id); | ||||
|             Assert.Equal(1, posts[3].Id); | ||||
|             Assert.Equal(4, posts[4].Id); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
| @@ -630,13 +678,15 @@ namespace SieveUnitTests | ||||
|             }; | ||||
|  | ||||
|             var result = _processor.Apply(model, _posts); | ||||
|             Assert.Equal(4, result.Count()); | ||||
|             Assert.Equal(5, result.Count()); | ||||
|  | ||||
|             var posts = result.ToList(); | ||||
|             Assert.Equal(3,posts[0].Id); | ||||
|             Assert.Equal(2,posts[1].Id); | ||||
|             Assert.Equal(1,posts[2].Id); | ||||
|             Assert.Equal(0,posts[3].Id); | ||||
|             Assert.Equal(4, posts[0].Id); | ||||
|             Assert.Equal(3,posts[1].Id); | ||||
|             Assert.Equal(2,posts[2].Id); | ||||
|             Assert.Equal(1,posts[3].Id); | ||||
|             Assert.Equal(0,posts[4].Id); | ||||
|  | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
| @@ -759,10 +809,13 @@ namespace SieveUnitTests | ||||
|         [InlineData(@"Title@=\>= ")] | ||||
|         [InlineData(@"Title@=\@= ")] | ||||
|         [InlineData(@"Title@=\_= ")] | ||||
|         [InlineData(@"Title@=\_-= ")] | ||||
|         [InlineData(@"Title@=!\@= ")] | ||||
|         [InlineData(@"Title@=!\_= ")] | ||||
|         [InlineData(@"Title@=!\_-= ")] | ||||
|         [InlineData(@"Title@=\@=* ")] | ||||
|         [InlineData(@"Title@=\_=* ")] | ||||
|         [InlineData(@"Title@=\_-=* ")] | ||||
|         [InlineData(@"Title@=\==* ")] | ||||
|         [InlineData(@"Title@=\!=* ")] | ||||
|         [InlineData(@"Title@=!\@=* ")] | ||||
| @@ -773,7 +826,7 @@ namespace SieveUnitTests | ||||
|                 new Post | ||||
|                 { | ||||
|                     Id = 1, | ||||
|                     Title = @"Operators: == != > < >= <= @= _= !@= !_= @=* _=* ==* !=* !@=* !_=* ", | ||||
|                     Title = @"Operators: == != > < >= <= @= _= _-= !@= !_= !_-= @=* _=* ==* !=* !@=* !_=* !_-=* ", | ||||
|                     LikeCount = 1, | ||||
|                     IsDraft = true, | ||||
|                     CategoryId = 1, | ||||
|   | ||||
| @@ -31,7 +31,7 @@ namespace SieveUnitTests | ||||
|                 { | ||||
|                     Id = 1, | ||||
|                     DateCreated = DateTimeOffset.UtcNow,  | ||||
|                     Text = "null is here in the text", | ||||
|                     Text = "null is here twice in the text ending by null", | ||||
|                     Author = "Cat", | ||||
|                 }, | ||||
|                 new Comment | ||||
| @@ -136,6 +136,21 @@ namespace SieveUnitTests | ||||
|             Assert.Equal(new[] {1}, result.Select(p => p.Id)); | ||||
|         } | ||||
|  | ||||
|         [Theory] | ||||
|         [InlineData("Text_-=null")] | ||||
|         [InlineData("Text_-=*null")] | ||||
|         [InlineData("Text_-=*NULL")] | ||||
|         [InlineData("Text_-=*NulL")] | ||||
|         [InlineData("Text_-=*null|text")] | ||||
|         public void Filter_EndsWith_NullString(string filter) | ||||
|         { | ||||
|             var model = new SieveModel { Filters = filter }; | ||||
|  | ||||
|             var result = _processor.Apply(model, _comments); | ||||
|  | ||||
|             Assert.Equal(new[] { 1 }, result.Select(p => p.Id)); | ||||
|         } | ||||
|  | ||||
|         [Theory] | ||||
|         [InlineData("Text!@=null")] | ||||
|         [InlineData("Text!@=*null")] | ||||
| @@ -164,5 +179,19 @@ namespace SieveUnitTests | ||||
|  | ||||
|             Assert.Equal(new[] {0, 2}, result.Select(p => p.Id)); | ||||
|         } | ||||
|  | ||||
|         [Theory] | ||||
|         [InlineData("Text!_-=null")] | ||||
|         [InlineData("Text!_-=*null")] | ||||
|         [InlineData("Text!_-=*NULL")] | ||||
|         [InlineData("Text!_-=*NulL")] | ||||
|         public void Filter_DoesNotEndsWith_NullString(string filter) | ||||
|         { | ||||
|             var model = new SieveModel { Filters = filter }; | ||||
|  | ||||
|             var result = _processor.Apply(model, _comments); | ||||
|  | ||||
|             Assert.Equal(new[] { 0, 2 }, result.Select(p => p.Id)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user