From f94d7587ad6f2e7c32669d97e9dab5a055886331 Mon Sep 17 00:00:00 2001 From: enisn Date: Fri, 24 Oct 2025 19:49:43 +0300 Subject: [PATCH 1/2] Improve array search filter for nullable Guid properties Enhanced ArraySearchFilterAttribute to handle nullable Guid properties by using extension methods for non-nullable types and value extraction. Added tests for filtering with Guid arrays without attribute and updated Preferences model to include OrganizationUnitId with ArraySearchFilter. --- .../Attributes/ArraySearchFilterAttribute.cs | 11 +++++----- .../Attributes/ArraySearchAttributeTests.cs | 22 +++++++++++++++++++ ...Filter_ArraySearchWithoutAttribute_Guid.cs | 10 +++++++++ .../Environment/Models/Preferences.cs | 6 ++++- 4 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 tests/AutoFilterer.Tests/Environment/Dtos/PreferencesFilter_ArraySearchWithoutAttribute_Guid.cs diff --git a/src/AutoFilterer/Attributes/ArraySearchFilterAttribute.cs b/src/AutoFilterer/Attributes/ArraySearchFilterAttribute.cs index b8adc4b..52ac321 100644 --- a/src/AutoFilterer/Attributes/ArraySearchFilterAttribute.cs +++ b/src/AutoFilterer/Attributes/ArraySearchFilterAttribute.cs @@ -1,4 +1,5 @@ -using System.Collections; +using AutoFilterer.Extensions; +using System.Collections; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -14,8 +15,8 @@ public override Expression BuildExpression(ExpressionBuildContext context) return Expression.Constant(true); // TODO: Make it better. Maybe return null? When null, it should be ignored and combined with another expressions. } - var type = context.TargetProperty.PropertyType; - var prop = Expression.Property(context.ExpressionBody, context.TargetProperty.Name); + var type = context.TargetProperty.PropertyType.AsNonNullable(); + var prop = Expression.Property(context.ExpressionBody, context.TargetProperty.Name).GetValueExpressionIfNullable(); var containsMethod = typeof(Enumerable).GetMethods().FirstOrDefault(x => x.Name == nameof(Enumerable.Contains)).MakeGenericMethod(type); @@ -23,8 +24,8 @@ public override Expression BuildExpression(ExpressionBuildContext context) method: containsMethod, arguments: new Expression[] { - Expression.Property(Expression.Constant(context.FilterObject), context.FilterProperty), - Expression.Property(context.ExpressionBody, context.TargetProperty) + Expression.Property(Expression.Constant(context.FilterObject), context.FilterProperty).GetValueExpressionIfNullable(), + Expression.Property(context.ExpressionBody, context.TargetProperty).GetValueExpressionIfNullable() }); return containsExpression; diff --git a/tests/AutoFilterer.Tests/Attributes/ArraySearchAttributeTests.cs b/tests/AutoFilterer.Tests/Attributes/ArraySearchAttributeTests.cs index 569fdb8..4fb9088 100644 --- a/tests/AutoFilterer.Tests/Attributes/ArraySearchAttributeTests.cs +++ b/tests/AutoFilterer.Tests/Attributes/ArraySearchAttributeTests.cs @@ -3,6 +3,7 @@ using AutoFilterer.Tests.Environment.Dtos; using AutoFilterer.Tests.Environment.Models; using System; +using System; using System.Collections.Generic; using System.Linq; using Xunit; @@ -57,6 +58,27 @@ public void BuildExpression_ShouldGenerateQueryCorrect_WithAttribute(List data) + { + // Arrange + var queryable = data.AsQueryable(); + var filter = new PreferencesFilter_ArraySearchWithoutAttribute_Guid + { + OrganizationUnitId = data.Take(3).Select(x => x.OrganizationUnitId.GetValueOrDefault()).ToArray() + }; + + // Act + var expectedResult = queryable.Where(x => filter.OrganizationUnitId.Contains(x.OrganizationUnitId.GetValueOrDefault())); + var actualResult = queryable.ApplyFilter(filter); + + // Assert + Assert.Equal(expectedResult.Count(), actualResult.Count()); + + foreach (var expected in expectedResult) + Assert.True(actualResult.Contains(expected)); + } + private static IEnumerable Repeat(Func func, int times = 3) { for (int i = 0; i < times; i++) diff --git a/tests/AutoFilterer.Tests/Environment/Dtos/PreferencesFilter_ArraySearchWithoutAttribute_Guid.cs b/tests/AutoFilterer.Tests/Environment/Dtos/PreferencesFilter_ArraySearchWithoutAttribute_Guid.cs new file mode 100644 index 0000000..f32bc82 --- /dev/null +++ b/tests/AutoFilterer.Tests/Environment/Dtos/PreferencesFilter_ArraySearchWithoutAttribute_Guid.cs @@ -0,0 +1,10 @@ +using AutoFilterer.Attributes; +using AutoFilterer.Types; +using System; + +namespace AutoFilterer.Tests.Environment.Dtos; + +public class PreferencesFilter_ArraySearchWithoutAttribute_Guid : FilterBase +{ + public Guid[] OrganizationUnitId { get; set; } +} \ No newline at end of file diff --git a/tests/AutoFilterer.Tests/Environment/Models/Preferences.cs b/tests/AutoFilterer.Tests/Environment/Models/Preferences.cs index d9382bf..4a6bd50 100644 --- a/tests/AutoFilterer.Tests/Environment/Models/Preferences.cs +++ b/tests/AutoFilterer.Tests/Environment/Models/Preferences.cs @@ -1,4 +1,5 @@ -using System; +using AutoFilterer.Attributes; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -13,4 +14,7 @@ public class Preferences public string GivenName { get; set; } public int SecurityLevel { get; set; } public int? ReadLimit { get; set; } + + [ArraySearchFilter] + public Guid? OrganizationUnitId { get; set; } } From 6989f47af5a26b3fdc7ba04206328a279b74c612 Mon Sep 17 00:00:00 2001 From: Enis Necipoglu Date: Fri, 24 Oct 2025 19:51:57 +0300 Subject: [PATCH 2/2] Update tests/AutoFilterer.Tests/Attributes/ArraySearchAttributeTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- tests/AutoFilterer.Tests/Attributes/ArraySearchAttributeTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/AutoFilterer.Tests/Attributes/ArraySearchAttributeTests.cs b/tests/AutoFilterer.Tests/Attributes/ArraySearchAttributeTests.cs index 4fb9088..3324e30 100644 --- a/tests/AutoFilterer.Tests/Attributes/ArraySearchAttributeTests.cs +++ b/tests/AutoFilterer.Tests/Attributes/ArraySearchAttributeTests.cs @@ -3,7 +3,6 @@ using AutoFilterer.Tests.Environment.Dtos; using AutoFilterer.Tests.Environment.Models; using System; -using System; using System.Collections.Generic; using System.Linq; using Xunit;