Skip to content

Commit

Permalink
Revert "fix: issue 193 and case sensitivity support improvements"
Browse files Browse the repository at this point in the history
This reverts commit 132139b
  • Loading branch information
moxplod committed Aug 20, 2024
1 parent 29e63df commit b8e4086
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 132 deletions.
20 changes: 17 additions & 3 deletions src/Gridify/Builder/BaseQueryBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.ComponentModel;
using System.Linq.Expressions;
using Gridify.Reflection;
using Gridify.Syntax;

namespace Gridify.Builder;
Expand Down Expand Up @@ -123,7 +124,7 @@ public TQuery Build(ExpressionSyntax expression)
return (result, isNested);
}

var query = BuildQuery(mapTarget.Body, mapTarget.Parameters[0], right, op, gMap.Convertor);
var query = BuildQuery(mapTarget.Body, mapTarget.Parameters[0], right, op, gMap.Convertor, false);
if (query == null) return null;

if (hasIndexer)
Expand Down Expand Up @@ -157,7 +158,8 @@ private static object AddIndexerNullCheck(LambdaExpression mapTarget, object que
ParameterExpression parameter,
ValueExpressionSyntax valueExpression,
ISyntaxNode op,
Func<string, object>? convertor)
Func<string, object>? convertor,
bool isNested)
{
// Remove the boxing for value types
if (body.NodeType == ExpressionType.Convert) body = ((UnaryExpression)body).Operand;
Expand Down Expand Up @@ -197,7 +199,7 @@ private static object AddIndexerNullCheck(LambdaExpression mapTarget, object que
{
return BuildAlwaysFalseQuery(parameter);
}

if (value is DateTime dateTime)
{
if (mapper.Configuration.DefaultDateTimeKind.HasValue)
Expand All @@ -207,6 +209,18 @@ private static object AddIndexerNullCheck(LambdaExpression mapTarget, object que
}
}

// handle case-Insensitive search
if (value is not null && (valueExpression.IsCaseInsensitive
|| (mapper.Configuration.CaseInsensitiveFiltering && !isNested && body.Type == typeof(string)))
&& op.Kind is not SyntaxKind.GreaterThan
&& op.Kind is not SyntaxKind.LessThan
&& op.Kind is not SyntaxKind.GreaterOrEqualThan
&& op.Kind is not SyntaxKind.LessOrEqualThan)
{
value = value.ToString()?.ToLower();
body = Expression.Call(body, MethodInfoHelper.GetToLowerMethod());
}

var query = BuildQueryAccordingToValueType(body, parameter, value, op, valueExpression);
return query;
}
Expand Down
67 changes: 13 additions & 54 deletions src/Gridify/Builder/LinqQueryBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using Gridify.Reflection;
Expand All @@ -25,7 +23,8 @@ public class LinqQueryBuilder<T>(IGridifyMapper<T> mapper) : BaseQueryBuilder<Ex
targetExp.Parameters[0],
value,
op,
gMap.Convertor);
gMap.Convertor,
true);

if (conditionExp is not LambdaExpression lambdaExp) return null;

Expand Down Expand Up @@ -117,15 +116,6 @@ protected override Expression<Func<T, bool>> BuildAlwaysFalseQuery(ParameterExpr

switch (op.Kind)
{
case SyntaxKind.Equal when !valueExpression.IsNullOrDefault && areBothStrings && (valueExpression.IsCaseInsensitive || mapper.Configuration.CaseInsensitiveFiltering):
be = Expression.Call(
null,
MethodInfoHelper.GetCaseAwareEqualsMethod(),
body,
GetValueExpression(body.Type, value),
Expression.Constant(StringComparison.OrdinalIgnoreCase)
);
break;
case SyntaxKind.Equal when !valueExpression.IsNullOrDefault:
be = Expression.Equal(body, GetValueExpression(body.Type, value));
break;
Expand All @@ -142,15 +132,6 @@ protected override Expression<Func<T, bool>> BuildAlwaysFalseQuery(ParameterExpr
: Expression.Equal(body, Expression.Default(body.Type));
}

break;
case SyntaxKind.NotEqual when !valueExpression.IsNullOrDefault && areBothStrings && (valueExpression.IsCaseInsensitive || mapper.Configuration.CaseInsensitiveFiltering):
be = Expression.Not(Expression.Call(
null,
MethodInfoHelper.GetCaseAwareEqualsMethod(),
body,
GetValueExpression(body.Type, value),
Expression.Constant(StringComparison.OrdinalIgnoreCase))
);
break;
case SyntaxKind.NotEqual when !valueExpression.IsNullOrDefault:
be = Expression.NotEqual(body, GetValueExpression(body.Type, value));
Expand Down Expand Up @@ -194,7 +175,7 @@ protected override Expression<Func<T, bool>> BuildAlwaysFalseQuery(ParameterExpr
case SyntaxKind.LessOrEqualThan when areBothStrings:
be = GetLessThanOrEqualExpression(body, valueExpression, value);
break;
case SyntaxKind.Like: // TODO: test and support case sensitivity
case SyntaxKind.Like:
be = Expression.Call(body, MethodInfoHelper.GetStringContainsMethod(), GetValueExpression(body.Type, value));
break;
case SyntaxKind.NotLike:
Expand Down Expand Up @@ -285,7 +266,7 @@ protected override Expression<Func<T, bool>> CombineWithOrOperator(Expression<Fu
case MethodCallExpression { Method.Name: "Select" } selectExp:
{
var targetExp = selectExp.Arguments.Single(a => a.NodeType == ExpressionType.Lambda) as LambdaExpression;
var conditionExp = BuildQuery(targetExp!.Body, targetExp.Parameters[0], value, op, gMap.Convertor);
var conditionExp = BuildQuery(targetExp!.Body, targetExp.Parameters[0], value, op, gMap.Convertor, true);

if (conditionExp is not LambdaExpression lambdaExp) return null;

Expand Down Expand Up @@ -322,14 +303,14 @@ private static LambdaExpression ParseMethodCallExpression(MethodCallExpression e
{
case MemberExpression member:
{
if (op.Kind is not (SyntaxKind.Equal or SyntaxKind.NotEqual) ||
!member.Type.IsSimpleTypeCollection(out _)) return GetAnyExpression(member, predicate);
return predicate.Body switch
if (op.Kind is SyntaxKind.Equal or SyntaxKind.NotEqual &&
member.Type.IsSimpleTypeCollection(out _) &&
predicate.Body is BinaryExpression binaryExpression)
{
BinaryExpression binaryExpression => GetContainsExpression(member, binaryExpression, op),
MethodCallExpression { Method.Name: "Equals" } methodCallExpression => GetCaseSensitiveContainsExpression(member, methodCallExpression, op),
_ => GetAnyExpression(member, predicate)
};
return GetContainsExpression(member, binaryExpression, op);
}

return GetAnyExpression(member, predicate);
}
case MethodCallExpression { Method.Name: "SelectMany" } subExp
when subExp.Arguments.Last()
Expand Down Expand Up @@ -368,28 +349,6 @@ when subExp.Arguments.Last() is LambdaExpression wherePredicate &&
}
}

private static LambdaExpression GetCaseSensitiveContainsExpression(MemberExpression member, MethodCallExpression methodCallExpression, ISyntaxNode op)
{
var param = GetParameterExpression(member);
var prop = GetPropertyOrField(member, param);

var tp = prop.Type.IsGenericType
? prop.Type.GenericTypeArguments.First() // list
: prop.Type.GetElementType(); // array

if (tp == null) throw new GridifyFilteringException($"Can not detect the '{member.Member.Name}' property type.");

var containsMethod = MethodInfoHelper.GetCaseAwareContainsMethod(tp);
var ignoreCaseComparerExpression = Expression.Constant(StringComparer.InvariantCultureIgnoreCase);
var value = methodCallExpression.Arguments[1];
Expression containsExp = Expression.Call(containsMethod, prop, value, ignoreCaseComparerExpression);
if (op.Kind == SyntaxKind.NotEqual)
{
containsExp = Expression.Not(containsExp);
}
return GetExpressionWithNullCheck(prop, param, containsExp);
}

private static LambdaExpression GetContainsExpression(MemberExpression member, BinaryExpression binaryExpression, ISyntaxNode op)
{
var param = GetParameterExpression(member);
Expand Down Expand Up @@ -516,9 +475,9 @@ private BinaryExpression GetGreaterThanExpression(Expression body, ValueExpressi
GetStringComparisonCaseExpression(valueExpression.IsCaseInsensitive)), Expression.Constant(0));
}

private static ConstantExpression GetStringComparisonCaseExpression(bool isCaseInsensitive)
private ConstantExpression GetStringComparisonCaseExpression(bool isCaseInsensitive)
{
return isCaseInsensitive
return isCaseInsensitive || mapper.Configuration.CaseInsensitiveFiltering
? Expression.Constant(StringComparison.OrdinalIgnoreCase)
: Expression.Constant(StringComparison.Ordinal);
}
Expand Down
15 changes: 5 additions & 10 deletions src/Gridify/Reflection/MethodInfoHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ namespace Gridify.Reflection;

public static class MethodInfoHelper
{
public static MethodInfo GetToLowerMethod()
{
return typeof(string).GetMethod("ToLower", [])!;
}

public static MethodInfo GetAnyMethod(Type type)
{
return typeof(Enumerable).GetMethods().Single(m => m.Name == "Any" && m.GetParameters().Length == 2).MakeGenericMethod(type);
Expand Down Expand Up @@ -55,14 +60,4 @@ public static MethodInfo GetSelectMethod(this Type type)
{
return typeof(Enumerable).GetMethods().First(m => m.Name == "Select").MakeGenericMethod([type, type]);
}

public static MethodInfo GetCaseAwareContainsMethod(Type tp)
{
return typeof(Enumerable).GetMethods().Last(x => x.Name == "Contains").MakeGenericMethod(tp);
}

public static MethodInfo GetCaseAwareEqualsMethod()
{
return typeof(string).GetMethod("Equals", [typeof(string), typeof(string), typeof(StringComparison)])!;
}
}
65 changes: 0 additions & 65 deletions test/EntityFrameworkPostgreSqlIntegrationTests/Issue193Tests.cs

This file was deleted.

0 comments on commit b8e4086

Please sign in to comment.