diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosMathTranslator.cs b/src/EFCore.Cosmos/Query/Internal/CosmosMathTranslator.cs index d6d01c1efda..a5c94298332 100644 --- a/src/EFCore.Cosmos/Query/Internal/CosmosMathTranslator.cs +++ b/src/EFCore.Cosmos/Query/Internal/CosmosMathTranslator.cs @@ -48,6 +48,8 @@ public class CosmosMathTranslator : IMethodCallTranslator { typeof(Math).GetRuntimeMethod(nameof(Math.Truncate), new[] { typeof(double) })!, "TRUNC" }, { typeof(Math).GetRuntimeMethod(nameof(Math.Round), new[] { typeof(decimal) })!, "ROUND" }, { typeof(Math).GetRuntimeMethod(nameof(Math.Round), new[] { typeof(double) })!, "ROUND" }, + { typeof(double).GetRuntimeMethod(nameof(double.DegreesToRadians), new[] { typeof(double) })!, "RADIANS" }, + { typeof(double).GetRuntimeMethod(nameof(double.RadiansToDegrees), new[] { typeof(double) })!, "DEGREES" }, { typeof(MathF).GetRuntimeMethod(nameof(MathF.Abs), new[] { typeof(float) })!, "ABS" }, { typeof(MathF).GetRuntimeMethod(nameof(MathF.Ceiling), new[] { typeof(float) })!, "CEILING" }, { typeof(MathF).GetRuntimeMethod(nameof(MathF.Floor), new[] { typeof(float) })!, "FLOOR" }, @@ -66,7 +68,9 @@ public class CosmosMathTranslator : IMethodCallTranslator { typeof(MathF).GetRuntimeMethod(nameof(MathF.Tan), new[] { typeof(float) })!, "TAN" }, { typeof(MathF).GetRuntimeMethod(nameof(MathF.Sign), new[] { typeof(float) })!, "SIGN" }, { typeof(MathF).GetRuntimeMethod(nameof(MathF.Truncate), new[] { typeof(float) })!, "TRUNC" }, - { typeof(MathF).GetRuntimeMethod(nameof(MathF.Round), new[] { typeof(float) })!, "ROUND" } + { typeof(MathF).GetRuntimeMethod(nameof(MathF.Round), new[] { typeof(float) })!, "ROUND" }, + { typeof(float).GetRuntimeMethod(nameof(float.DegreesToRadians), new[] { typeof(float) })!, "RADIANS" }, + { typeof(float).GetRuntimeMethod(nameof(float.RadiansToDegrees), new[] { typeof(float) })!, "DEGREES" }, }; private readonly ISqlExpressionFactory _sqlExpressionFactory; diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerMathTranslator.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerMathTranslator.cs index b6bee38f8bd..7d262da5ce0 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerMathTranslator.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerMathTranslator.cs @@ -47,6 +47,8 @@ public class SqlServerMathTranslator : IMethodCallTranslator { typeof(Math).GetRuntimeMethod(nameof(Math.Sign), new[] { typeof(long) })!, "SIGN" }, { typeof(Math).GetRuntimeMethod(nameof(Math.Sign), new[] { typeof(sbyte) })!, "SIGN" }, { typeof(Math).GetRuntimeMethod(nameof(Math.Sign), new[] { typeof(short) })!, "SIGN" }, + { typeof(double).GetRuntimeMethod(nameof(double.DegreesToRadians), new[] { typeof(double) })!, "RADIANS" }, + { typeof(double).GetRuntimeMethod(nameof(double.RadiansToDegrees), new[] { typeof(double) })!, "DEGREES" }, { typeof(MathF).GetRuntimeMethod(nameof(MathF.Abs), new[] { typeof(float) })!, "ABS" }, { typeof(MathF).GetRuntimeMethod(nameof(MathF.Ceiling), new[] { typeof(float) })!, "CEILING" }, { typeof(MathF).GetRuntimeMethod(nameof(MathF.Floor), new[] { typeof(float) })!, "FLOOR" }, @@ -63,7 +65,9 @@ public class SqlServerMathTranslator : IMethodCallTranslator { typeof(MathF).GetRuntimeMethod(nameof(MathF.Cos), new[] { typeof(float) })!, "COS" }, { typeof(MathF).GetRuntimeMethod(nameof(MathF.Sin), new[] { typeof(float) })!, "SIN" }, { typeof(MathF).GetRuntimeMethod(nameof(MathF.Tan), new[] { typeof(float) })!, "TAN" }, - { typeof(MathF).GetRuntimeMethod(nameof(MathF.Sign), new[] { typeof(float) })!, "SIGN" } + { typeof(MathF).GetRuntimeMethod(nameof(MathF.Sign), new[] { typeof(float) })!, "SIGN" }, + { typeof(float).GetRuntimeMethod(nameof(float.DegreesToRadians), new[] { typeof(float) })!, "RADIANS" }, + { typeof(float).GetRuntimeMethod(nameof(float.RadiansToDegrees), new[] { typeof(float) })!, "DEGREES" } }; private static readonly IEnumerable TruncateMethodInfos = new[] diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs index 80e0846356d..6ff277f6f90 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindFunctionsQueryCosmosTest.cs @@ -573,6 +573,22 @@ public override async Task Where_math_max(bool async) AssertSql(); } + public override async Task Where_math_degrees(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Where_math_degrees(async)); + + AssertSql(); + } + + public override async Task Where_math_radians(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed(() => base.Where_math_radians(async)); + + AssertSql(); + } + public override async Task Where_mathf_abs1(bool async) { // Cosmos client evaluation. Issue #17246. @@ -797,6 +813,30 @@ SELECT c """); } + public override async Task Where_mathf_degrees(bool async) + { + await base.Where_mathf_degrees(async); + + AssertSql( +""" +SELECT c +FROM root c +WHERE (((c["Discriminator"] = "OrderDetail") AND (c["OrderID"] = 11077)) AND (DEGREES(c["Discount"]) > 0.0)) +"""); + } + + public override async Task Where_mathf_radians(bool async) + { + await base.Where_mathf_radians(async); + + AssertSql( +""" +SELECT c +FROM root c +WHERE (((c["Discriminator"] = "OrderDetail") AND (c["OrderID"] = 11077)) AND (RADIANS(c["Discount"]) > 0.0)) +"""); + } + public override async Task Where_guid_newguid(bool async) { // Cosmos client evaluation. Issue #17246. diff --git a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs index ea1f6829bb3..4a514b97812 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindFunctionsQueryTestBase.cs @@ -1113,6 +1113,22 @@ public virtual Task Where_math_min(bool async) .Where(od => Math.Min(od.OrderID, od.ProductID) == od.ProductID), entryCount: 25); + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Where_math_degrees(bool async) + => AssertQuery( + async, + ss => ss.Set().Where(od => od.OrderID == 11077).Where(od => double.RadiansToDegrees(od.Discount) > 0), + entryCount: 13); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Where_math_radians(bool async) + => AssertQuery( + async, + ss => ss.Set().Where(od => od.OrderID == 11077).Where(od => double.DegreesToRadians(od.Discount) > 0), + entryCount: 13); + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Where_mathf_abs1(bool async) @@ -1307,6 +1323,22 @@ public virtual Task Where_mathf_sign(bool async) ss => ss.Set().Where(od => od.OrderID == 11077).Where(od => MathF.Sign(od.Discount) > 0), entryCount: 13); + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Where_mathf_degrees(bool async) + => AssertQuery( + async, + ss => ss.Set().Where(od => od.OrderID == 11077).Where(od => float.RadiansToDegrees(od.Discount) > 0), + entryCount: 13); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Where_mathf_radians(bool async) + => AssertQuery( + async, + ss => ss.Set().Where(od => od.OrderID == 11077).Where(od => float.DegreesToRadians(od.Discount) > 0), + entryCount: 13); + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Where_guid_newguid(bool async) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs index 3ec4a922545..7bd4e81f5d4 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServerTest.cs @@ -1323,6 +1323,30 @@ public override async Task Where_math_max(bool async) AssertSql(); } + public override async Task Where_math_degrees(bool async) + { + await base.Where_math_degrees(async); + + AssertSql( +""" +SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice] +FROM [Order Details] AS [o] +WHERE [o].[OrderID] = 11077 AND DEGREES(CAST([o].[Discount] AS float)) > 0.0E0 +"""); + } + + public override async Task Where_math_radians(bool async) + { + await base.Where_math_radians(async); + + AssertSql( +""" +SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice] +FROM [Order Details] AS [o] +WHERE [o].[OrderID] = 11077 AND RADIANS(CAST([o].[Discount] AS float)) > 0.0E0 +"""); + } + public override async Task Where_mathf_abs1(bool async) { await base.Where_mathf_abs1(async); @@ -1599,6 +1623,30 @@ public override async Task Where_mathf_sign(bool async) """); } + public override async Task Where_mathf_degrees(bool async) + { + await base.Where_mathf_degrees(async); + + AssertSql( +""" +SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice] +FROM [Order Details] AS [o] +WHERE [o].[OrderID] = 11077 AND DEGREES([o].[Discount]) > CAST(0 AS real) +"""); + } + + public override async Task Where_mathf_radians(bool async) + { + await base.Where_mathf_radians(async); + + AssertSql( +""" +SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice] +FROM [Order Details] AS [o] +WHERE [o].[OrderID] = 11077 AND RADIANS([o].[Discount]) > CAST(0 AS real) +"""); + } + public override async Task Where_guid_newguid(bool async) { await base.Where_guid_newguid(async); diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs index 62a6d0b1744..be7ac9d8535 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindFunctionsQuerySqliteTest.cs @@ -144,6 +144,12 @@ public override Task Where_math_tan(bool async) public override Task Where_math_truncate(bool async) => AssertTranslationFailed(() => base.Where_math_truncate(async)); + public override Task Where_math_degrees(bool async) + => AssertTranslationFailed(() => base.Where_math_degrees(async)); + + public override Task Where_math_radians(bool async) + => AssertTranslationFailed(() => base.Where_math_radians(async)); + public override Task Where_mathf_acos(bool async) => AssertTranslationFailed(() => base.Where_mathf_acos(async)); @@ -207,6 +213,12 @@ public override Task Where_mathf_tan(bool async) public override Task Where_mathf_truncate(bool async) => AssertTranslationFailed(() => base.Where_mathf_truncate(async)); + public override Task Where_mathf_degrees(bool async) + => AssertTranslationFailed(() => base.Where_mathf_degrees(async)); + + public override Task Where_mathf_radians(bool async) + => AssertTranslationFailed(() => base.Where_mathf_radians(async)); + public override async Task String_StartsWith_Literal(bool async) { await base.String_StartsWith_Literal(async);