Skip to content

Commit

Permalink
Report cross-document join exception on Cosmos
Browse files Browse the repository at this point in the history
And some test cleanup

Closes dotnet#33969
  • Loading branch information
roji committed Jun 22, 2024
1 parent 9e15699 commit 1fc8ad0
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 44 deletions.
6 changes: 6 additions & 0 deletions src/EFCore.Cosmos/Properties/CosmosStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/EFCore.Cosmos/Properties/CosmosStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@
<data name="CosmosNotInUse" xml:space="preserve">
<value>Cosmos-specific methods can only be used when the context is using the Cosmos provider.</value>
</data>
<data name="CrossDocumentJoinNotSupported" xml:space="preserve">
<value>Joins across documents aren't supported in Cosmos; consider modeling your data differently so that related data is in the same document. Alternatively, perform two separate queries to query the two documents.</value>
</data>
<data name="DefaultTTLMismatch" xml:space="preserve">
<value>The default time to live was configured to '{ttl1}' on '{entityType1}', but on '{entityType2}' it was configured to '{ttl2}'. All entity types mapped to the same container '{container}' must be configured with the same default time to live.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,10 @@ protected override ShapedQueryExpression TranslateDistinct(ShapedQueryExpression
LambdaExpression outerKeySelector,
LambdaExpression innerKeySelector,
LambdaExpression resultSelector)
=> null;
{
AddTranslationErrorDetails(CosmosStrings.CrossDocumentJoinNotSupported);
return null;
}

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down Expand Up @@ -807,7 +810,10 @@ protected override ShapedQueryExpression TranslateDistinct(ShapedQueryExpression
LambdaExpression outerKeySelector,
LambdaExpression innerKeySelector,
LambdaExpression resultSelector)
=> null;
{
AddTranslationErrorDetails(CosmosStrings.CrossDocumentJoinNotSupported);
return null;
}

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
117 changes: 75 additions & 42 deletions test/EFCore.Cosmos.FunctionalTests/Query/OwnedQueryCosmosTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ public OwnedQueryCosmosTest(OwnedQueryCosmosFixture fixture, ITestOutputHelper t
Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
}

// TODO: Fake LeftJoin, #33969
// Fink.Barton is a non-owned navigation, cross-document join
public override Task Query_loads_reference_nav_automatically_in_projection(bool async)
=> AssertTranslationFailed(() => base.Query_loads_reference_nav_automatically_in_projection(async));
=> AssertTranslationFailedWithDetails(
() => base.Query_loads_reference_nav_automatically_in_projection(async),
CosmosStrings.CrossDocumentJoinNotSupported);

// Non-correlated queries not supported by Cosmos
public override Task Query_with_owned_entity_equality_operator(bool async)
Expand Down Expand Up @@ -161,10 +163,11 @@ FROM root c
""");
});

// TODO: Fake LeftJoin, #33969
// Address.Planet is a non-owned navigation, cross-document join
public override Task Filter_owned_entity_chained_with_regular_entity_followed_by_projecting_owned_collection(bool async)
=> AssertTranslationFailed(
() => base.Filter_owned_entity_chained_with_regular_entity_followed_by_projecting_owned_collection(async));
=> AssertTranslationFailedWithDetails(
() => base.Filter_owned_entity_chained_with_regular_entity_followed_by_projecting_owned_collection(async),
CosmosStrings.CrossDocumentJoinNotSupported);

public override async Task Set_throws_for_owned_type(bool async)
{
Expand All @@ -173,55 +176,65 @@ public override async Task Set_throws_for_owned_type(bool async)
AssertSql();
}

// TODO: Fake LeftJoin, #33969
// Address.Planet is a non-owned navigation, cross-document join
public override Task Navigation_rewrite_on_owned_reference_followed_by_regular_entity(bool async)
=> AssertTranslationFailed(
() => base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity(async));
=> AssertTranslationFailedWithDetails(
() => base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity(async),
CosmosStrings.CrossDocumentJoinNotSupported);

// TODO: Fake LeftJoin, #33969
// Address.Planet is a non-owned navigation, cross-document join
public override Task Navigation_rewrite_on_owned_reference_followed_by_regular_entity_filter(bool async)
=> AssertTranslationFailed(
() => base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_filter(async));
=> AssertTranslationFailedWithDetails(
() => base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity(async),
CosmosStrings.CrossDocumentJoinNotSupported);

// TODO: Fake LeftJoin, #33969
// Address.Planet is a non-owned navigation, cross-document join
public override Task Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_another_reference(bool async)
=> AssertTranslationFailed(
() => base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_another_reference(async));
=> AssertTranslationFailedWithDetails(
() => base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_another_reference(async),
CosmosStrings.CrossDocumentJoinNotSupported);

// TODO: Fake LeftJoin, #33969
// Address.Planet is a non-owned navigation, cross-document join
public override Task Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_another_reference_and_scalar(bool async)
=> AssertTranslationFailed(
() => base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_another_reference_and_scalar(async));
=> AssertTranslationFailedWithDetails(
() => base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_another_reference_and_scalar(async),
CosmosStrings.CrossDocumentJoinNotSupported);

// TODO: Fake LeftJoin, #33969
// Address.Planet is a non-owned navigation, cross-document join
public override Task Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_collection(bool async)
=> AssertTranslationFailed(
() => base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_collection(async));
=> AssertTranslationFailedWithDetails(
() => base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_collection(async),
CosmosStrings.CrossDocumentJoinNotSupported);

// TODO: Fake LeftJoin, #33969
// Address.Planet is a non-owned navigation, cross-document join
public override Task Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_collection_count(bool async)
=> AssertTranslationFailed(
() => base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_collection(async));
=> AssertTranslationFailedWithDetails(
() => base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_collection_count(async),
CosmosStrings.CrossDocumentJoinNotSupported);

// TODO: Fake LeftJoin, #33969
// Address.Planet is a non-owned navigation, cross-document join
public override Task Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_property(bool async)
=> AssertTranslationFailed(
() => base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_property(async));
=> AssertTranslationFailedWithDetails(
() => base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_property(async),
CosmosStrings.CrossDocumentJoinNotSupported);

// TODO: Fake LeftJoin, #33969
// Address.Planet is a non-owned navigation, cross-document join
public override Task Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_another_reference_in_predicate_and_projection(bool async)
=> AssertTranslationFailed(
() => base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_another_reference_in_predicate_and_projection(async));
=> AssertTranslationFailedWithDetails(
() => base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_another_reference_in_predicate_and_projection(async),
CosmosStrings.CrossDocumentJoinNotSupported);

// TODO: Fake LeftJoin, #33969
// Address.Planet is a non-owned navigation, cross-document join
public override Task Project_multiple_owned_navigations(bool async)
=> AssertTranslationFailed(
() => base.Project_multiple_owned_navigations(async));
=> AssertTranslationFailedWithDetails(
() => base.Project_multiple_owned_navigations(async),
CosmosStrings.CrossDocumentJoinNotSupported);

// TODO: Fake LeftJoin, #33969
// Address.Planet is a non-owned navigation, cross-document join
public override Task Project_multiple_owned_navigations_with_expansion_on_owned_collections(bool async)
=> AssertTranslationFailed(
() => base.Project_multiple_owned_navigations_with_expansion_on_owned_collections(async));
=> AssertTranslationFailedWithDetails(
() => base.Project_multiple_owned_navigations_with_expansion_on_owned_collections(async),
CosmosStrings.CrossDocumentJoinNotSupported);

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
Expand All @@ -240,13 +253,17 @@ JOIN a IN c["Orders"]
""");
});

// TODO: Fake LeftJoin, #33969
// Address.Planet is a non-owned navigation, cross-document join
public override Task SelectMany_on_owned_reference_followed_by_regular_entity_and_collection(bool async)
=> AssertTranslationFailed(() => base.SelectMany_on_owned_reference_followed_by_regular_entity_and_collection(async));
=> AssertTranslationFailedWithDetails(
() => base.SelectMany_on_owned_reference_followed_by_regular_entity_and_collection(async),
CosmosStrings.CrossDocumentJoinNotSupported);

// TODO: Fake LeftJoin, #33969
// Address.Planet is a non-owned navigation, cross-document join
public override Task SelectMany_on_owned_reference_with_entity_in_between_ending_in_owned_collection(bool async)
=> AssertTranslationFailed(() => base.SelectMany_on_owned_reference_with_entity_in_between_ending_in_owned_collection(async));
=> AssertTranslationFailedWithDetails(
() => base.SelectMany_on_owned_reference_with_entity_in_between_ending_in_owned_collection(async),
CosmosStrings.CrossDocumentJoinNotSupported);

// Non-correlated queries not supported by Cosmos
public override Task Query_with_owned_entity_equality_method(bool async)
Expand Down Expand Up @@ -274,6 +291,21 @@ FROM root c
public override Task Query_when_subquery(bool async)
=> AssertTranslationFailed(() => base.Query_when_subquery(async));

public override Task Project_owned_reference_navigation(bool async)
=> CosmosTestHelpers.Instance.NoSyncTest(
async, async a =>
{
await base.Project_owned_reference_navigation(a);

AssertSql(
"""
SELECT c
FROM root c
WHERE c["Discriminator"] IN ("OwnedPerson", "Branch", "LeafB", "LeafA")
ORDER BY c["Id"]
""");
});

public override Task No_ignored_include_warning_when_implicit_load(bool async)
=> CosmosTestHelpers.Instance.NoSyncTest(
async, async a =>
Expand Down Expand Up @@ -687,12 +719,13 @@ public override async Task NoTracking_Include_with_cycles_throws(bool async)
AssertSql();
}

// TODO: Fake LeftJoin, #33969
// Order.Client is a non-owned navigation, cross-document join
public override Task NoTracking_Include_with_cycles_does_not_throw_when_performing_identity_resolution(
bool async,
bool useAsTracking)
=> AssertTranslationFailed(
() => base.NoTracking_Include_with_cycles_does_not_throw_when_performing_identity_resolution(async, useAsTracking));
=> AssertTranslationFailedWithDetails(
() => base.NoTracking_Include_with_cycles_does_not_throw_when_performing_identity_resolution(async, useAsTracking),
CosmosStrings.CrossDocumentJoinNotSupported);

public override async Task Trying_to_access_non_existent_indexer_property_throws_meaningful_exception(bool async)
{
Expand Down
7 changes: 7 additions & 0 deletions test/EFCore.Specification.Tests/Query/OwnedQueryTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ public virtual Task Query_when_subquery(bool async)
assertOrder: true,
elementAsserter: (e, a) => AssertEqual(e.op, a.op));

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Project_owned_reference_navigation(bool async)
=> AssertQuery(
async,
ss => ss.Set<OwnedPerson>().OrderBy(o => o.Id).Select(p => p.PersonAddress));

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Navigation_rewrite_on_owned_reference_projecting_scalar(bool async)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,18 @@ FROM [Order] AS [o1]
""");
}

public override async Task Project_owned_reference_navigation(bool async)
{
await base.Project_owned_reference_navigation(async);

AssertSql(
"""
SELECT [o].[PersonAddress_Country_Name]
FROM [OwnedPerson] AS [o]
WHERE [o].[PersonAddress_Country_Name] = N'USA'
""");
}

public override async Task Navigation_rewrite_on_owned_reference_projecting_scalar(bool async)
{
await base.Navigation_rewrite_on_owned_reference_projecting_scalar(async);
Expand Down

0 comments on commit 1fc8ad0

Please sign in to comment.