From b6af44c580028ef743ca0ad6485b8eaeda9c0a10 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Fri, 17 Jun 2022 11:10:24 +0200 Subject: [PATCH] Fixup to Cosmos regex translation Closes #28139 --- .../Query/Internal/CosmosRegexTranslator.cs | 39 +++++++++---------- .../NorthwindFunctionsQueryCosmosTest.cs | 22 ++++++----- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosRegexTranslator.cs b/src/EFCore.Cosmos/Query/Internal/CosmosRegexTranslator.cs index 51e735e7681..bf765963620 100644 --- a/src/EFCore.Cosmos/Query/Internal/CosmosRegexTranslator.cs +++ b/src/EFCore.Cosmos/Query/Internal/CosmosRegexTranslator.cs @@ -19,8 +19,6 @@ public class CosmosRegexTranslator : IMethodCallTranslator private static readonly MethodInfo IsMatchWithRegexOptions = typeof(Regex).GetRuntimeMethod(nameof(Regex.IsMatch), new[] { typeof(string), typeof(string), typeof(RegexOptions) })!; - private const RegexOptions SupportedOptions = RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace; - private readonly ISqlExpressionFactory _sqlExpressionFactory; /// @@ -53,48 +51,49 @@ public CosmosRegexTranslator(ISqlExpressionFactory sqlExpressionFactory) var (input, pattern) = (arguments[0], arguments[1]); var typeMapping = ExpressionExtensions.InferTypeMapping(input, pattern); + (input, pattern) = ( + _sqlExpressionFactory.ApplyTypeMapping(input, typeMapping), + _sqlExpressionFactory.ApplyTypeMapping(pattern, typeMapping)); - if (method == IsMatch) + if (method == IsMatch || arguments[2] is SqlConstantExpression { Value: RegexOptions.None }) { - return _sqlExpressionFactory.Function( - "RegexMatch", - new[] { - _sqlExpressionFactory.ApplyTypeMapping(input, typeMapping), - _sqlExpressionFactory.ApplyTypeMapping(pattern, typeMapping) - }, - typeof(bool)); + return _sqlExpressionFactory.Function("RegexMatch", new[] { input, pattern }, typeof(bool)); } - else if (arguments[2] is SqlConstantExpression { Value: RegexOptions regexOptions }) + + if (arguments[2] is SqlConstantExpression { Value: RegexOptions regexOptions }) { - string modifier = ""; + var modifier = ""; + if (regexOptions.HasFlag(RegexOptions.Multiline)) { + regexOptions &= ~RegexOptions.Multiline; modifier += "m"; } + if (regexOptions.HasFlag(RegexOptions.Singleline)) { + regexOptions &= ~RegexOptions.Singleline; modifier += "s"; } + if (regexOptions.HasFlag(RegexOptions.IgnoreCase)) { + regexOptions &= ~RegexOptions.IgnoreCase; modifier += "i"; } + if (regexOptions.HasFlag(RegexOptions.IgnorePatternWhitespace)) { + regexOptions &= ~RegexOptions.IgnorePatternWhitespace; modifier += "x"; } - return (regexOptions & ~SupportedOptions) == 0 + return regexOptions == 0 ? _sqlExpressionFactory.Function( "RegexMatch", - new[] - { - _sqlExpressionFactory.ApplyTypeMapping(input, typeMapping), - _sqlExpressionFactory.ApplyTypeMapping(pattern, typeMapping), - _sqlExpressionFactory.Constant(modifier) - }, + new[] { input, pattern, _sqlExpressionFactory.Constant(modifier) }, typeof(bool)) - : null; + : null; // TODO: Report unsupported RegexOption, #26410 } return null; diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs index 7529b91fa3d..a67e1e4ced6 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs @@ -1235,7 +1235,7 @@ await AssertQuery( AssertSql( @"SELECT c FROM root c -WHERE ((c[""Discriminator""] = ""Customer"") AND RegexMatch(c[""CustomerID""], ""^T"", """"))"); +WHERE ((c[""Discriminator""] = ""Customer"") AND RegexMatch(c[""CustomerID""], ""^T""))"); } [ConditionalTheory] @@ -1313,15 +1313,19 @@ FROM root c WHERE ((c[""Discriminator""] = ""Customer"") AND RegexMatch(c[""CustomerID""], ""^T"", ""ix""))"); } - [Fact] - public virtual void Regex_IsMatch_MethodCall_With_Unsupported_Option() - => Assert.Throws(() => - Fixture.CreateContext().Customers.Where(o => Regex.IsMatch(o.CustomerID, "^T", RegexOptions.RightToLeft)).ToList()); + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Regex_IsMatch_MethodCall_With_Unsupported_Option(bool async) + => AssertTranslationFailed(() => AssertQuery( + async, + ss => ss.Set().Where(o => Regex.IsMatch(o.CustomerID, "^T", RegexOptions.RightToLeft)))); - [Fact] - public virtual void Regex_IsMatch_MethodCall_With_Any_Unsupported_Option() - => Assert.Throws(() => - Fixture.CreateContext().Customers.Where(o => Regex.IsMatch(o.CustomerID, "^T", RegexOptions.IgnoreCase | RegexOptions.RightToLeft)).ToList()); + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Regex_IsMatch_MethodCall_With_Any_Unsupported_Option(bool async) + => AssertTranslationFailed(() => AssertQuery( + async, + ss => ss.Set().Where(o => Regex.IsMatch(o.CustomerID, "^T", RegexOptions.IgnoreCase | RegexOptions.RightToLeft)))); [ConditionalTheory] [MemberData(nameof(IsAsyncData))]