Skip to content

Commit

Permalink
fix(federation): use out_edges_with_federation_self_edges in query …
Browse files Browse the repository at this point in the history
…builder (#6127)
  • Loading branch information
duckki authored Oct 8, 2024
1 parent c438729 commit bf61558
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 9 deletions.
14 changes: 5 additions & 9 deletions apollo-federation/src/query_graph/build_query_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1572,8 +1572,8 @@ impl FederatedQueryGraphBuilder {
Selection::Field(field_selection) => {
let existing_edge_info = base
.query_graph
.graph
.edges_directed(node, Direction::Outgoing)
.out_edges_with_federation_self_edges(node)
.into_iter()
.find_map(|edge_ref| {
let edge_weight = edge_ref.weight();
let QueryGraphEdgeTransition::FieldCollection {
Expand Down Expand Up @@ -1697,8 +1697,8 @@ impl FederatedQueryGraphBuilder {
// construction.
let (edge, tail) = base
.query_graph
.graph
.edges_directed(node, Direction::Outgoing)
.out_edges_with_federation_self_edges(node)
.into_iter()
.find_map(|edge_ref| {
let edge_weight = edge_ref.weight();
let QueryGraphEdgeTransition::Downcast {
Expand Down Expand Up @@ -1810,11 +1810,7 @@ impl FederatedQueryGraphBuilder {
new_node_weight.has_reachable_cross_subgraph_edges = has_reachable_cross_subgraph_edges;

let mut new_edges = Vec::new();
for edge_ref in base
.query_graph
.graph
.edges_directed(node, Direction::Outgoing)
{
for edge_ref in base.query_graph.out_edges_with_federation_self_edges(node) {
let edge_tail = edge_ref.target();
let edge_weight = edge_ref.weight();
new_edges.push(QueryGraphEdgeData {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -846,3 +846,73 @@ fn it_works_with_type_condition_even_for_types_only_reachable_by_the_at_provides
"###
);
}

#[test]
fn test_provides_edge_ordering() {
let planner = planner!(
SubgraphQ: r#"
type A {
id: ID! @external
}
type Query {
test: A @provides(fields: "id")
}
"#,
SubgraphX: r#"
type A @key(fields: "id") {
id: ID!
data: String! @shareable
}
"#,
SubgraphY: r#"
type A @key(fields: "id") {
id: ID!
data: String! @shareable
}
"#,
);

assert_plan!(
&planner,
r#"
{
test { # provides id
data
}
}
"#,

// Make sure @provides edges are ordered as expected.
// `data` is expected to be fetched from SubgraphX, not SubgraphY.
@r###"
QueryPlan {
Sequence {
Fetch(service: "SubgraphQ") {
{
test {
__typename
id
}
}
},
Flatten(path: "test") {
Fetch(service: "SubgraphX") {
{
... on A {
__typename
id
}
} =>
{
... on A {
data
}
}
},
},
},
}
"###
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Composed from subgraphs with hash: f5cb1210587d45fee11b9c57247d6c570d0ae7fd
schema
@link(url: "https://specs.apollo.dev/link/v1.0")
@link(url: "https://specs.apollo.dev/join/v0.4", for: EXECUTION)
{
query: Query
}

directive @join__directive(graphs: [join__Graph!], name: String!, args: join__DirectiveArguments) repeatable on SCHEMA | OBJECT | INTERFACE | FIELD_DEFINITION

directive @join__enumValue(graph: join__Graph!) repeatable on ENUM_VALUE

directive @join__field(graph: join__Graph, requires: join__FieldSet, provides: join__FieldSet, type: String, external: Boolean, override: String, usedOverridden: Boolean, overrideLabel: String) repeatable on FIELD_DEFINITION | INPUT_FIELD_DEFINITION

directive @join__graph(name: String!, url: String!) on ENUM_VALUE

directive @join__implements(graph: join__Graph!, interface: String!) repeatable on OBJECT | INTERFACE

directive @join__type(graph: join__Graph!, key: join__FieldSet, extension: Boolean! = false, resolvable: Boolean! = true, isInterfaceObject: Boolean! = false) repeatable on OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT | SCALAR

directive @join__unionMember(graph: join__Graph!, member: String!) repeatable on UNION

directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA

type A
@join__type(graph: SUBGRAPHQ)
@join__type(graph: SUBGRAPHX, key: "id")
@join__type(graph: SUBGRAPHY, key: "id")
{
id: ID! @join__field(graph: SUBGRAPHQ, external: true) @join__field(graph: SUBGRAPHX) @join__field(graph: SUBGRAPHY)
data: String! @join__field(graph: SUBGRAPHX) @join__field(graph: SUBGRAPHY)
}

scalar join__DirectiveArguments

scalar join__FieldSet

enum join__Graph {
SUBGRAPHQ @join__graph(name: "SubgraphQ", url: "none")
SUBGRAPHX @join__graph(name: "SubgraphX", url: "none")
SUBGRAPHY @join__graph(name: "SubgraphY", url: "none")
}

scalar link__Import

enum link__Purpose {
"""
`SECURITY` features provide metadata necessary to securely resolve fields.
"""
SECURITY

"""
`EXECUTION` features provide metadata necessary for operation execution.
"""
EXECUTION
}

type Query
@join__type(graph: SUBGRAPHQ)
@join__type(graph: SUBGRAPHX)
@join__type(graph: SUBGRAPHY)
{
test: A @join__field(graph: SUBGRAPHQ, provides: "id")
}

0 comments on commit bf61558

Please sign in to comment.