From b0e684c2c0b7c0632b70c8185b0b368c207457ee Mon Sep 17 00:00:00 2001 From: Maurycy Markowski Date: Tue, 12 Oct 2021 15:09:32 -0700 Subject: [PATCH] Fix to #19356 - Query: Add more tests for Queryable.Reverse Adding tests for thenby, join, subquery, selectmany Fixes #19356 --- .../Query/NorthwindSelectQueryCosmosTest.cs | 248 +++++++----------- .../Query/NorthwindSelectQueryTestBase.cs | 185 +++++++++++++ .../NorthwindSelectQuerySqlServerTest.cs | 205 +++++++++++++++ .../Query/NorthwindSelectQuerySqliteTest.cs | 18 ++ 4 files changed, 499 insertions(+), 157 deletions(-) diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs index 53caf32a5c4..e44fb8360fb 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs @@ -913,122 +913,82 @@ FROM root c [ConditionalTheory(Skip = "Issue#17246")] public override Task Client_method_in_projection_requiring_materialization_1(bool async) - { - return base.Client_method_in_projection_requiring_materialization_1(async); - } + => base.Client_method_in_projection_requiring_materialization_1(async); [ConditionalTheory(Skip = "Issue#17246")] public override Task Client_method_in_projection_requiring_materialization_2(bool async) - { - return base.Client_method_in_projection_requiring_materialization_2(async); - } + => base.Client_method_in_projection_requiring_materialization_2(async); [ConditionalTheory(Skip = "Issue#17246")] public override Task Multiple_select_many_with_predicate(bool async) - { - return base.Multiple_select_many_with_predicate(async); - } + => base.Multiple_select_many_with_predicate(async); [ConditionalTheory(Skip = "Issue #17246")] public override Task SelectMany_without_result_selector_naked_collection_navigation(bool async) - { - return base.SelectMany_without_result_selector_naked_collection_navigation(async); - } + => base.SelectMany_without_result_selector_naked_collection_navigation(async); [ConditionalTheory(Skip = "Issue #17246")] public override Task SelectMany_without_result_selector_collection_navigation_composed(bool async) - { - return base.SelectMany_without_result_selector_collection_navigation_composed(async); - } + => base.SelectMany_without_result_selector_collection_navigation_composed(async); [ConditionalTheory(Skip = "Issue#17246")] public override Task SelectMany_correlated_with_outer_1(bool async) - { - return base.SelectMany_correlated_with_outer_1(async); - } + => base.SelectMany_correlated_with_outer_1(async); [ConditionalTheory(Skip = "Issue#17246")] public override Task SelectMany_correlated_with_outer_2(bool async) - { - return base.SelectMany_correlated_with_outer_2(async); - } + => base.SelectMany_correlated_with_outer_2(async); [ConditionalTheory(Skip = "Issue#17246")] public override Task SelectMany_correlated_with_outer_3(bool async) - { - return base.SelectMany_correlated_with_outer_3(async); - } + => base.SelectMany_correlated_with_outer_3(async); [ConditionalTheory(Skip = "Issue#17246")] public override Task SelectMany_correlated_with_outer_4(bool async) - { - return base.SelectMany_correlated_with_outer_4(async); - } + => base.SelectMany_correlated_with_outer_4(async); [ConditionalTheory(Skip = "Issue#17246")] public override Task SelectMany_correlated_with_outer_5(bool async) - { - return base.SelectMany_correlated_with_outer_5(async); - } + => base.SelectMany_correlated_with_outer_5(async); [ConditionalTheory(Skip = "Issue#17246")] public override Task SelectMany_correlated_with_outer_6(bool async) - { - return base.SelectMany_correlated_with_outer_6(async); - } + => base.SelectMany_correlated_with_outer_6(async); [ConditionalTheory(Skip = "Issue#17246")] public override Task SelectMany_correlated_with_outer_7(bool async) - { - return base.SelectMany_correlated_with_outer_7(async); - } + => base.SelectMany_correlated_with_outer_7(async); [ConditionalTheory(Skip = "Issue#17246")] public override Task FirstOrDefault_over_empty_collection_of_value_type_returns_correct_results(bool async) - { - return base.FirstOrDefault_over_empty_collection_of_value_type_returns_correct_results(async); - } + => base.FirstOrDefault_over_empty_collection_of_value_type_returns_correct_results(async); [ConditionalTheory(Skip = "Issue#17246")] public override Task Project_non_nullable_value_after_FirstOrDefault_on_empty_collection(bool async) - { - return base.Project_non_nullable_value_after_FirstOrDefault_on_empty_collection(async); - } + => base.Project_non_nullable_value_after_FirstOrDefault_on_empty_collection(async); public override Task Member_binding_after_ctor_arguments_fails_with_client_eval(bool async) - { - return AssertTranslationFailed(() => base.Member_binding_after_ctor_arguments_fails_with_client_eval(async)); - } + => AssertTranslationFailed(() => base.Member_binding_after_ctor_arguments_fails_with_client_eval(async)); [ConditionalTheory(Skip = "Issue#17246")] public override Task Filtered_collection_projection_is_tracked(bool async) - { - return base.Filtered_collection_projection_is_tracked(async); - } + => base.Filtered_collection_projection_is_tracked(async); [ConditionalTheory(Skip = "Issue#17246")] public override Task Filtered_collection_projection_with_to_list_is_tracked(bool async) - { - return base.Filtered_collection_projection_with_to_list_is_tracked(async); - } + => base.Filtered_collection_projection_with_to_list_is_tracked(async); [ConditionalTheory(Skip = "Issue #17246")] public override Task SelectMany_with_collection_being_correlated_subquery_which_references_inner_and_outer_entity(bool async) - { - return base.SelectMany_with_collection_being_correlated_subquery_which_references_inner_and_outer_entity(async); - } + => base.SelectMany_with_collection_being_correlated_subquery_which_references_inner_and_outer_entity(async); [ConditionalTheory(Skip = "Issue #17246")] public override Task Select_chained_entity_navigation_doesnt_materialize_intermittent_entities(bool async) - { - return base.Select_chained_entity_navigation_doesnt_materialize_intermittent_entities(async); - } + => base.Select_chained_entity_navigation_doesnt_materialize_intermittent_entities(async); [ConditionalTheory(Skip = "Issue #17246")] public override Task Select_entity_compared_to_null(bool async) - { - return base.Select_entity_compared_to_null(async); - } + => base.Select_entity_compared_to_null(async); public override async Task Explicit_cast_in_arithmetic_operation_is_preserved(bool async) { @@ -1042,39 +1002,27 @@ FROM root c [ConditionalTheory(Skip = "Issue #17246")] public override Task SelectMany_whose_selector_references_outer_source(bool async) - { - return base.SelectMany_whose_selector_references_outer_source(async); - } + => base.SelectMany_whose_selector_references_outer_source(async); [ConditionalTheory(Skip = "Issue #17246")] public override Task Collection_FirstOrDefault_with_entity_equality_check_in_projection(bool async) - { - return base.Collection_FirstOrDefault_with_entity_equality_check_in_projection(async); - } + => base.Collection_FirstOrDefault_with_entity_equality_check_in_projection(async); [ConditionalTheory(Skip = "Issue #17246")] public override Task Collection_FirstOrDefault_with_nullable_unsigned_int_column(bool async) - { - return base.Collection_FirstOrDefault_with_nullable_unsigned_int_column(async); - } + => base.Collection_FirstOrDefault_with_nullable_unsigned_int_column(async); [ConditionalTheory(Skip = "Issue#17246")] public override Task ToList_Count_in_projection_works(bool async) - { - return base.ToList_Count_in_projection_works(async); - } + => base.ToList_Count_in_projection_works(async); [ConditionalTheory(Skip = "Issue#17246")] public override Task LastOrDefault_member_access_in_projection_translates_to_server(bool async) - { - return base.LastOrDefault_member_access_in_projection_translates_to_server(async); - } + => base.LastOrDefault_member_access_in_projection_translates_to_server(async); [ConditionalTheory(Skip = "Issue#17246")] public override Task Collection_projection_AsNoTracking_OrderBy(bool async) - { - return base.Collection_projection_AsNoTracking_OrderBy(async); - } + => base.Collection_projection_AsNoTracking_OrderBy(async); public override async Task Coalesce_over_nullable_uint(bool async) { @@ -1088,15 +1036,11 @@ FROM root c [ConditionalTheory(Skip = "Issue#17246")] public override Task Project_uint_through_collection_FirstOrDefault(bool async) - { - return base.Project_uint_through_collection_FirstOrDefault(async); - } + => base.Project_uint_through_collection_FirstOrDefault(async); [ConditionalTheory(Skip = "Issue#17246")] public override Task Project_keyless_entity_FirstOrDefault_without_orderby(bool async) - { - return base.Project_keyless_entity_FirstOrDefault_without_orderby(async); - } + => base.Project_keyless_entity_FirstOrDefault_without_orderby(async); public override async Task Reverse_changes_asc_order_to_desc(bool async) { @@ -1122,9 +1066,7 @@ FROM root c [ConditionalTheory(Skip = "Issue#17246")] public override Task Projection_AsEnumerable_projection(bool async) - { - return base.Projection_AsEnumerable_projection(async); - } + => base.Projection_AsEnumerable_projection(async); public override async Task Projection_custom_type_in_both_sides_of_ternary(bool async) { @@ -1139,63 +1081,43 @@ FROM root c [ConditionalTheory(Skip = "Issue#17246")] public override Task Projecting_multiple_collection_with_same_constant_works(bool async) - { - return base.Projecting_multiple_collection_with_same_constant_works(async); - } + => base.Projecting_multiple_collection_with_same_constant_works(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Projecting_after_navigation_and_distinct(bool async) - { - return base.Projecting_after_navigation_and_distinct(async); - } + => base.Projecting_after_navigation_and_distinct(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Correlated_collection_after_distinct_with_complex_projection_containing_original_identifier(bool async) - { - return base.Correlated_collection_after_distinct_with_complex_projection_containing_original_identifier(async); - } + => base.Correlated_collection_after_distinct_with_complex_projection_containing_original_identifier(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Correlated_collection_after_distinct_not_containing_original_identifier(bool async) - { - return base.Correlated_collection_after_distinct_not_containing_original_identifier(async); - } + => base.Correlated_collection_after_distinct_not_containing_original_identifier(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Correlated_collection_after_distinct_with_complex_projection_not_containing_original_identifier(bool async) - { - return base.Correlated_collection_after_distinct_with_complex_projection_not_containing_original_identifier(async); - } + => base.Correlated_collection_after_distinct_with_complex_projection_not_containing_original_identifier(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Correlated_collection_after_groupby_with_complex_projection_containing_original_identifier(bool async) - { - return base.Correlated_collection_after_groupby_with_complex_projection_containing_original_identifier(async); - } + => base.Correlated_collection_after_groupby_with_complex_projection_containing_original_identifier(async); public override Task Reverse_without_explicit_ordering(bool async) - { - return AssertTranslationFailedWithDetails( + => AssertTranslationFailedWithDetails( () => base.Reverse_without_explicit_ordering(async), CosmosStrings.MissingOrderingInSelectExpression); - } [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Custom_projection_reference_navigation_PK_to_FK_optimization(bool async) - { - return base.Custom_projection_reference_navigation_PK_to_FK_optimization(async); - } + => base.Custom_projection_reference_navigation_PK_to_FK_optimization(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Select_nested_collection_deep(bool async) - { - return base.Select_nested_collection_deep(async); - } + => base.Select_nested_collection_deep(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Projecting_Length_of_a_string_property_after_FirstOrDefault_on_correlated_collection(bool async) - { - return base.Projecting_Length_of_a_string_property_after_FirstOrDefault_on_correlated_collection(async); - } + => base.Projecting_Length_of_a_string_property_after_FirstOrDefault_on_correlated_collection(async); public override async Task Projection_take_predicate_projection(bool async) { @@ -1233,39 +1155,27 @@ public override async Task Projection_skip_projection_doesnt_project_intermitten [ConditionalTheory(Skip = "Issue#17246")] public override Task Projection_Distinct_projection_preserves_columns_used_for_distinct_in_subquery(bool async) - { - return base.Projection_Distinct_projection_preserves_columns_used_for_distinct_in_subquery(async); - } + => base.Projection_Distinct_projection_preserves_columns_used_for_distinct_in_subquery(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Projecting_count_of_navigation_which_is_generic_collection(bool async) - { - return base.Projecting_count_of_navigation_which_is_generic_collection(async); - } + => base.Projecting_count_of_navigation_which_is_generic_collection(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Projecting_count_of_navigation_which_is_generic_list(bool async) - { - return base.Projecting_count_of_navigation_which_is_generic_list(async); - } + => base.Projecting_count_of_navigation_which_is_generic_list(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Do_not_erase_projection_mapping_when_adding_single_projection(bool async) - { - return base.Do_not_erase_projection_mapping_when_adding_single_projection(async); - } + => base.Do_not_erase_projection_mapping_when_adding_single_projection(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Select_nested_collection_deep_distinct_no_identifiers(bool async) - { - return base.Select_nested_collection_deep_distinct_no_identifiers(async); - } + => base.Select_nested_collection_deep_distinct_no_identifiers(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Correlated_collection_after_groupby_with_complex_projection_not_containing_original_identifier(bool async) - { - return base.Correlated_collection_after_groupby_with_complex_projection_not_containing_original_identifier(async); - } + => base.Correlated_collection_after_groupby_with_complex_projection_not_containing_original_identifier(async); public override async Task Ternary_in_client_eval_assigns_correct_types(bool async) { @@ -1280,50 +1190,74 @@ FROM root c [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Collection_include_over_result_of_single_non_scalar(bool async) - { - return base.Collection_include_over_result_of_single_non_scalar(async); - } + => base.Collection_include_over_result_of_single_non_scalar(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Collection_projection_selecting_outer_element_followed_by_take(bool async) - { - return base.Collection_projection_selecting_outer_element_followed_by_take(async); - } + => base.Collection_projection_selecting_outer_element_followed_by_take(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Take_on_top_level_and_on_collection_projection_with_outer_apply(bool async) - { - return base.Take_on_top_level_and_on_collection_projection_with_outer_apply(async); - } + => base.Take_on_top_level_and_on_collection_projection_with_outer_apply(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Take_on_correlated_collection_in_first(bool async) - { - return base.Take_on_correlated_collection_in_first(async); - } + => base.Take_on_correlated_collection_in_first(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Client_projection_via_ctor_arguments(bool async) - { - return base.Client_projection_via_ctor_arguments(async); - } + => base.Client_projection_via_ctor_arguments(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Client_projection_with_string_initialization_with_scalar_subquery(bool async) - { - return base.Client_projection_with_string_initialization_with_scalar_subquery(async); - } + => base.Client_projection_with_string_initialization_with_scalar_subquery(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Projecting_count_of_navigation_which_is_generic_collection_using_convert(bool async) - { - return base.Projecting_count_of_navigation_which_is_generic_collection_using_convert(async); - } + => base.Projecting_count_of_navigation_which_is_generic_collection_using_convert(async); [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task MemberInit_in_projection_without_arguments(bool async) + => base.MemberInit_in_projection_without_arguments(async); + + [ConditionalTheory(Skip = "Cross collection join Issue#17246")] + public override Task Reverse_in_join_outer(bool async) + => base.Reverse_in_join_outer(async); + + [ConditionalTheory(Skip = "Cross collection join Issue#17246")] + public override Task Reverse_in_join_outer_with_take(bool async) + => base.Reverse_in_join_outer_with_take(async); + + [ConditionalTheory(Skip = "Cross collection join Issue#17246")] + public override Task Reverse_in_join_inner(bool async) + => base.Reverse_in_join_inner(async); + + [ConditionalTheory(Skip = "Cross collection join Issue#17246")] + public override Task Reverse_in_join_inner_with_skip(bool async) + => base.Reverse_in_join_inner_with_skip(async); + + [ConditionalTheory(Skip = "Issue #17246")] + public override Task Reverse_in_SelectMany(bool async) + => base.Reverse_in_SelectMany(async); + + [ConditionalTheory(Skip = "Issue #17246")] + public override Task Reverse_in_SelectMany_with_Take(bool async) + => base.Reverse_in_SelectMany_with_Take(async); + + [ConditionalTheory(Skip = "Issue #17246")] + public override Task Reverse_in_projection_subquery(bool async) + => base.Reverse_in_projection_subquery(async); + + [ConditionalTheory(Skip = "Issue #17246")] + public override Task Reverse_in_subquery_via_pushdown(bool async) + => base.Reverse_in_subquery_via_pushdown(async); + + public override async Task Reverse_after_orderBy_and_take(bool async) { - return base.MemberInit_in_projection_without_arguments(async); + var message = (await Assert.ThrowsAsync( + () => base.Reverse_after_orderBy_and_take(async))).Message; + + Assert.Equal(CosmosStrings.ReverseAfterSkipTakeNotSupported, message); } private void AssertSql(params string[] expected) diff --git a/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs index cffe03586f5..071944500cf 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs @@ -927,6 +927,191 @@ public virtual Task Reverse_without_explicit_ordering(bool async) ss => ss.Set().Reverse().Select(e => e.EmployeeID)); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Reverse_after_multiple_orderbys(bool async) + { + return AssertQueryScalar( + async, + ss => ss.Set() + .OrderBy(e => e.City) + .OrderByDescending(e => e.EmployeeID) + .Reverse() + .Select(e => e.EmployeeID), + assertOrder: true); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Reverse_after_orderby_thenby(bool async) + { + return AssertQueryScalar( + async, + ss => ss.Set() + .OrderBy(e => e.EmployeeID) + .ThenByDescending(e => e.City) + .Select(e => e.EmployeeID) + .Reverse(), + assertOrder: true); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Reverse_in_subquery_via_pushdown(bool async) + { + return AssertQuery( + async, + ss => ss.Set() + .OrderBy(e => e.EmployeeID) + .Reverse() + .Take(5) + .Distinct() + .Select(e => new { e.EmployeeID, e.City }), + assertOrder: true); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Reverse_after_orderBy_and_take(bool async) + { + return AssertQuery( + async, + ss => ss.Set() + .OrderBy(e => e.EmployeeID) + .Take(5) + .Reverse() + .Select(e => new { e.EmployeeID, e.City }), + assertOrder: true); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Reverse_in_join_outer(bool async) + { + return AssertQuery( + async, + ss => ss.Set() + .OrderByDescending(c => c.City) + .ThenBy(c => c.CustomerID) + .Reverse() + .Join( + ss.Set().OrderBy(o => o.OrderID), + o => o.CustomerID, + i => i.CustomerID, + (o, i) => new { o.CustomerID, i.OrderID }), + elementSorter: e => (e.CustomerID, e.OrderID)); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Reverse_in_join_outer_with_take(bool async) + { + return AssertQuery( + async, + ss => ss.Set() + .OrderByDescending(c => c.CustomerID) + .Reverse() + .Take(20) + .Join( + ss.Set().OrderBy(o => o.OrderID), + o => o.CustomerID, + i => i.CustomerID, + (o, i) => new { o.CustomerID, i.OrderID }), + elementSorter: e => (e.CustomerID, e.OrderID)); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Reverse_in_join_inner(bool async) + { + return AssertQuery( + async, + ss => from c in ss.Set().OrderBy(x => x.CustomerID) + join o in ss.Set().OrderByDescending(x => x.OrderDate).Reverse() on c.CustomerID equals o.CustomerID into grouping + from o in grouping.DefaultIfEmpty() + select new { c.CustomerID, OrderID = (int?)o.OrderID }, + elementSorter: e => (e.CustomerID, e.OrderID)); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Reverse_in_join_inner_with_skip(bool async) + { + return AssertQuery( + async, + ss => from c in ss.Set().OrderBy(x => x.CustomerID) + join o in ss.Set().OrderByDescending(x => x.OrderID).Skip(2).Reverse() on c.CustomerID equals o.CustomerID into grouping + from o in grouping.DefaultIfEmpty() + select new { c.CustomerID, OrderID = (int?)o.OrderID }, + elementSorter: e => (e.CustomerID, e.OrderID)); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Reverse_in_SelectMany(bool async) + { + return AssertQuery( + async, + ss => ss.Set() + .OrderBy(c => c.CustomerID) + .Reverse() + .SelectMany(c => c.Orders.OrderByDescending(o => o.OrderID).Reverse()), + entryCount: 830); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Reverse_in_SelectMany_with_Take(bool async) + { + return AssertQuery( + async, + ss => ss.Set() + .OrderBy(c => c.CustomerID) + .Reverse() + .Take(20) + .SelectMany(c => c.Orders.OrderByDescending(o => o.OrderID).Take(30).Reverse()), + entryCount: 161); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Reverse_in_projection_subquery(bool async) + { + return AssertQuery( + async, + ss => ss.Set() + .OrderBy(c => c.CustomerID) + .Select(c => ss.Set().OrderBy(o => o.OrderDate).ThenByDescending(o => o.OrderID).Reverse().ToList()), + assertOrder: true, + elementAsserter: (e, a) => AssertCollection(e, a, ordered: true), + entryCount: 830); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Reverse_in_projection_subquery_single_result(bool async) + { + return AssertQuery( + async, + ss => ss.Set() + .OrderBy(c => c.CustomerID) + .Select(c => ss.Set().OrderBy(o => o.OrderDate).ThenByDescending(o => o.OrderID).Reverse().FirstOrDefault()), + assertOrder: true, + entryCount: 1); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Reverse_in_projection_scalar_subquery(bool async) + { + return AssertQueryScalar( + async, + ss => ss.Set() + .OrderBy(c => c.CustomerID) + .Select(c => ss.Set().OrderBy(o => o.OrderDate).ThenByDescending(o => o.OrderID).Reverse().Select(o => o.OrderID).FirstOrDefault()), + assertOrder: true); + } + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Projection_containing_DateTime_subtraction(bool async) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs index c8bd7504324..6e7d24c3546 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs @@ -1381,6 +1381,211 @@ FROM [Employees] AS [e] ORDER BY [e].[EmployeeID]"); } + public override async Task Reverse_after_multiple_orderbys(bool async) + { + await base.Reverse_after_multiple_orderbys(async); + + AssertSql( + @"SELECT [e].[EmployeeID] +FROM [Employees] AS [e] +ORDER BY [e].[EmployeeID]"); + } + + public override async Task Reverse_after_orderby_thenby(bool async) + { + await base.Reverse_after_orderby_thenby(async); + + AssertSql( + @"SELECT [e].[EmployeeID] +FROM [Employees] AS [e] +ORDER BY [e].[EmployeeID] DESC, [e].[City]"); + } + + + public override async Task Reverse_in_subquery_via_pushdown(bool async) + { + await base.Reverse_in_subquery_via_pushdown(async); + + AssertSql( + @"@__p_0='5' + +SELECT [t0].[EmployeeID], [t0].[City] +FROM ( + SELECT DISTINCT [t].[EmployeeID], [t].[City], [t].[Country], [t].[FirstName], [t].[ReportsTo], [t].[Title] + FROM ( + SELECT TOP(@__p_0) [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] + FROM [Employees] AS [e] + ORDER BY [e].[EmployeeID] DESC + ) AS [t] +) AS [t0]"); + } + + public override async Task Reverse_after_orderBy_and_take(bool async) + { + await base.Reverse_after_orderBy_and_take(async); + + AssertSql( + @"@__p_0='5' + +SELECT [t].[EmployeeID], [t].[City] +FROM ( + SELECT TOP(@__p_0) [e].[EmployeeID], [e].[City] + FROM [Employees] AS [e] + ORDER BY [e].[EmployeeID] +) AS [t] +ORDER BY [t].[EmployeeID] DESC"); + } + + public override async Task Reverse_in_join_outer(bool async) + { + await base.Reverse_in_join_outer(async); + + AssertSql( + @"SELECT [c].[CustomerID], [t].[OrderID] +FROM [Customers] AS [c] +INNER JOIN ( + SELECT [o].[OrderID], [o].[CustomerID] + FROM [Orders] AS [o] +) AS [t] ON [c].[CustomerID] = [t].[CustomerID] +ORDER BY [c].[City], [c].[CustomerID] DESC"); + } + + public override async Task Reverse_in_join_outer_with_take(bool async) + { + await base.Reverse_in_join_outer_with_take(async); + + AssertSql( + @"@__p_0='20' + +SELECT [t].[CustomerID], [t0].[OrderID] +FROM ( + SELECT TOP(@__p_0) [c].[CustomerID] + FROM [Customers] AS [c] + ORDER BY [c].[CustomerID] +) AS [t] +INNER JOIN ( + SELECT [o].[OrderID], [o].[CustomerID] + FROM [Orders] AS [o] +) AS [t0] ON [t].[CustomerID] = [t0].[CustomerID] +ORDER BY [t].[CustomerID]"); + } + + public override async Task Reverse_in_join_inner(bool async) + { + await base.Reverse_in_join_inner(async); + + AssertSql( + @"SELECT [c].[CustomerID], [t].[OrderID] +FROM [Customers] AS [c] +LEFT JOIN ( + SELECT [o].[OrderID], [o].[CustomerID] + FROM [Orders] AS [o] +) AS [t] ON [c].[CustomerID] = [t].[CustomerID] +ORDER BY [c].[CustomerID]"); + } + + public override async Task Reverse_in_join_inner_with_skip(bool async) + { + await base.Reverse_in_join_inner_with_skip(async); + + AssertSql( + @"@__p_0='2' + +SELECT [c].[CustomerID], [t0].[OrderID] +FROM [Customers] AS [c] +LEFT JOIN ( + SELECT [t].[OrderID], [t].[CustomerID] + FROM ( + SELECT [o].[OrderID], [o].[CustomerID] + FROM [Orders] AS [o] + ORDER BY [o].[OrderID] DESC + OFFSET @__p_0 ROWS + ) AS [t] +) AS [t0] ON [c].[CustomerID] = [t0].[CustomerID] +ORDER BY [c].[CustomerID]"); + } + + public override async Task Reverse_in_SelectMany(bool async) + { + await base.Reverse_in_SelectMany(async); + + AssertSql( + @"SELECT [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate] +FROM [Customers] AS [c] +INNER JOIN ( + SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] + FROM [Orders] AS [o] +) AS [t] ON [c].[CustomerID] = [t].[CustomerID] +ORDER BY [c].[CustomerID] DESC"); + } + + public override async Task Reverse_in_SelectMany_with_Take(bool async) + { + await base.Reverse_in_SelectMany_with_Take(async); + + AssertSql( + @"@__p_0='20' + +SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate] +FROM ( + SELECT TOP(@__p_0) [c].[CustomerID] + FROM [Customers] AS [c] + ORDER BY [c].[CustomerID] DESC +) AS [t] +CROSS APPLY ( + SELECT [t1].[OrderID], [t1].[CustomerID], [t1].[EmployeeID], [t1].[OrderDate] + FROM ( + SELECT TOP(30) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] + FROM [Orders] AS [o] + WHERE [t].[CustomerID] = [o].[CustomerID] + ORDER BY [o].[OrderID] DESC + ) AS [t1] +) AS [t0] +ORDER BY [t].[CustomerID] DESC"); + } + + public override async Task Reverse_in_projection_subquery(bool async) + { + await base.Reverse_in_projection_subquery(async); + + AssertSql( + @"SELECT [c].[CustomerID], [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate] +FROM [Customers] AS [c] +OUTER APPLY ( + SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] + FROM [Orders] AS [o] +) AS [t] +ORDER BY [c].[CustomerID], [t].[OrderDate] DESC, [t].[OrderID]"); + } + + public override async Task Reverse_in_projection_subquery_single_result(bool async) + { + await base.Reverse_in_projection_subquery_single_result(async); + + AssertSql( + @"SELECT [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate] +FROM [Customers] AS [c] +OUTER APPLY ( + SELECT TOP(1) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] + FROM [Orders] AS [o] + ORDER BY [o].[OrderDate] DESC, [o].[OrderID] +) AS [t] +ORDER BY [c].[CustomerID]"); + } + + public override async Task Reverse_in_projection_scalar_subquery(bool async) + { + await base.Reverse_in_projection_scalar_subquery(async); + + AssertSql( + @"SELECT COALESCE(( + SELECT TOP(1) [o].[OrderID] + FROM [Orders] AS [o] + ORDER BY [o].[OrderDate] DESC, [o].[OrderID]), 0) +FROM [Customers] AS [c] +ORDER BY [c].[CustomerID]"); + } + public override async Task Projection_AsEnumerable_projection(bool async) { await base.Projection_AsEnumerable_projection(async); diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindSelectQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindSelectQuerySqliteTest.cs index eef675f189c..4ec21a5c324 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindSelectQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindSelectQuerySqliteTest.cs @@ -224,6 +224,24 @@ public override async Task Select_nested_collection_deep_distinct_no_identifiers (await Assert.ThrowsAsync( () => base.Select_nested_collection_deep_distinct_no_identifiers(async))).Message); + public override async Task Reverse_in_projection_subquery(bool async) + => Assert.Equal( + SqliteStrings.ApplyNotSupported, + (await Assert.ThrowsAsync( + () => base.Reverse_in_projection_subquery(async))).Message); + + public override async Task Reverse_in_projection_subquery_single_result(bool async) + => Assert.Equal( + SqliteStrings.ApplyNotSupported, + (await Assert.ThrowsAsync( + () => base.Reverse_in_projection_subquery_single_result(async))).Message); + + public override async Task Reverse_in_SelectMany_with_Take(bool async) + => Assert.Equal( + SqliteStrings.ApplyNotSupported, + (await Assert.ThrowsAsync( + () => base.Reverse_in_SelectMany_with_Take(async))).Message); + [ConditionalTheory(Skip = "Issue#17324")] public override Task Project_single_element_from_collection_with_OrderBy_over_navigation_Take_and_FirstOrDefault_2(bool async) {