Skip to content

Commit f755ffc

Browse files
authored
Fixup to Cosmos regex translation (#28261)
Closes #28139
1 parent e62e767 commit f755ffc

File tree

2 files changed

+32
-29
lines changed

2 files changed

+32
-29
lines changed

src/EFCore.Cosmos/Query/Internal/CosmosRegexTranslator.cs

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ public class CosmosRegexTranslator : IMethodCallTranslator
1919
private static readonly MethodInfo IsMatchWithRegexOptions =
2020
typeof(Regex).GetRuntimeMethod(nameof(Regex.IsMatch), new[] { typeof(string), typeof(string), typeof(RegexOptions) })!;
2121

22-
private const RegexOptions SupportedOptions = RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace;
23-
2422
private readonly ISqlExpressionFactory _sqlExpressionFactory;
2523

2624
/// <summary>
@@ -53,48 +51,49 @@ public CosmosRegexTranslator(ISqlExpressionFactory sqlExpressionFactory)
5351

5452
var (input, pattern) = (arguments[0], arguments[1]);
5553
var typeMapping = ExpressionExtensions.InferTypeMapping(input, pattern);
54+
(input, pattern) = (
55+
_sqlExpressionFactory.ApplyTypeMapping(input, typeMapping),
56+
_sqlExpressionFactory.ApplyTypeMapping(pattern, typeMapping));
5657

57-
if (method == IsMatch)
58+
if (method == IsMatch || arguments[2] is SqlConstantExpression { Value: RegexOptions.None })
5859
{
59-
return _sqlExpressionFactory.Function(
60-
"RegexMatch",
61-
new[] {
62-
_sqlExpressionFactory.ApplyTypeMapping(input, typeMapping),
63-
_sqlExpressionFactory.ApplyTypeMapping(pattern, typeMapping)
64-
},
65-
typeof(bool));
60+
return _sqlExpressionFactory.Function("RegexMatch", new[] { input, pattern }, typeof(bool));
6661
}
67-
else if (arguments[2] is SqlConstantExpression { Value: RegexOptions regexOptions })
62+
63+
if (arguments[2] is SqlConstantExpression { Value: RegexOptions regexOptions })
6864
{
69-
string modifier = "";
65+
var modifier = "";
66+
7067
if (regexOptions.HasFlag(RegexOptions.Multiline))
7168
{
69+
regexOptions &= ~RegexOptions.Multiline;
7270
modifier += "m";
7371
}
72+
7473
if (regexOptions.HasFlag(RegexOptions.Singleline))
7574
{
75+
regexOptions &= ~RegexOptions.Singleline;
7676
modifier += "s";
7777
}
78+
7879
if (regexOptions.HasFlag(RegexOptions.IgnoreCase))
7980
{
81+
regexOptions &= ~RegexOptions.IgnoreCase;
8082
modifier += "i";
8183
}
84+
8285
if (regexOptions.HasFlag(RegexOptions.IgnorePatternWhitespace))
8386
{
87+
regexOptions &= ~RegexOptions.IgnorePatternWhitespace;
8488
modifier += "x";
8589
}
8690

87-
return (regexOptions & ~SupportedOptions) == 0
91+
return regexOptions == 0
8892
? _sqlExpressionFactory.Function(
8993
"RegexMatch",
90-
new[]
91-
{
92-
_sqlExpressionFactory.ApplyTypeMapping(input, typeMapping),
93-
_sqlExpressionFactory.ApplyTypeMapping(pattern, typeMapping),
94-
_sqlExpressionFactory.Constant(modifier)
95-
},
94+
new[] { input, pattern, _sqlExpressionFactory.Constant(modifier) },
9695
typeof(bool))
97-
: null;
96+
: null; // TODO: Report unsupported RegexOption, #26410
9897
}
9998

10099
return null;

test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,7 +1235,7 @@ await AssertQuery(
12351235
AssertSql(
12361236
@"SELECT c
12371237
FROM root c
1238-
WHERE ((c[""Discriminator""] = ""Customer"") AND RegexMatch(c[""CustomerID""], ""^T"", """"))");
1238+
WHERE ((c[""Discriminator""] = ""Customer"") AND RegexMatch(c[""CustomerID""], ""^T""))");
12391239
}
12401240

12411241
[ConditionalTheory]
@@ -1313,15 +1313,19 @@ FROM root c
13131313
WHERE ((c[""Discriminator""] = ""Customer"") AND RegexMatch(c[""CustomerID""], ""^T"", ""ix""))");
13141314
}
13151315

1316-
[Fact]
1317-
public virtual void Regex_IsMatch_MethodCall_With_Unsupported_Option()
1318-
=> Assert.Throws<InvalidOperationException>(() =>
1319-
Fixture.CreateContext().Customers.Where(o => Regex.IsMatch(o.CustomerID, "^T", RegexOptions.RightToLeft)).ToList());
1316+
[ConditionalTheory]
1317+
[MemberData(nameof(IsAsyncData))]
1318+
public virtual Task Regex_IsMatch_MethodCall_With_Unsupported_Option(bool async)
1319+
=> AssertTranslationFailed(() => AssertQuery(
1320+
async,
1321+
ss => ss.Set<Customer>().Where(o => Regex.IsMatch(o.CustomerID, "^T", RegexOptions.RightToLeft))));
13201322

1321-
[Fact]
1322-
public virtual void Regex_IsMatch_MethodCall_With_Any_Unsupported_Option()
1323-
=> Assert.Throws<InvalidOperationException>(() =>
1324-
Fixture.CreateContext().Customers.Where(o => Regex.IsMatch(o.CustomerID, "^T", RegexOptions.IgnoreCase | RegexOptions.RightToLeft)).ToList());
1323+
[ConditionalTheory]
1324+
[MemberData(nameof(IsAsyncData))]
1325+
public virtual Task Regex_IsMatch_MethodCall_With_Any_Unsupported_Option(bool async)
1326+
=> AssertTranslationFailed(() => AssertQuery(
1327+
async,
1328+
ss => ss.Set<Customer>().Where(o => Regex.IsMatch(o.CustomerID, "^T", RegexOptions.IgnoreCase | RegexOptions.RightToLeft))));
13251329

13261330
[ConditionalTheory]
13271331
[MemberData(nameof(IsAsyncData))]

0 commit comments

Comments
 (0)