From cfa6b142d49c04b80f02a7360f10039d5629b089 Mon Sep 17 00:00:00 2001 From: Roman Marusyk Date: Sat, 20 Feb 2021 03:29:06 +0200 Subject: [PATCH 1/3] Cosmos: Add translator for ToUpper method which map to UPPER built-in function --- .../Query/Internal/StringMethodTranslator.cs | 11 +++++++ .../NorthwindFunctionsQueryCosmosTest.cs | 30 +++++++++++++++++ .../Query/NorthwindFunctionsQueryTestBase.cs | 33 +++++++++++++++++++ 3 files changed, 74 insertions(+) diff --git a/src/EFCore.Cosmos/Query/Internal/StringMethodTranslator.cs b/src/EFCore.Cosmos/Query/Internal/StringMethodTranslator.cs index 434e2ba2add..946d3f550a2 100644 --- a/src/EFCore.Cosmos/Query/Internal/StringMethodTranslator.cs +++ b/src/EFCore.Cosmos/Query/Internal/StringMethodTranslator.cs @@ -30,6 +30,9 @@ private static readonly MethodInfo _startsWithMethodInfo private static readonly MethodInfo _endsWithMethodInfo = typeof(string).GetRequiredRuntimeMethod(nameof(string.EndsWith), new[] { typeof(string) }); + private static readonly MethodInfo _toUpperMethodInfo + = typeof(string).GetRequiredRuntimeMethod(nameof(string.ToUpper), Array.Empty()); + private static readonly MethodInfo _firstOrDefaultMethodInfoWithoutArgs = typeof(Enumerable).GetRuntimeMethods().Single( m => m.Name == nameof(Enumerable.FirstOrDefault) @@ -97,6 +100,11 @@ public StringMethodTranslator([NotNull] ISqlExpressionFactory sqlExpressionFacto { return TranslateSystemFunction("ENDSWITH", instance, arguments[0], typeof(bool)); } + + if (_toUpperMethodInfo.Equals(method)) + { + return TranslateSystemFunction("UPPER", instance, method.ReturnType); + } } if (_firstOrDefaultMethodInfoWithoutArgs.Equals(method)) @@ -141,5 +149,8 @@ public StringMethodTranslator([NotNull] ISqlExpressionFactory sqlExpressionFacto private SqlExpression TranslateSystemFunction(string function, SqlExpression instance, SqlExpression pattern, Type returnType) => _sqlExpressionFactory.Function(function, new[] { instance, pattern }, returnType); + + private SqlExpression TranslateSystemFunction(string function, SqlExpression instance, Type returnType) + => _sqlExpressionFactory.Function(function, new[] { instance }, returnType); } } diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs index e3770d9c77b..2a43d06a8e0 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs @@ -99,6 +99,36 @@ FROM root c WHERE ((c[""Discriminator""] = ""Customer"") AND ((c[""ContactName""] != null) AND ((""m"" != null) AND ENDSWITH(c[""ContactName""], ""m""))))"); } + public override async Task String_ToUpper_Literal(bool async) + { + await base.String_ToUpper_Literal(async); + + AssertSql( + @"SELECT c +FROM root c +WHERE ((c[""Discriminator""] = ""Customer"") AND (UPPER(c[""ContactName""]) = ""MARIA ANDERS""))"); + } + + public override async Task String_ToUpper_Column(bool async) + { + await base.String_ToUpper_Column(async); + + AssertSql( + @"SELECT c +FROM root c +WHERE ((c[""Discriminator""] = ""Customer"") AND (c[""ContactName""] != UPPER(c[""ContactName""])))"); + } + + public override async Task String_ToUpper_MethodCall(bool async) + { + await base.String_ToUpper_MethodCall(async); + + AssertSql( + @"SELECT c +FROM root c +WHERE ((c[""Discriminator""] = ""Customer"") AND (UPPER(c[""ContactName""]) = ""MARIA ANDERS""))"); + } + public override async Task String_Contains_Literal(bool async) { await base.String_Contains_Literal(async); diff --git a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs index 674a88f3600..20dc0eb9797 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs @@ -119,6 +119,36 @@ public virtual Task String_EndsWith_MethodCall(bool async) entryCount: 1); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task String_ToUpper_Literal(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Where(c => c.ContactName.ToUpper() == "MARIA ANDERS"), + entryCount: 1); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task String_ToUpper_Column(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Where(c => c.ContactName != c.ContactName.ToUpper()), + entryCount: 91); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task String_ToUpper_MethodCall(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Where(c => c.ContactName.ToUpper() == LocalMethod4()), + entryCount: 1); + } + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task String_Contains_Literal(bool async) @@ -743,6 +773,9 @@ protected static string LocalMethod1() protected static string LocalMethod2() => "m"; + protected static string LocalMethod4() + => "MARIA ANDERS"; + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Where_math_abs1(bool async) From 1a4227f8ad73246e32dc4fce0320f2494de9be33 Mon Sep 17 00:00:00 2001 From: Roman Marusyk Date: Sun, 21 Feb 2021 00:01:49 +0200 Subject: [PATCH 2/3] Code review fixes. Remove redundant tests --- .../NorthwindFunctionsQueryCosmosTest.cs | 33 +------------------ .../Query/NorthwindFunctionsQueryTestBase.cs | 33 ------------------- 2 files changed, 1 insertion(+), 65 deletions(-) diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs index 2a43d06a8e0..304fde6b7bd 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs @@ -99,36 +99,6 @@ FROM root c WHERE ((c[""Discriminator""] = ""Customer"") AND ((c[""ContactName""] != null) AND ((""m"" != null) AND ENDSWITH(c[""ContactName""], ""m""))))"); } - public override async Task String_ToUpper_Literal(bool async) - { - await base.String_ToUpper_Literal(async); - - AssertSql( - @"SELECT c -FROM root c -WHERE ((c[""Discriminator""] = ""Customer"") AND (UPPER(c[""ContactName""]) = ""MARIA ANDERS""))"); - } - - public override async Task String_ToUpper_Column(bool async) - { - await base.String_ToUpper_Column(async); - - AssertSql( - @"SELECT c -FROM root c -WHERE ((c[""Discriminator""] = ""Customer"") AND (c[""ContactName""] != UPPER(c[""ContactName""])))"); - } - - public override async Task String_ToUpper_MethodCall(bool async) - { - await base.String_ToUpper_MethodCall(async); - - AssertSql( - @"SELECT c -FROM root c -WHERE ((c[""Discriminator""] = ""Customer"") AND (UPPER(c[""ContactName""]) = ""MARIA ANDERS""))"); - } - public override async Task String_Contains_Literal(bool async) { await base.String_Contains_Literal(async); @@ -636,7 +606,6 @@ FROM root c WHERE (c[""Discriminator""] = ""OrderDetail"")"); } - [ConditionalTheory(Skip = "Issue #17246")] public override async Task Where_string_to_upper(bool async) { await base.Where_string_to_upper(async); @@ -644,7 +613,7 @@ public override async Task Where_string_to_upper(bool async) AssertSql( @"SELECT c FROM root c -WHERE (c[""Discriminator""] = ""Customer"")"); +WHERE ((c[""Discriminator""] = ""Customer"") AND (UPPER(c[""CustomerID""]) = ""ALFKI""))"); } [ConditionalTheory(Skip = "Issue #17246")] diff --git a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs index 20dc0eb9797..674a88f3600 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs @@ -119,36 +119,6 @@ public virtual Task String_EndsWith_MethodCall(bool async) entryCount: 1); } - [ConditionalTheory] - [MemberData(nameof(IsAsyncData))] - public virtual Task String_ToUpper_Literal(bool async) - { - return AssertQuery( - async, - ss => ss.Set().Where(c => c.ContactName.ToUpper() == "MARIA ANDERS"), - entryCount: 1); - } - - [ConditionalTheory] - [MemberData(nameof(IsAsyncData))] - public virtual Task String_ToUpper_Column(bool async) - { - return AssertQuery( - async, - ss => ss.Set().Where(c => c.ContactName != c.ContactName.ToUpper()), - entryCount: 91); - } - - [ConditionalTheory] - [MemberData(nameof(IsAsyncData))] - public virtual Task String_ToUpper_MethodCall(bool async) - { - return AssertQuery( - async, - ss => ss.Set().Where(c => c.ContactName.ToUpper() == LocalMethod4()), - entryCount: 1); - } - [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task String_Contains_Literal(bool async) @@ -773,9 +743,6 @@ protected static string LocalMethod1() protected static string LocalMethod2() => "m"; - protected static string LocalMethod4() - => "MARIA ANDERS"; - [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Where_math_abs1(bool async) From 9c1d00d55f3e39815181bceb469100749b1e703a Mon Sep 17 00:00:00 2001 From: Roman Marusyk Date: Mon, 22 Feb 2021 22:50:23 +0200 Subject: [PATCH 3/3] Code review fixes --- .../Query/Internal/StringMethodTranslator.cs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/EFCore.Cosmos/Query/Internal/StringMethodTranslator.cs b/src/EFCore.Cosmos/Query/Internal/StringMethodTranslator.cs index 946d3f550a2..22505eff2ba 100644 --- a/src/EFCore.Cosmos/Query/Internal/StringMethodTranslator.cs +++ b/src/EFCore.Cosmos/Query/Internal/StringMethodTranslator.cs @@ -88,33 +88,33 @@ public StringMethodTranslator([NotNull] ISqlExpressionFactory sqlExpressionFacto { if (_containsMethodInfo.Equals(method)) { - return TranslateSystemFunction("CONTAINS", instance, arguments[0], typeof(bool)); + return TranslateSystemFunction("CONTAINS", typeof(bool), instance, arguments[0]); } if (_startsWithMethodInfo.Equals(method)) { - return TranslateSystemFunction("STARTSWITH", instance, arguments[0], typeof(bool)); + return TranslateSystemFunction("STARTSWITH", typeof(bool), instance, arguments[0]); } if (_endsWithMethodInfo.Equals(method)) { - return TranslateSystemFunction("ENDSWITH", instance, arguments[0], typeof(bool)); + return TranslateSystemFunction("ENDSWITH", typeof(bool), instance, arguments[0]); } if (_toUpperMethodInfo.Equals(method)) { - return TranslateSystemFunction("UPPER", instance, method.ReturnType); + return TranslateSystemFunction("UPPER", method.ReturnType, instance); } } if (_firstOrDefaultMethodInfoWithoutArgs.Equals(method)) { - return TranslateSystemFunction("LEFT", arguments[0], _sqlExpressionFactory.Constant(1), typeof(char)); + return TranslateSystemFunction("LEFT", typeof(char), arguments[0], _sqlExpressionFactory.Constant(1)); } if (_lastOrDefaultMethodInfoWithoutArgs.Equals(method)) { - return TranslateSystemFunction("RIGHT", arguments[0], _sqlExpressionFactory.Constant(1), typeof(char)); + return TranslateSystemFunction("RIGHT", typeof(char), arguments[0], _sqlExpressionFactory.Constant(1)); } if(_stringConcatWithTwoArguments.Equals(method)) @@ -147,10 +147,7 @@ public StringMethodTranslator([NotNull] ISqlExpressionFactory sqlExpressionFacto return null; } - private SqlExpression TranslateSystemFunction(string function, SqlExpression instance, SqlExpression pattern, Type returnType) - => _sqlExpressionFactory.Function(function, new[] { instance, pattern }, returnType); - - private SqlExpression TranslateSystemFunction(string function, SqlExpression instance, Type returnType) - => _sqlExpressionFactory.Function(function, new[] { instance }, returnType); + private SqlExpression TranslateSystemFunction(string function, Type returnType, params SqlExpression[] arguments) + => _sqlExpressionFactory.Function(function, arguments, returnType); } }