Skip to content

Commit 7baa925

Browse files
committed
CSHARP-4772: Add support for List<T>.Exists and Array.Exists<T> in LINQ3.
1 parent e9cb7b7 commit 7baa925

File tree

9 files changed

+397
-7
lines changed

9 files changed

+397
-7
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System;
17+
using System.Reflection;
18+
19+
namespace MongoDB.Driver.Linq.Linq3Implementation.Reflection
20+
{
21+
internal static class ArrayMethod
22+
{
23+
// private static fields
24+
private static readonly MethodInfo __exists;
25+
26+
// static constructor
27+
static ArrayMethod()
28+
{
29+
__exists = ReflectionInfo.Method((object[] array, Predicate<object> match) => Array.Exists(array, match));
30+
}
31+
32+
// public properties
33+
public static MethodInfo Exists => __exists;
34+
}
35+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System;
17+
using System.Collections.Generic;
18+
using System.Reflection;
19+
20+
namespace MongoDB.Driver.Linq.Linq3Implementation.Reflection
21+
{
22+
internal static class ListMethod
23+
{
24+
// public methods
25+
public static bool IsExistsMethod(MethodInfo method)
26+
=>
27+
method.DeclaringType is var declaringType &&
28+
declaringType.IsConstructedGenericType &&
29+
declaringType.GetGenericTypeDefinition() == typeof(List<>) &&
30+
declaringType.GetGenericArguments() is var genericArguments &&
31+
genericArguments.Length == 1 &&
32+
genericArguments[0] is var T &&
33+
method.IsPublic &&
34+
method.IsStatic == false &&
35+
method.ReturnType == typeof(bool) &&
36+
method.GetParameters() is var parameters &&
37+
parameters.Length == 1 &&
38+
parameters[0].ParameterType == typeof(Predicate<>).MakeGenericType(T);
39+
}
40+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public static AggregationExpression Translate(TranslationContext context, Method
4747
case "ElementAt": return ElementAtMethodToAggregationExpressionTranslator.Translate(context, expression);
4848
case "Equals": return EqualsMethodToAggregationExpressionTranslator.Translate(context, expression);
4949
case "Except": return ExceptMethodToAggregationExpressionTranslator.Translate(context, expression);
50+
case "Exists": return ExistsMethodToAggregationExpressionTranslator.Translate(context, expression);
5051
case "Exp": return ExpMethodToAggregationExpressionTranslator.Translate(context, expression);
5152
case "ExponentialMovingAverage": return ExponentialMovingAverageMethodToAggregationExpressionTranslator.Translate(context, expression);
5253
case "Floor": return FloorMethodToAggregationExpressionTranslator.Translate(context, expression);

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public static AggregationExpression Translate(TranslationContext context, Method
2828
var method = expression.Method;
2929
var arguments = expression.Arguments;
3030

31-
var sourceExpression = arguments[0];
31+
var sourceExpression = method.IsStatic ? arguments[0] : expression.Object;
3232
var sourceTranslation = ExpressionToAggregationExpressionTranslator.TranslateEnumerable(context, sourceExpression);
3333

3434
if (method.Is(EnumerableMethod.Any))
@@ -37,9 +37,9 @@ public static AggregationExpression Translate(TranslationContext context, Method
3737
return new AggregationExpression(expression, ast, new BooleanSerializer());
3838
}
3939

40-
if (method.Is(EnumerableMethod.AnyWithPredicate))
40+
if (method.IsOneOf(EnumerableMethod.AnyWithPredicate, ArrayMethod.Exists) || ListMethod.IsExistsMethod(method))
4141
{
42-
var predicateLambda = (LambdaExpression)arguments[1];
42+
var predicateLambda = (LambdaExpression)(method.IsStatic ? arguments[1] : arguments[0]);
4343
var predicateParameter = predicateLambda.Parameters[0];
4444
var predicateParameterSerializer = ArraySerializerHelper.GetItemSerializer(sourceTranslation.Serializer);
4545
var predicateSymbol = context.CreateSymbol(predicateParameter, predicateParameterSerializer);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System.Linq.Expressions;
17+
using MongoDB.Driver.Linq.Linq3Implementation.Misc;
18+
using MongoDB.Driver.Linq.Linq3Implementation.Reflection;
19+
20+
namespace MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodTranslators
21+
{
22+
internal static class ExistsMethodToAggregationExpressionTranslator
23+
{
24+
public static AggregationExpression Translate(TranslationContext context, MethodCallExpression expression)
25+
{
26+
var method = expression.Method;
27+
28+
if (method.Is(ArrayMethod.Exists) || ListMethod.IsExistsMethod(expression.Method))
29+
{
30+
return AnyMethodToAggregationExpressionTranslator.Translate(context, expression);
31+
}
32+
33+
throw new ExpressionNotSupportedException(expression);
34+
}
35+
}
36+
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/AllOrAnyMethodToFilterTranslator.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@ public static AstFilter Translate(TranslationContext context, MethodCallExpressi
4343
var method = expression.Method;
4444
var arguments = expression.Arguments;
4545

46-
if (method.IsOneOf(EnumerableMethod.All, EnumerableMethod.Any, EnumerableMethod.AnyWithPredicate))
46+
if (method.IsOneOf(EnumerableMethod.All, EnumerableMethod.Any, EnumerableMethod.AnyWithPredicate, ArrayMethod.Exists) || ListMethod.IsExistsMethod(method))
4747
{
48-
var sourceExpression = arguments[0];
48+
var sourceExpression = method.IsStatic ? arguments[0] : expression.Object;
4949
var (field, filter) = FilteredEnumerableFilterFieldTranslator.Translate(context, sourceExpression);
5050

51-
if (method.IsOneOf(EnumerableMethod.All, EnumerableMethod.AnyWithPredicate))
51+
if (method.IsOneOf(EnumerableMethod.All, EnumerableMethod.AnyWithPredicate, ArrayMethod.Exists) || ListMethod.IsExistsMethod(method))
5252
{
53-
var predicateLambda = (LambdaExpression)arguments[1];
53+
var predicateLambda = (LambdaExpression)(method.IsStatic ? arguments[1] : arguments[0]);
5454
var parameterExpression = predicateLambda.Parameters.Single();
5555
var elementSerializer = ArraySerializerHelper.GetItemSerializer(field.Serializer);
5656
var parameterSymbol = context.CreateSymbol(parameterExpression, "@<elem>", elementSerializer); // @<elem> represents the implied element
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System.Linq.Expressions;
17+
using MongoDB.Driver.Linq.Linq3Implementation.Ast.Filters;
18+
using MongoDB.Driver.Linq.Linq3Implementation.Misc;
19+
using MongoDB.Driver.Linq.Linq3Implementation.Reflection;
20+
21+
namespace MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToFilterTranslators.MethodTranslators
22+
{
23+
internal static class ExistsMethodToFilterTranslator
24+
{
25+
public static AstFilter Translate(TranslationContext context, MethodCallExpression expression)
26+
{
27+
var method = expression.Method;
28+
29+
if (method.Is(ArrayMethod.Exists) || ListMethod.IsExistsMethod(method))
30+
{
31+
return AllOrAnyMethodToFilterTranslator.Translate(context, expression);
32+
}
33+
34+
throw new ExpressionNotSupportedException(expression);
35+
}
36+
}
37+
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/MethodCallExpressionToFilterTranslator.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public static AstFilter Translate(TranslationContext context, MethodCallExpressi
2828
case "ContainsKey": return ContainsKeyMethodToFilterTranslator.Translate(context, expression);
2929
case "EndsWith": return EndsWithMethodToFilterTranslator.Translate(context, expression);
3030
case "Equals": return EqualsMethodToFilterTranslator.Translate(context, expression);
31+
case "Exists": return ExistsMethodToFilterTranslator.Translate(context, expression);
3132
case "HasFlag": return HasFlagMethodToFilterTranslator.Translate(context, expression);
3233
case "Inject": return InjectMethodToFilterTranslator.Translate(context, expression);
3334
case "IsMatch": return IsMatchMethodToFilterTranslator.Translate(context, expression);

0 commit comments

Comments
 (0)