diff --git a/src/Gridify/Builder/BaseQueryBuilder.cs b/src/Gridify/Builder/BaseQueryBuilder.cs index 592dbe88..9875e0fb 100644 --- a/src/Gridify/Builder/BaseQueryBuilder.cs +++ b/src/Gridify/Builder/BaseQueryBuilder.cs @@ -217,8 +217,13 @@ private static object AddIndexerNullCheck(LambdaExpression mapTarget, object que && op.Kind is not SyntaxKind.GreaterOrEqualThan && op.Kind is not SyntaxKind.LessOrEqualThan) { - value = value.ToString()?.ToLower(); - body = Expression.Call(body, MethodInfoHelper.GetToLowerMethod()); + var strLowerValue = value.ToString()?.ToLower(); + value = strLowerValue; + + if(!string.IsNullOrEmpty(strLowerValue)) + { + body = Expression.Call(body, MethodInfoHelper.GetToLowerMethod()); + } } var query = BuildQueryAccordingToValueType(body, parameter, value, op, valueExpression); diff --git a/src/Gridify/Builder/LinqQueryBuilder.cs b/src/Gridify/Builder/LinqQueryBuilder.cs index 3a4464e8..ada3fee2 100644 --- a/src/Gridify/Builder/LinqQueryBuilder.cs +++ b/src/Gridify/Builder/LinqQueryBuilder.cs @@ -364,6 +364,9 @@ private static LambdaExpression GetContainsExpression(MemberExpression member, B if (op.Kind == SyntaxKind.NotEqual) { containsExp = Expression.Not(containsExp); + // issue #204 we need to add or null check as well for Not Contains + containsExp = Expression.OrElse(Expression.Equal(prop, Expression.Constant(null)), containsExp); + return Expression.Lambda(containsExp, param); } return GetExpressionWithNullCheck(prop, param, containsExp); } diff --git a/test/Gridify.Tests/GridifyExtensionsShould.cs b/test/Gridify.Tests/GridifyExtensionsShould.cs index f0266cb2..2e049955 100644 --- a/test/Gridify.Tests/GridifyExtensionsShould.cs +++ b/test/Gridify.Tests/GridifyExtensionsShould.cs @@ -52,6 +52,7 @@ public static IEnumerable GetSampleData() lst.Add(new TestClass(27, "ali reza", null)); lst.Add(new TestClass(27, "[ali]", null)); lst.Add(new TestClass(28, @"Esc/\pe", null)); + lst.Add(new TestClass(29, @"NullTag", null, tag: null)); return lst; } diff --git a/test/Gridify.Tests/IssueTests/Issue202Tests.cs b/test/Gridify.Tests/IssueTests/Issue202Tests.cs new file mode 100644 index 00000000..c6b93061 --- /dev/null +++ b/test/Gridify.Tests/IssueTests/Issue202Tests.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace Gridify.Tests.IssueTests; + +public class Issue202Tests +{ + private readonly List _fakeRepository = [.. GridifyExtensionsShould.GetSampleData()]; + + [Fact] + // Issue #202 + public void ApplyFiltering_NotExists_GlobalCaseInsensitiveSearch() + { + var mapper = new GridifyMapper(m => m.CaseInsensitiveFiltering = true).GenerateMappings(); + + var gq = new GridifyQuery { Filter = "tag=" }; + + var expected = _fakeRepository.Where(q => string.IsNullOrEmpty(q.Tag)).ToList(); + + var actual = _fakeRepository.AsQueryable() + .ApplyFiltering(gq, mapper) + .ToList(); + + Assert.Equal(expected.Count, actual.Count); + Assert.Equal(expected, actual); + Assert.True(actual.Any()); + } + + [Fact] + // Issue #202 + public void ApplyFiltering_Exists_GlobalCaseInsensitiveSearch() + { + var mapper = new GridifyMapper(m => m.CaseInsensitiveFiltering = true).GenerateMappings(); + + var gq = new GridifyQuery { Filter = "tag!=" }; + + var expected = _fakeRepository.Where(q => !string.IsNullOrEmpty(q.Tag)).ToList(); + + var actual = _fakeRepository.AsQueryable() + .ApplyFiltering(gq, mapper) + .ToList(); + + Assert.Equal(expected.Count, actual.Count); + Assert.Equal(expected, actual); + Assert.True(actual.Any()); + } +} \ No newline at end of file diff --git a/test/Gridify.Tests/IssueTests/Issue204Tests.cs b/test/Gridify.Tests/IssueTests/Issue204Tests.cs new file mode 100644 index 00000000..1da20b23 --- /dev/null +++ b/test/Gridify.Tests/IssueTests/Issue204Tests.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace Gridify.Tests.IssueTests; + +public class Issue204Tests +{ + [Fact] + public void ApplyFiltering_NotEquals_ShouldMatch_NullItems() + { + // arrange + var dataSource = new List() + { + new() {FavouriteColorList = ["Green", "Blue"]}, + new() {FavouriteColorList = ["White", "Yellow"]}, + new() { FavouriteColorList = null }, + }.AsQueryable(); + + var expected = dataSource.Where(q => q.FavouriteColorList == null || !q.FavouriteColorList.Contains("Green")).ToList(); + var actual = dataSource.ApplyFiltering("FavouriteColorList!=Green").ToList(); + + // assert + Assert.Equal(expected.Count, actual.Count); + Assert.Equal(expected, actual); + Assert.True(actual.Any()); + } + + private class Test + { + public List FavouriteColorList { get; set; } + } +} \ No newline at end of file