From aaedf7a68419a10347ab439ad3cf53ba7a5e0a69 Mon Sep 17 00:00:00 2001 From: AnasZakarneh Date: Mon, 24 May 2021 20:24:18 +0300 Subject: [PATCH] stop excluding null values when filtering using notEqual (#114) * stop excluding null values when filtering using notEqual * add IgnoreNullsOnNotEqual config field, to enable/disable the new feature Co-authored-by: AnasZakarneh --- README.md | 3 ++- Sieve.Sample/appsettings.json | 3 ++- Sieve/Models/SieveOptions.cs | 4 +++- Sieve/Services/SieveProcessor.cs | 12 ++++++----- SieveUnitTests/General.cs | 27 ++++++++++++++++++++++++- SieveUnitTests/GeneralWithInterfaces.cs | 25 +++++++++++++++++++++++ 6 files changed, 65 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index cbd4efa..33f1daa 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,8 @@ Then you can add the configuration: "CaseSensitive": "boolean: should property names be case-sensitive? Defaults to false", "DefaultPageSize": "int number: optional number to fallback to when no page argument is given. Set <=0 to disable paging if no pageSize is specified (default).", "MaxPageSize": "int number: maximum allowed page size. Set <=0 to make infinite (default)", - "ThrowExceptions": "boolean: should Sieve throw exceptions instead of silently failing? Defaults to false" + "ThrowExceptions": "boolean: should Sieve throw exceptions instead of silently failing? Defaults to false", + "IgnoreNullsOnNotEqual": "boolean: ignore null values when filtering using is not equal operator? Default to true" } } ``` diff --git a/Sieve.Sample/appsettings.json b/Sieve.Sample/appsettings.json index d1314f5..f4aec2b 100644 --- a/Sieve.Sample/appsettings.json +++ b/Sieve.Sample/appsettings.json @@ -4,7 +4,8 @@ }, "Sieve": { "CaseSensitive": false, - "DefaultPageSize": 10 + "DefaultPageSize": 10, + "IgnoreNullsOnNotEqual": true }, "Logging": { "Debug": { diff --git a/Sieve/Models/SieveOptions.cs b/Sieve/Models/SieveOptions.cs index f0059ee..226abe1 100644 --- a/Sieve/Models/SieveOptions.cs +++ b/Sieve/Models/SieveOptions.cs @@ -9,5 +9,7 @@ public int MaxPageSize { get; set; } = 0; public bool ThrowExceptions { get; set; } = false; + + public bool IgnoreNullsOnNotEqual { get; set; } = true; } -} \ No newline at end of file +} diff --git a/Sieve/Services/SieveProcessor.cs b/Sieve/Services/SieveProcessor.cs index e55655c..d71c09f 100644 --- a/Sieve/Services/SieveProcessor.cs +++ b/Sieve/Services/SieveProcessor.cs @@ -217,10 +217,13 @@ namespace Sieve.Services expression = Expression.Not(expression); } - var filterValueNullCheck = GetFilterValueNullCheck(parameter, fullPropertyName, isFilterTermValueNull); - if (filterValueNullCheck != null) + if (expression.NodeType != ExpressionType.NotEqual || Options.Value.IgnoreNullsOnNotEqual) { - expression = Expression.AndAlso(filterValueNullCheck, expression); + var filterValueNullCheck = GetFilterValueNullCheck(parameter, fullPropertyName, isFilterTermValueNull); + if (filterValueNullCheck != null) + { + expression = Expression.AndAlso(filterValueNullCheck, expression); + } } innerExpression = innerExpression == null @@ -254,8 +257,7 @@ namespace Sieve.Services : result.Where(Expression.Lambda>(outerExpression, parameter)); } - private static Expression GetFilterValueNullCheck(Expression parameter, string fullPropertyName, - bool isFilterTermValueNull) + private static Expression GetFilterValueNullCheck(Expression parameter, string fullPropertyName, bool isFilterTermValueNull) { var (propertyValue, nullCheck) = GetPropertyValueAndNullCheckExpression(parameter, fullPropertyName); diff --git a/SieveUnitTests/General.cs b/SieveUnitTests/General.cs index a59c15f..866ece5 100644 --- a/SieveUnitTests/General.cs +++ b/SieveUnitTests/General.cs @@ -15,16 +15,24 @@ namespace SieveUnitTests { private readonly ITestOutputHelper _testOutputHelper; private readonly SieveProcessor _processor; + private readonly SieveProcessor _nullableProcessor; private readonly IQueryable _posts; private readonly IQueryable _comments; public General(ITestOutputHelper testOutputHelper) { + var nullableAccessor = new SieveOptionsAccessor(); + nullableAccessor.Value.IgnoreNullsOnNotEqual = false; + _testOutputHelper = testOutputHelper; _processor = new ApplicationSieveProcessor(new SieveOptionsAccessor(), new SieveCustomSortMethods(), new SieveCustomFilterMethods()); + _nullableProcessor = new ApplicationSieveProcessor(nullableAccessor, + new SieveCustomSortMethods(), + new SieveCustomFilterMethods()); + _posts = new List { new Post @@ -180,10 +188,27 @@ namespace SieveUnitTests }; var result = _processor.Apply(model, _posts); + var nullableResult = _nullableProcessor.Apply(model, _posts); Assert.True(result.Count() == 2); + Assert.True(nullableResult.Count() == 2); } - + + [Fact] + public void CanFilterNullableIntsWithNotEqual() + { + var model = new SieveModel() + { + Filters = "CategoryId!=1" + }; + + var result = _processor.Apply(model, _posts); + var nullableResult = _nullableProcessor.Apply(model, _posts); + + Assert.True(result.Count() == 1); + Assert.True(nullableResult.Count() == 2); + } + [Theory] [InlineData(@"Text@=*\,")] [InlineData(@"Text@=*\, ")] diff --git a/SieveUnitTests/GeneralWithInterfaces.cs b/SieveUnitTests/GeneralWithInterfaces.cs index abcbaa3..f23db16 100644 --- a/SieveUnitTests/GeneralWithInterfaces.cs +++ b/SieveUnitTests/GeneralWithInterfaces.cs @@ -16,16 +16,24 @@ namespace SieveUnitTests { private readonly ITestOutputHelper _testOutputHelper; private readonly SieveProcessor _processor; + private readonly SieveProcessor _nullableProcessor; private readonly IQueryable _posts; private readonly IQueryable _comments; public GeneralWithInterfaces(ITestOutputHelper testOutputHelper) { + var nullableAccessor = new SieveOptionsAccessor(); + nullableAccessor.Value.IgnoreNullsOnNotEqual = false; + _testOutputHelper = testOutputHelper; _processor = new ApplicationSieveProcessor(new SieveOptionsAccessor(), new SieveCustomSortMethods(), new SieveCustomFilterMethods()); + _nullableProcessor = new ApplicationSieveProcessor(nullableAccessor, + new SieveCustomSortMethods(), + new SieveCustomFilterMethods()); + _posts = new List { new Post @@ -181,8 +189,25 @@ namespace SieveUnitTests }; var result = _processor.Apply(model, _posts); + var nullableResult = _nullableProcessor.Apply(model, _posts); Assert.True(result.Count() == 2); + Assert.True(nullableResult.Count() == 2); + } + + [Fact] + public void CanFilterNullableIntsWithNotEqual() + { + var model = new SieveModel() + { + Filters = "CategoryId!=1" + }; + + var result = _processor.Apply(model, _posts); + var nullableResult = _nullableProcessor.Apply(model, _posts); + + Assert.True(result.Count() == 1); + Assert.True(nullableResult.Count() == 2); } [Fact]