Skip to content

Commit c1e3424

Browse files
committed
CSHARP-4803: Refactor StringExpressionToRegexFilterTranslator.TryTranslate to not use an exception for flow control when possible.
1 parent adc68c8 commit c1e3424

File tree

2 files changed

+118
-34
lines changed

2 files changed

+118
-34
lines changed

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

Lines changed: 48 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -230,33 +230,52 @@ public static bool CanTranslate(Expression expression)
230230
return false;
231231
}
232232

233+
public static bool CanTranslateComparisonExpression(Expression leftExpression, AstComparisonFilterOperator comparisonOperator, Expression rightExpression)
234+
{
235+
return
236+
IsGetCharsComparison(leftExpression) ||
237+
IsStringEqualityComparison(leftExpression, comparisonOperator) ||
238+
IsStringIndexOfComparison(leftExpression) ||
239+
IsStringLengthComparison(leftExpression) || IsStringCountComparison(leftExpression);
240+
}
241+
233242
public static bool TryTranslate(TranslationContext context, Expression expression, out AstFilter filter)
234243
{
235-
try
236-
{
237-
filter = Translate(context, expression);
238-
return true;
239-
}
240-
catch (ExpressionNotSupportedException)
244+
if (CanTranslate(expression))
241245
{
242-
filter = null;
243-
return false;
246+
try
247+
{
248+
filter = Translate(context, expression);
249+
return true;
250+
}
251+
catch (ExpressionNotSupportedException)
252+
{
253+
// ignore exception and return false
254+
}
244255
}
256+
257+
filter = null;
258+
return false;
245259
}
246260

247261
// caller is responsible for ensuring constant is on the right
248262
public static bool TryTranslateComparisonExpression(TranslationContext context, Expression expression, Expression leftExpression, AstComparisonFilterOperator comparisonOperator, Expression rightExpression, out AstFilter filter)
249263
{
250-
try
251-
{
252-
filter = TranslateComparisonExpression(context, expression, leftExpression, comparisonOperator, rightExpression);
253-
return true;
254-
}
255-
catch (ExpressionNotSupportedException)
264+
if (CanTranslateComparisonExpression(leftExpression, comparisonOperator, rightExpression))
256265
{
257-
filter = null;
258-
return false;
266+
try
267+
{
268+
filter = TranslateComparisonExpression(context, expression, leftExpression, comparisonOperator, rightExpression);
269+
return true;
270+
}
271+
catch (ExpressionNotSupportedException)
272+
{
273+
// ignore exception and return false
274+
}
259275
}
276+
277+
filter = null;
278+
return false;
260279
}
261280

262281
public static AstFilter Translate(TranslationContext context, Expression expression)
@@ -287,9 +306,9 @@ public static AstFilter TranslateComparisonExpression(TranslationContext context
287306
return TranslateGetCharsComparison(context, expression, leftExpression, comparisonOperator, rightExpression);
288307
}
289308

290-
if (IsStringComparison(leftExpression))
309+
if (IsStringEqualityComparison(leftExpression, comparisonOperator))
291310
{
292-
return TranslateStringComparison(context, expression, leftExpression, comparisonOperator, rightExpression);
311+
return TranslateStringEqualityComparison(context, expression, leftExpression, comparisonOperator, rightExpression);
293312
}
294313

295314
if (IsStringIndexOfComparison(leftExpression))
@@ -370,24 +389,19 @@ private static string GetEscapedTrimChars(MethodCallExpression trimExpression)
370389

371390
private static bool IsGetCharsComparison(Expression leftExpression)
372391
{
373-
if (leftExpression is UnaryExpression leftUnaryExpression &&
374-
leftUnaryExpression.NodeType == ExpressionType.Convert &&
375-
leftUnaryExpression.Type == typeof(int) &&
376-
leftUnaryExpression.Operand is MethodCallExpression leftMethodCallExpression)
377-
{
378-
var method = leftMethodCallExpression.Method;
379-
if (method.Is(StringMethod.GetChars))
380-
{
381-
return true;
382-
}
383-
}
384-
385-
return false;
392+
return
393+
leftExpression is UnaryExpression leftConvertExpression &&
394+
leftConvertExpression.NodeType == ExpressionType.Convert &&
395+
leftConvertExpression.Type == typeof(int) &&
396+
leftConvertExpression.Operand is MethodCallExpression leftGetCharsExpression &&
397+
leftGetCharsExpression.Method.Is(StringMethod.GetChars);
386398
}
387399

388-
private static bool IsStringComparison(Expression leftExpression)
400+
private static bool IsStringEqualityComparison(Expression leftExpression, AstComparisonFilterOperator comparisonOperator)
389401
{
390-
return leftExpression.Type == typeof(string);
402+
return
403+
leftExpression.Type == typeof(string) &&
404+
(comparisonOperator == AstComparisonFilterOperator.Eq || comparisonOperator == AstComparisonFilterOperator.Ne);
391405
}
392406

393407
private static bool IsStringCountComparison(Expression leftExpression)
@@ -608,7 +622,7 @@ bool IsImpossibleMatch(Modifiers modifiers, string value)
608622
}
609623
}
610624

611-
private static AstFilter TranslateStringComparison(TranslationContext context, Expression expression, Expression leftExpression, AstComparisonFilterOperator comparisonOperator, Expression rightExpression)
625+
private static AstFilter TranslateStringEqualityComparison(TranslationContext context, Expression expression, Expression leftExpression, AstComparisonFilterOperator comparisonOperator, Expression rightExpression)
612626
{
613627
var (field, modifiers) = TranslateField(context, expression, leftExpression);
614628
var comparand = rightExpression.GetConstantValue<string>(containingExpression: expression);
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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.Linq.Expressions;
18+
using FluentAssertions;
19+
using MongoDB.Driver.Linq;
20+
using MongoDB.TestHelpers.XunitExtensions;
21+
using Xunit;
22+
23+
namespace MongoDB.Driver.Tests.Linq.Linq3Implementation.Jira
24+
{
25+
public class CSharp4803Tests : Linq3IntegrationTest
26+
{
27+
[Theory]
28+
[ParameterAttributeData]
29+
public void Find_filter_with_nonnullable_date_fields_should_work(
30+
[Values(LinqProvider.V2, LinqProvider.V3)] LinqProvider linqProvider)
31+
{
32+
var collection = GetCollection(linqProvider);
33+
var fromDate = new DateTime(2023, 9, 27, 0, 0, 0, DateTimeKind.Utc);
34+
Expression<Func<C, bool>> filter = ft => ft.Date >= fromDate;
35+
36+
var find = collection.Find(filter);
37+
38+
var renderedFilter = TranslateFindFilter(collection, find);
39+
renderedFilter.Should().Be("{ Date : { $gte : ISODate('2023-09-27T00:00:00Z') } }");
40+
}
41+
42+
[Theory]
43+
[ParameterAttributeData]
44+
public void Find_filter_with_nullable_date_fields_should_work(
45+
[Values(LinqProvider.V2, LinqProvider.V3)] LinqProvider linqProvider)
46+
{
47+
var collection = GetCollection(linqProvider);
48+
var fromDate = new DateTime(2023, 9, 27, 0, 0, 0, DateTimeKind.Utc);
49+
Expression<Func<C, bool>> filter = ft => ft.NullableDate >= fromDate;
50+
51+
var find = collection.Find(filter);
52+
53+
var renderedFilter = TranslateFindFilter(collection, find);
54+
renderedFilter.Should().Be("{ NullableDate : { $gte : ISODate('2023-09-27T00:00:00Z') } }");
55+
}
56+
57+
private IMongoCollection<C> GetCollection(LinqProvider linqProvider)
58+
{
59+
var collection = GetCollection<C>("test", linqProvider);
60+
return collection;
61+
}
62+
63+
private class C
64+
{
65+
public int Id { get; set; }
66+
public DateTime Date { get; set; }
67+
public DateTime? NullableDate { get; set; }
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)