File tree Expand file tree Collapse file tree 3 files changed +86
-0
lines changed
src/supergraph/validation/rules/satisfiablity Expand file tree Collapse file tree 3 files changed +86
-0
lines changed Original file line number Diff line number Diff line change 1+ ---
2+ " @theguild/federation-composition " : patch
3+ ---
4+
5+ Fix failing satisfiability check for interface types.
Original file line number Diff line number Diff line change @@ -685,5 +685,72 @@ testImplementations((api) => {
685685 test . skip ( `several interfaces and several interface objects. Should succeed` , ( ) => { } ) ;
686686 } ) ;
687687 } ) ;
688+
689+ test ( "satisfiability with @interfaceObject" , ( ) => {
690+ const result = api . composeServices ( [
691+ {
692+ name : "a" ,
693+ typeDefs : parse ( /* GraphQL */ `
694+ type Query {
695+ book: Book!
696+ }
697+
698+ interface Media @key(fields: "id") {
699+ id: ID!
700+ }
701+
702+ type Book implements Media @key(fields: "id") {
703+ id: ID!
704+ isbn: String!
705+ }
706+
707+ extend schema
708+ @link(
709+ url: "https://specs.apollo.dev/federation/v2.3"
710+ import: ["@key"]
711+ )
712+ ` ) ,
713+ } ,
714+ {
715+ name : "b" ,
716+ typeDefs : parse ( /* GraphQL */ `
717+ type Media @key(fields: "id") @interfaceObject {
718+ id: ID!
719+ }
720+
721+ type Query {
722+ topRatedMedia: [Media!]!
723+ }
724+
725+ extend schema
726+ @link(
727+ url: "https://specs.apollo.dev/federation/v2.3"
728+ import: ["@key", "@interfaceObject"]
729+ )
730+ ` ) ,
731+ } ,
732+ {
733+ name : "c" ,
734+ typeDefs : parse ( /* GraphQL */ `
735+ type Query {
736+ cBook: Book
737+ }
738+
739+ type Book @key(fields: "id") {
740+ id: ID!
741+ }
742+
743+ extend schema
744+ @link(
745+ url: "https://specs.apollo.dev/federation/v2.3"
746+ import: ["@key"]
747+ )
748+ ` ) ,
749+ } ,
750+ ] ) ;
751+
752+ // console.log(api.library, result.errors);
753+ expect ( result . errors ) . toBe ( undefined ) ;
754+ } ) ;
688755 } ) ;
689756} ) ;
Original file line number Diff line number Diff line change @@ -260,6 +260,20 @@ export class PathFinder {
260260 return ;
261261 }
262262
263+ // We can skip the edge in case the the graph interface implementation does not provide the field.
264+ if ( edge . tail . typeState ?. kind === "interface" ) {
265+ const fieldInEdge = edge . tail . typeState . fields
266+ . get ( fieldName )
267+ ?. byGraph . get ( edge . tail . graphId ) ;
268+
269+ if ( fieldInEdge === undefined ) {
270+ this . logger . groupEnd (
271+ ( ) => "Ignore edge: tail type does not have this field" ,
272+ ) ;
273+ return ;
274+ }
275+ }
276+
263277 // A huge win for performance, is when you do less work :D
264278 // We can ignore an edge that has already been visited with the same key fields / requirements.
265279 // The way entity-move edges are created, where every graph points to every other graph:
You can’t perform that action at this time.
0 commit comments