Skip to content

Commit 36a30dd

Browse files
authored
feat(Filter): add StringComparison parameter (#7449)
* refactor: 重构代码 * refactor: 增加忽略大小写参数 * refactor: add StringComparison parameter * test: 更新单元测试 * test: 增加单元测试 * chore: bump version 10.2.1-beta01
1 parent a30224f commit 36a30dd

File tree

5 files changed

+69
-37
lines changed

5 files changed

+69
-37
lines changed

src/BootstrapBlazor/BootstrapBlazor.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Razor">
22

33
<PropertyGroup>
4-
<Version>10.2.0</Version>
4+
<Version>10.2.1-beta01</Version>
55
</PropertyGroup>
66

77
<ItemGroup>

src/BootstrapBlazor/Extensions/LambdaExtensions.cs

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -34,27 +34,27 @@ private class ComboExpressionVisitor(ParameterExpression parameter) : Expression
3434
/// </summary>
3535
/// <typeparam name="TItem"></typeparam>
3636
/// <param name="filter"></param>
37-
/// <returns></returns>
38-
public static Func<TItem, bool> GetFilterFunc<TItem>(this FilterKeyValueAction filter) => filter.GetFilterLambda<TItem>().Compile();
37+
/// <param name="comparison"><see cref="StringComparison"/> 实例,此方法不支持 EFCore Where 查询</param>
38+
public static Func<TItem, bool> GetFilterFunc<TItem>(this FilterKeyValueAction filter, StringComparison? comparison = null) => filter.GetFilterLambda<TItem>(comparison).Compile();
3939

4040
/// <summary>
4141
/// 指定 FilterKeyValueAction 获取 Lambda 表达式
4242
/// </summary>
4343
/// <typeparam name="TItem"></typeparam>
4444
/// <param name="filter"></param>
45-
/// <returns></returns>
46-
public static Expression<Func<TItem, bool>> GetFilterLambda<TItem>(this FilterKeyValueAction filter)
45+
/// <param name="comparison"><see cref="StringComparison"/> 实例,此方法不支持 EFCore Where 查询</param>
46+
public static Expression<Func<TItem, bool>> GetFilterLambda<TItem>(this FilterKeyValueAction filter, StringComparison? comparison = null)
4747
{
4848
var express = new List<Expression<Func<TItem, bool>>>();
4949
if (filter.Filters.Count > 0)
5050
{
5151
express.AddRange(filter.Filters.Select(f => f.Filters.Count > 0
52-
? f.Filters.GetFilterLambda<TItem>(f.FilterLogic)
53-
: f.GetInnerFilterLambda<TItem>()));
52+
? f.Filters.GetFilterLambda<TItem>(f.FilterLogic, comparison)
53+
: f.GetInnerFilterLambda<TItem>(comparison)));
5454
}
5555
else
5656
{
57-
express.Add(filter.GetInnerFilterLambda<TItem>());
57+
express.Add(filter.GetInnerFilterLambda<TItem>(comparison));
5858
}
5959
return express.ExpressionAndLambda(filter.FilterLogic);
6060
}
@@ -83,12 +83,13 @@ public static Expression<Func<TItem, bool>> GetFilterLambda<TItem>(this FilterKe
8383
/// <typeparam name="TItem"></typeparam>
8484
/// <param name="filters"></param>
8585
/// <param name="logic"></param>
86+
/// <param name="comparison"><see cref="StringComparison"/> 实例</param>
8687
/// <returns></returns>
87-
private static Expression<Func<TItem, bool>> GetFilterLambda<TItem>(this IEnumerable<FilterKeyValueAction> filters, FilterLogic logic)
88+
private static Expression<Func<TItem, bool>> GetFilterLambda<TItem>(this IEnumerable<FilterKeyValueAction> filters, FilterLogic logic, StringComparison? comparison = null)
8889
{
8990
var express = filters.Select(filter => filter.Filters.Count > 0
90-
? filter.Filters.GetFilterLambda<TItem>(filter.FilterLogic)
91-
: filter.GetInnerFilterLambda<TItem>())
91+
? filter.Filters.GetFilterLambda<TItem>(filter.FilterLogic, comparison)
92+
: filter.GetInnerFilterLambda<TItem>(comparison))
9293
.ToList();
9394
return express.ExpressionAndLambda(logic);
9495
}
@@ -126,13 +127,7 @@ private static Expression<Func<TItem, bool>> ExpressionAndLambda<TItem>(this IEn
126127
return ret ?? (r => true);
127128
}
128129

129-
/// <summary>
130-
/// 指定 FilterKeyValueAction 获取 Lambda 表达式
131-
/// </summary>
132-
/// <typeparam name="TItem"></typeparam>
133-
/// <param name="filter"></param>
134-
/// <returns></returns>
135-
private static Expression<Func<TItem, bool>> GetInnerFilterLambda<TItem>(this FilterKeyValueAction filter)
130+
private static Expression<Func<TItem, bool>> GetInnerFilterLambda<TItem>(this FilterKeyValueAction filter, StringComparison? comparison = null)
136131
{
137132
Expression<Func<TItem, bool>> ret = t => true;
138133
var type = typeof(TItem);
@@ -148,7 +143,7 @@ Expression<Func<TItem, bool>> GetSimpleFilterExpression()
148143
var prop = typeof(TItem).GetPropertyByName(filter.FieldKey) ?? throw new InvalidOperationException($"the model {type.Name} not found the property {filter.FieldKey}");
149144
var parameter = Expression.Parameter(type);
150145
var fieldExpression = Expression.Property(parameter, prop);
151-
ret = filter.GetFilterExpression<TItem>(prop, fieldExpression, parameter);
146+
ret = filter.GetFilterExpression<TItem>(prop, fieldExpression, parameter, comparison);
152147
return ret;
153148
}
154149

@@ -175,13 +170,13 @@ Expression<Func<TItem, bool>> GetComplexFilterExpression()
175170

176171
if (fieldExpression != null)
177172
{
178-
ret = filter.GetFilterExpression<TItem>(prop, fieldExpression, parameter);
173+
ret = filter.GetFilterExpression<TItem>(prop, fieldExpression, parameter, comparison);
179174
}
180175
return ret;
181176
}
182177
}
183178

184-
private static Expression<Func<TItem, bool>> GetFilterExpression<TItem>(this FilterKeyValueAction filter, PropertyInfo? prop, Expression fieldExpression, ParameterExpression parameter)
179+
private static Expression<Func<TItem, bool>> GetFilterExpression<TItem>(this FilterKeyValueAction filter, PropertyInfo? prop, Expression fieldExpression, ParameterExpression parameter, StringComparison? comparison = null)
185180
{
186181
var isNullable = false;
187182
var eq = fieldExpression;
@@ -201,12 +196,12 @@ private static Expression<Func<TItem, bool>> GetFilterExpression<TItem>(this Fil
201196
}
202197
}
203198
eq = isNullable
204-
? Expression.AndAlso(Expression.NotEqual(fieldExpression, Expression.Constant(null)), filter.GetExpression(eq))
205-
: filter.GetExpression(eq);
199+
? Expression.AndAlso(Expression.NotEqual(fieldExpression, Expression.Constant(null)), filter.GetExpression(eq, comparison))
200+
: filter.GetExpression(eq, comparison);
206201
return Expression.Lambda<Func<TItem, bool>>(eq, parameter);
207202
}
208203

209-
private static Expression GetExpression(this FilterKeyValueAction filter, Expression left)
204+
private static Expression GetExpression(this FilterKeyValueAction filter, Expression left, StringComparison? comparison = null)
210205
{
211206
var right = Expression.Constant(filter.FieldValue);
212207
return filter.FilterAction switch
@@ -217,8 +212,8 @@ private static Expression GetExpression(this FilterKeyValueAction filter, Expres
217212
FilterAction.GreaterThanOrEqual => Expression.GreaterThanOrEqual(left, right),
218213
FilterAction.LessThan => Expression.LessThan(left, right),
219214
FilterAction.LessThanOrEqual => Expression.LessThanOrEqual(left, right),
220-
FilterAction.Contains => left.Contains(right),
221-
FilterAction.NotContains => Expression.Not(left.Contains(right)),
215+
FilterAction.Contains => left.Contains(right, comparison),
216+
FilterAction.NotContains => Expression.Not(left.Contains(right, comparison)),
222217
_ => filter.FieldValue switch
223218
{
224219
LambdaExpression t => Expression.Invoke(t, left),
@@ -228,12 +223,23 @@ private static Expression GetExpression(this FilterKeyValueAction filter, Expres
228223
};
229224
}
230225

231-
private static BinaryExpression Contains(this Expression left, Expression right)
226+
private static BinaryExpression Contains(this Expression left, Expression right, StringComparison? comparison) => comparison.HasValue
227+
? ContainsWidthComparison(left, right, comparison.Value)
228+
: ContainsWithoutComparison(left, right);
229+
230+
private static BinaryExpression ContainsWithoutComparison(this Expression left, Expression right)
232231
{
233232
var method = typeof(string).GetMethod("Contains", [typeof(string)])!;
234233
return Expression.AndAlso(Expression.NotEqual(left, Expression.Constant(null)), Expression.Call(left, method, right));
235234
}
236235

236+
private static BinaryExpression ContainsWidthComparison(this Expression left, Expression right, StringComparison comparison)
237+
{
238+
var method = typeof(string).GetMethod("Contains", [typeof(string), typeof(StringComparison)])!;
239+
var comparisonConstant = Expression.Constant(comparison);
240+
return Expression.AndAlso(Expression.NotEqual(left, Expression.Constant(null)), Expression.Call(left, method, right, comparisonConstant));
241+
}
242+
237243
#region Count
238244
/// <summary>
239245
/// Count 方法内部使用 Lambda 表达式做通用适配 可接受 IEnumerable 与 Array 子类

src/BootstrapBlazor/Extensions/QueryPageOptionsExtensions.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Licensed to the .NET Foundation under one or more agreements.
1+
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the Apache 2.0 License
33
// See the LICENSE file in the project root for more information.
44
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone
@@ -56,15 +56,17 @@ public static FilterKeyValueAction ToFilter(this QueryPageOptions option)
5656
/// 将 QueryPageOptions 过滤条件转换为 where 条件中的参数 <see cref="Func{T, TResult}"/>"/> 推荐 Linq 使用
5757
/// </summary>
5858
/// <param name="option"></param>
59+
/// <param name="comparison"><see cref="StringComparison"/> 实例,此方法不支持 EFCore Where 查询</param>
5960
/// <returns></returns>
60-
public static Func<TItem, bool> ToFilterFunc<TItem>(this QueryPageOptions option) => option.ToFilterLambda<TItem>().Compile();
61+
public static Func<TItem, bool> ToFilterFunc<TItem>(this QueryPageOptions option, StringComparison? comparison = null) => option.ToFilterLambda<TItem>(comparison).Compile();
6162

6263
/// <summary>
6364
/// 将 QueryPageOptions 过滤条件转换为 <see cref="Expression{TDelegate}"/> 表达式"/> 推荐 EFCore <see cref="IQueryable"/> 使用
6465
/// </summary>
6566
/// <param name="option"></param>
67+
/// <param name="comparison"><see cref="StringComparison"/> 实例,此方法不支持 EFCore Where 查询</param>
6668
/// <returns></returns>
67-
public static Expression<Func<TItem, bool>> ToFilterLambda<TItem>(this QueryPageOptions option) => option.ToFilter().GetFilterLambda<TItem>();
69+
public static Expression<Func<TItem, bool>> ToFilterLambda<TItem>(this QueryPageOptions option, StringComparison? comparison = null) => option.ToFilter().GetFilterLambda<TItem>(comparison);
6870

6971
/// <summary>
7072
/// 是否包含过滤条件

test/UnitTest/Extensions/LambadaExtensionsTest.cs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,30 @@ namespace UnitTest.Extensions;
1212

1313
public class LambadaExtensionsTest : BootstrapBlazorTestBase
1414
{
15+
[Fact]
16+
public void GetFilterFunc_Comparison()
17+
{
18+
var filter = new FilterKeyValueAction()
19+
{
20+
FieldKey = "Name",
21+
FilterAction = FilterAction.Contains,
22+
FieldValue = "T"
23+
};
24+
25+
var foos = new Foo[]
26+
{
27+
new() { Name = "Test1" },
28+
new() { Name = "test2" },
29+
};
30+
31+
var items = foos.Where(filter.GetFilterFunc<Foo>());
32+
Assert.Single(items);
33+
34+
// 忽略大小写
35+
items = foos.Where(filter.GetFilterFunc<Foo>(StringComparison.OrdinalIgnoreCase));
36+
Assert.Equal(2, items.Count());
37+
}
38+
1539
[Fact]
1640
public void GetFilterFunc_Null()
1741
{
@@ -694,11 +718,6 @@ public override FilterKeyValueAction GetFilterConditions()
694718
}
695719
}
696720

697-
/// <summary>
698-
///
699-
/// </summary>
700-
/// <param name="fix"></param>
701-
/// <param name="data"></param>
702721
private class CustomDynamicData(Dictionary<string, string> data) : System.Dynamic.DynamicObject
703722
{
704723
/// <summary>
@@ -719,9 +738,9 @@ public CustomDynamicData() : this([]) { }
719738
/// <returns></returns>
720739
public override bool TryGetMember(GetMemberBinder binder, out object? result)
721740
{
722-
if (Dynamic.ContainsKey(binder.Name))
741+
if (Dynamic.TryGetValue(binder.Name, out string? value))
723742
{
724-
result = Dynamic[binder.Name];
743+
result = value;
725744
}
726745
else
727746
{

test/UnitTest/Extensions/QueryPageOptionsExtensionsTest.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ public void ToFilter_Searches()
3939
expected = _foos.Where(predicate);
4040
Assert.Equal(2, expected.Count());
4141

42+
// 忽略大小写
43+
predicate = option.ToFilterFunc<Foo>(StringComparison.OrdinalIgnoreCase);
44+
expected = _foos.Where(predicate);
45+
Assert.Equal(4, expected.Count());
46+
4247
option.Searches.Clear();
4348
option.Searches.Add(new SearchFilterAction("Name", "Mock"));
4449
predicate = option.ToFilterFunc<Foo>();

0 commit comments

Comments
 (0)