Skip to content

Commit c5a12dd

Browse files
committed
Fix composition satisfiability and query planning for @Shareable mutation fields
1 parent de30c6b commit c5a12dd

File tree

6 files changed

+720
-95
lines changed

6 files changed

+720
-95
lines changed

composition-js/src/__tests__/validation_errors.test.ts

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,151 @@ describe('when shared field has non-intersecting runtime types in different subg
413413
});
414414
});
415415

416+
describe('@shareable on top-level mutation fields', () => {
417+
it('errors when queries may require multiple calls to mutation field', () => {
418+
const subgraphA = {
419+
name: 'A',
420+
typeDefs: gql`
421+
type Query {
422+
dummy: Int
423+
}
424+
425+
type Mutation {
426+
f: F @shareable
427+
}
428+
429+
type F {
430+
x: Int
431+
}
432+
`
433+
};
434+
const subgraphB = {
435+
name: 'B',
436+
typeDefs: gql`
437+
type Mutation {
438+
f: F @shareable
439+
}
440+
441+
type F {
442+
y: Int
443+
}
444+
`
445+
};
446+
447+
const result = composeAsFed2Subgraphs([subgraphA, subgraphB]);
448+
expect(result.errors).toBeDefined();
449+
expect(errorMessages(result)).toMatchStringArray([
450+
`
451+
Supergraph API queries using the mutation field \"Mutation.f\" at top-level must be satisfiable without needing to call that field from multiple subgraphs, but every subgraph with that field encounters satisfiability errors. Please fix these satisfiability errors for (at least) one of the following subgraphs with the mutation field:
452+
- When calling \"Mutation.f\" at top-level from subgraph \"A\":
453+
The following supergraph API query:
454+
mutation {
455+
f {
456+
y
457+
}
458+
}
459+
cannot be satisfied by the subgraphs because:
460+
- from subgraph \"A\":
461+
- cannot find field \"F.y\".
462+
- cannot move to subgraph \"B\", which has field \"F.y\", because type \"F\" has no @key defined in subgraph \"B\".
463+
- When calling \"Mutation.f\" at top-level from subgraph \"B\":
464+
The following supergraph API query:
465+
mutation {
466+
f {
467+
x
468+
}
469+
}
470+
cannot be satisfied by the subgraphs because:
471+
- from subgraph \"B\":
472+
- cannot find field \"F.x\".
473+
- cannot move to subgraph \"A\", which has field \"F.x\", because type \"F\" has no @key defined in subgraph \"A\".
474+
`
475+
]);
476+
});
477+
478+
it('errors normally for mutation fields that are not actually shared', () => {
479+
const subgraphA = {
480+
name: 'A',
481+
typeDefs: gql`
482+
type Query {
483+
dummy: Int
484+
}
485+
486+
type Mutation {
487+
f: F @shareable
488+
}
489+
490+
type F @key(fields: "id") {
491+
id: ID!
492+
x: Int
493+
}
494+
`
495+
};
496+
const subgraphB = {
497+
name: 'B',
498+
typeDefs: gql`
499+
type F @key(fields: "id", resolvable: false) {
500+
id: ID!
501+
y: Int
502+
}
503+
`
504+
};
505+
506+
const result = composeAsFed2Subgraphs([subgraphA, subgraphB]);
507+
expect(result.errors).toBeDefined();
508+
expect(errorMessages(result)).toMatchStringArray([
509+
`
510+
The following supergraph API query:
511+
mutation {
512+
f {
513+
y
514+
}
515+
}
516+
cannot be satisfied by the subgraphs because:
517+
- from subgraph "A":
518+
- cannot find field "F.y".
519+
- cannot move to subgraph "B", which has field "F.y", because none of the @key defined on type "F" in subgraph "B" are resolvable (they are all declared with their "resolvable" argument set to false).
520+
`
521+
]);
522+
});
523+
524+
it('succeeds when queries do not require multiple calls to mutation field', () => {
525+
const subgraphA = {
526+
name: 'A',
527+
typeDefs: gql`
528+
type Query {
529+
dummy: Int
530+
}
531+
532+
type Mutation {
533+
f: F @shareable
534+
}
535+
536+
type F @key(fields: "id") {
537+
id: ID!
538+
x: Int
539+
}
540+
`
541+
};
542+
const subgraphB = {
543+
name: 'B',
544+
typeDefs: gql`
545+
type Mutation {
546+
f: F @shareable
547+
}
548+
549+
type F @key(fields: "id", resolvable: false) {
550+
id: ID!
551+
y: Int
552+
}
553+
`
554+
};
555+
556+
const result = composeAsFed2Subgraphs([subgraphA, subgraphB]);
557+
expect(result.errors).toBeUndefined();
558+
});
559+
});
560+
416561
describe('other validation errors', () => {
417562

418563
it('errors when maxValidationSubgraphPaths is exceeded', () => {

0 commit comments

Comments
 (0)