Skip to content

Commit 09382e7

Browse files
author
Sylvain Lebresne
authored
Fix assertion errors when querying types with no common supertypes at the same path (#2467)
Fetches input selections used to be based on the queried subgraph schema. However, those selections truly applies to the in-memory data maintained by the gateway/router, so the supergraph. This used to not matter (all input selection did correctly applied to the subgraph schema), but `@interfaceObject` made it so that some input selections could be invalid for the subgraph. Typically, a fetch that queries a subgraph with an `@interfaceObject` may look like: ``` Fetch(service: 'A') { { ... on Book { id } } => { ... on Product { <some fields> } } } ``` where `Book` is a concrete implementation of `Product` but unknown to subgraph `A`. However, basing the input selections on the supergraph schema means having the parent type, in the supergraph, for those selections, and because some fetches can query multiple different entities, this is not trivial. The initial code for `@interfaceObject` make the (incorrect) assumption that, when a fetch does query multiple types, then we could always find a common supertype for all those types, and so was using that type as parent type. Unfortunately, this isn't always true (see test in this PR, which uses a union type with types having a field with the same name but different (and unrelated) types). So in pratice, fetch inputs cannot always have a common parent type. This patch thus changes the fetch inputs to be a map of type to selection sets instead of a single selection set. Note that it does mean that the `requires` field of a `FetchGroup` is not a true valid "single" selection for the supergraph (or any subgraph for that matter), but it is more of a "fun fact" since the execution never relied on this anyway. Fixes #2466
1 parent bceee47 commit 09382e7

File tree

3 files changed

+225
-85
lines changed

3 files changed

+225
-85
lines changed

.changeset/thin-weeks-refuse.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@apollo/query-planner": patch
3+
---
4+
5+
Fix query planner assertion error when types with no common supertypes are requested at the same path
6+

query-planner-js/src/__tests__/buildPlan.test.ts

+115
Original file line numberDiff line numberDiff line change
@@ -5452,3 +5452,118 @@ test('handles case of key chains in parallel requires', () => {
54525452
}
54535453
`);
54545454
});
5455+
5456+
test('handles types with no common supertype at the same "mergeAt"', () => {
5457+
const subgraph1 = {
5458+
name: 'Subgraph1',
5459+
typeDefs: gql`
5460+
type Query {
5461+
t: T
5462+
}
5463+
5464+
union T = T1 | T2
5465+
5466+
type T1 @key(fields: "id") {
5467+
id: ID!
5468+
sub: Foo
5469+
}
5470+
5471+
type Foo @key(fields: "id") {
5472+
id: ID!
5473+
x: Int
5474+
}
5475+
5476+
type T2 @key(fields: "id") {
5477+
id: ID!
5478+
sub: Bar
5479+
}
5480+
5481+
type Bar @key(fields: "id") {
5482+
id: ID!
5483+
x: Int
5484+
}
5485+
`
5486+
}
5487+
5488+
const subgraph2 = {
5489+
name: 'Subgraph2',
5490+
typeDefs: gql`
5491+
type Foo @key(fields: "id") {
5492+
id: ID!
5493+
y: Int
5494+
}
5495+
5496+
type Bar @key(fields: "id") {
5497+
id: ID!
5498+
y: Int
5499+
}
5500+
`
5501+
}
5502+
5503+
const [api, queryPlanner] = composeAndCreatePlanner(subgraph1, subgraph2);
5504+
const operation = operationFromDocument(api, gql`
5505+
{
5506+
t {
5507+
... on T1 {
5508+
sub {
5509+
y
5510+
}
5511+
}
5512+
... on T2 {
5513+
sub {
5514+
y
5515+
}
5516+
}
5517+
}
5518+
}
5519+
`);
5520+
5521+
const plan = queryPlanner.buildQueryPlan(operation);
5522+
expect(plan).toMatchInlineSnapshot(`
5523+
QueryPlan {
5524+
Sequence {
5525+
Fetch(service: "Subgraph1") {
5526+
{
5527+
t {
5528+
__typename
5529+
... on T1 {
5530+
sub {
5531+
__typename
5532+
id
5533+
}
5534+
}
5535+
... on T2 {
5536+
sub {
5537+
__typename
5538+
id
5539+
}
5540+
}
5541+
}
5542+
}
5543+
},
5544+
Flatten(path: "t.sub") {
5545+
Fetch(service: "Subgraph2") {
5546+
{
5547+
... on Foo {
5548+
__typename
5549+
id
5550+
}
5551+
... on Bar {
5552+
__typename
5553+
id
5554+
}
5555+
} =>
5556+
{
5557+
... on Foo {
5558+
y
5559+
}
5560+
... on Bar {
5561+
y
5562+
}
5563+
}
5564+
},
5565+
},
5566+
},
5567+
}
5568+
`);
5569+
});

0 commit comments

Comments
 (0)