Skip to content

Commit d34f3d3

Browse files
committed
CSHARP-5730: Added support for Compare with ignoreCase overloads.
1 parent 3852a30 commit d34f3d3

File tree

7 files changed

+464
-162
lines changed

7 files changed

+464
-162
lines changed

src/MongoDB.Driver/Linq/Linq3Implementation/Misc/MethodInfoExtensions.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@ public static bool Is(this MethodInfo method, MethodInfo comparand)
3838
return false;
3939
}
4040

41+
public static bool IsInstanceCompareToMethod(this MethodInfo method)
42+
{
43+
return
44+
method.IsPublic &&
45+
!method.IsStatic &&
46+
method.ReturnType == typeof(int) &&
47+
method.Name == "CompareTo" &&
48+
method.GetParameters() is var parameters &&
49+
parameters.Length == 1 &&
50+
parameters[0].ParameterType is var parameterType &&
51+
(parameterType == method.DeclaringType || parameterType == typeof(object));
52+
}
53+
4154
public static bool IsOneOf(this MethodInfo method, MethodInfo comparand1, MethodInfo comparand2)
4255
{
4356
return method.Is(comparand1) || method.Is(comparand2);
@@ -78,5 +91,18 @@ public static bool IsOneOf(this MethodInfo method, params MethodInfo[][] compara
7891

7992
return false;
8093
}
94+
95+
public static bool IsStaticCompareMethod(this MethodInfo method)
96+
{
97+
return
98+
method.IsPublic &&
99+
method.IsStatic &&
100+
method.ReturnType == typeof(int) &&
101+
method.Name == "Compare" &&
102+
method.GetParameters() is var parameters &&
103+
parameters.Length == 2 &&
104+
parameters[0].ParameterType == method.DeclaringType &&
105+
parameters[1].ParameterType == method.DeclaringType;
106+
}
81107
}
82108
}

src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/StringMethod.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ internal static class StringMethod
7373
private static readonly MethodInfo __startsWithWithStringAndComparisonType;
7474
private static readonly MethodInfo __startsWithWithStringAndIgnoreCaseAndCulture;
7575
private static readonly MethodInfo __staticCompare;
76+
private static readonly MethodInfo __staticCompareWithIgnoreCase;
7677
private static readonly MethodInfo __stringInWithEnumerable;
7778
private static readonly MethodInfo __stringInWithParams;
7879
private static readonly MethodInfo __stringNinWithEnumerable;
@@ -153,6 +154,7 @@ static StringMethod()
153154
__startsWithWithStringAndComparisonType = ReflectionInfo.Method((string s, string value, StringComparison comparisonType) => s.StartsWith(value, comparisonType));
154155
__startsWithWithStringAndIgnoreCaseAndCulture = ReflectionInfo.Method((string s, string value, bool ignoreCase, CultureInfo culture) => s.StartsWith(value, ignoreCase, culture));
155156
__staticCompare = ReflectionInfo.Method((string strA, string strB) => String.Compare(strA, strB));
157+
__staticCompareWithIgnoreCase = ReflectionInfo.Method((string strA, string strB, bool ignoreCase) => String.Compare(strA, strB, ignoreCase));
156158
__stringInWithEnumerable = ReflectionInfo.Method((string s, IEnumerable<StringOrRegularExpression> values) => s.StringIn(values));
157159
__stringInWithParams = ReflectionInfo.Method((string s, StringOrRegularExpression[] values) => s.StringIn(values));
158160
__stringNinWithEnumerable = ReflectionInfo.Method((string s, IEnumerable<StringOrRegularExpression> values) => s.StringNin(values));
@@ -223,6 +225,7 @@ static StringMethod()
223225
public static MethodInfo StartsWithWithStringAndComparisonType => __startsWithWithStringAndComparisonType;
224226
public static MethodInfo StartsWithWithStringAndIgnoreCaseAndCulture => __startsWithWithStringAndIgnoreCaseAndCulture;
225227
public static MethodInfo StaticCompare => __staticCompare;
228+
public static MethodInfo StaticCompareWithIgnoreCase => __staticCompareWithIgnoreCase;
226229
public static MethodInfo StringInWithEnumerable => __stringInWithEnumerable;
227230
public static MethodInfo StringInWithParams => __stringInWithParams;
228231
public static MethodInfo StringNinWithEnumerable => __stringNinWithEnumerable;

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodCallExpressionToAggregationExpressionTranslator.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC
3333
case "AsQueryable": return AsQueryableMethodToAggregationExpressionTranslator.Translate(context, expression);
3434
case "Average": return AverageMethodToAggregationExpressionTranslator.Translate(context, expression);
3535
case "Ceiling": return CeilingMethodToAggregationExpressionTranslator.Translate(context, expression);
36-
case "Compare": return CompareMethodToAggregationExpressionTranslator.Translate(context, expression);
37-
case "CompareTo": return CompareToMethodToAggregationExpressionTranslator.Translate(context, expression);
3836
case "Concat": return ConcatMethodToAggregationExpressionTranslator.Translate(context, expression);
3937
case "Constant": return ConstantMethodToAggregationExpressionTranslator.Translate(context, expression);
4038
case "Contains": return ContainsMethodToAggregationExpressionTranslator.Translate(context, expression);
@@ -139,6 +137,10 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC
139137
case "TopN":
140138
return PickMethodToAggregationExpressionTranslator.Translate(context, expression);
141139

140+
case "Compare":
141+
case "CompareTo":
142+
return CompareMethodToAggregationExpressionTranslator.Translate(context, expression);
143+
142144
case "Count":
143145
case "LongCount":
144146
return CountMethodToAggregationExpressionTranslator.Translate(context, expression);

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/CompareMethodToAggregationExpressionTranslator.cs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,58 @@
1414
*/
1515

1616
using System.Linq.Expressions;
17+
using System.Reflection;
1718
using MongoDB.Bson.Serialization.Serializers;
1819
using MongoDB.Driver.Linq.Linq3Implementation.Ast.Expressions;
20+
using MongoDB.Driver.Linq.Linq3Implementation.ExtensionMethods;
1921
using MongoDB.Driver.Linq.Linq3Implementation.Misc;
2022

2123
namespace MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodTranslators
2224
{
2325
internal static class CompareMethodToAggregationExpressionTranslator
2426
{
27+
private static readonly MethodInfo[] __stringCompareMethods =
28+
[
29+
StringMethod.StaticCompare,
30+
StringMethod.StaticCompareWithIgnoreCase
31+
];
32+
2533
public static TranslatedExpression Translate(TranslationContext context, MethodCallExpression expression)
2634
{
2735
var method = expression.Method;
2836
var arguments = expression.Arguments;
2937

30-
if (method.Is(StringMethod.StaticCompare))
38+
if (method.IsStaticCompareMethod() || method.IsInstanceCompareToMethod() || method.IsOneOf(__stringCompareMethods))
3139
{
32-
var strAExpression = arguments[0];
33-
var strBExpression = arguments[1];
40+
Expression value1Expression;
41+
Expression value2Expression;
42+
if (method.IsStatic)
43+
{
44+
value1Expression = arguments[0];
45+
value2Expression = arguments[1];
46+
}
47+
else
48+
{
49+
value1Expression = expression.Object;
50+
value2Expression = arguments[0];
51+
}
3452

35-
var strATranslation = ExpressionToAggregationExpressionTranslator.Translate(context, strAExpression);
36-
var strBTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, strBExpression);
53+
var value1Translation = ExpressionToAggregationExpressionTranslator.Translate(context, value1Expression);
54+
var value2Translation = ExpressionToAggregationExpressionTranslator.Translate(context, value2Expression);
3755

38-
var ast = AstExpression.Cmp(strATranslation.Ast, strBTranslation.Ast);
56+
AstExpression ast;
57+
if (method.Is(StringMethod.StaticCompareWithIgnoreCase))
58+
{
59+
var ignoreCaseExpression = arguments[2];
60+
var ignoreCase = ignoreCaseExpression.GetConstantValue<bool>(containingExpression: expression);
61+
ast = ignoreCase
62+
? AstExpression.StrCaseCmp(value1Translation.Ast, value2Translation.Ast)
63+
: AstExpression.Cmp(value1Translation.Ast, value2Translation.Ast);
64+
}
65+
else
66+
{
67+
ast = AstExpression.Cmp(value1Translation.Ast, value2Translation.Ast);
68+
}
3969

4070
return new TranslatedExpression(expression, ast, Int32Serializer.Instance);
4171
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/CompareToMethodToAggregationExpressionTranslator.cs

Lines changed: 0 additions & 43 deletions
This file was deleted.

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/CompareComparisonExpressionToFilterTranslator.cs

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public static bool CanTranslate(Expression leftExpression)
2929
return
3030
leftExpression is MethodCallExpression leftMethodCallExpression &&
3131
leftMethodCallExpression.Method is var method &&
32-
(IsStaticCompareMethod(method) || IsInstanceCompareToMethod(method));
32+
(method.IsStaticCompareMethod() || method.IsInstanceCompareToMethod() || method.Is(StringMethod.StaticCompareWithIgnoreCase));
3333
}
3434

3535
// caller is responsible for ensuring constant is on the right
@@ -60,6 +60,16 @@ public static AstFilter Translate(
6060
innerValueExpression = compareArguments[0];
6161
}
6262

63+
if (compareMethod.Is(StringMethod.StaticCompareWithIgnoreCase))
64+
{
65+
var ignoreCaseExpression = compareArguments[2];
66+
var ignoreCase = ignoreCaseExpression.GetConstantValue<bool>(containingExpression: compareMethodCallExpression);
67+
if (ignoreCase)
68+
{
69+
throw new ExpressionNotSupportedException(compareMethodCallExpression, because: "ignoreCase must be false");
70+
}
71+
}
72+
6373
var fieldComparisonOperator = (outerComparisonOperator, outerValue) switch
6474
{
6575
(AstComparisonFilterOperator.Eq, -1) => AstComparisonFilterOperator.Lt,
@@ -92,31 +102,5 @@ public static AstFilter Translate(
92102

93103
throw new ExpressionNotSupportedException(expression);
94104
}
95-
96-
private static bool IsInstanceCompareToMethod(MethodInfo method)
97-
{
98-
return
99-
method.IsPublic &&
100-
!method.IsStatic &&
101-
method.ReturnType == typeof(int) &&
102-
method.Name == "CompareTo" &&
103-
method.GetParameters() is var parameters &&
104-
parameters.Length == 1 &&
105-
parameters[0].ParameterType is var parameterType &&
106-
(parameterType == method.DeclaringType || parameterType == typeof(object));
107-
}
108-
109-
private static bool IsStaticCompareMethod(MethodInfo method)
110-
{
111-
return
112-
method.IsPublic &&
113-
method.IsStatic &&
114-
method.ReturnType == typeof(int) &&
115-
method.Name == "Compare" &&
116-
method.GetParameters() is var parameters &&
117-
parameters.Length == 2 &&
118-
parameters[0].ParameterType == method.DeclaringType &&
119-
parameters[1].ParameterType == method.DeclaringType;
120-
}
121105
}
122106
}

0 commit comments

Comments
 (0)