diff --git a/src/index.ts b/src/index.ts index c06f4a6..0411f27 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,6 +11,7 @@ import unavailableOverrideTestCase from "./test-cases/unavailable-override"; import overrideWithRequiresTestCase from "./test-cases/override-with-requires"; import simpleInaccessible from "./test-cases/simple-inaccessible"; import enumIntersection from "./test-cases/enum-intersection"; +import inputObjectIntersection from "./test-cases/input-object-intersection"; const testCases = [ unionIntersectionTestCase, @@ -25,6 +26,7 @@ const testCases = [ overrideWithRequiresTestCase, simpleInaccessible, enumIntersection, + inputObjectIntersection, ]; function routerFetch(request: Request) { diff --git a/src/supergraph.ts b/src/supergraph.ts index 52086c0..2c805c2 100644 --- a/src/supergraph.ts +++ b/src/supergraph.ts @@ -38,7 +38,13 @@ export function serve( return { id, createRoutes(router: ReturnType) { + let subgraphNames = new Set(); for (const subgraph of subgraphs) { + if (subgraphNames.has(subgraph.name)) { + throw new Error(`Duplicate subgraph name ${subgraph.name}`); + } + + subgraphNames.add(subgraph.name); subgraph.createRoutes(id, router); } diff --git a/src/test-cases/input-object-intersection/a.subgraph.ts b/src/test-cases/input-object-intersection/a.subgraph.ts new file mode 100644 index 0000000..d1ab190 --- /dev/null +++ b/src/test-cases/input-object-intersection/a.subgraph.ts @@ -0,0 +1,47 @@ +import { createSubgraph } from "../../subgraph"; +import { users } from "./data"; + +export default createSubgraph("a", { + typeDefs: /* GraphQL */ ` + extend schema + @link( + url: "https://specs.apollo.dev/federation/v2.3" + import: ["@key", "@shareable"] + ) + + input UsersFilter { + first: Int! + } + + type User @key(fields: "id") { + id: ID! + name: String! @shareable + } + + type Query { + usersInA(filter: UsersFilter!): [User!] + } + `, + resolvers: { + Query: { + usersInA(_: {}, { filter }: { filter: { first: number } }) { + if ("offset" in filter) { + return []; + } + + return users; + }, + }, + User: { + __resolveReference(key: { id: string }) { + const user = users.find((user) => user.id === key.id); + + if (!user) { + return null; + } + + return user; + }, + }, + }, +}); diff --git a/src/test-cases/input-object-intersection/b.subgraph.ts b/src/test-cases/input-object-intersection/b.subgraph.ts new file mode 100644 index 0000000..76308f7 --- /dev/null +++ b/src/test-cases/input-object-intersection/b.subgraph.ts @@ -0,0 +1,51 @@ +import { createSubgraph } from "../../subgraph"; +import { users } from "./data"; + +export default createSubgraph("b", { + typeDefs: /* GraphQL */ ` + extend schema + @link( + url: "https://specs.apollo.dev/federation/v2.3" + import: ["@key", "@shareable"] + ) + + input UsersFilter { + offset: Int + first: Int! + } + + type User @key(fields: "id") { + id: ID! + name: String! @shareable + } + + type Query { + usersInB(filter: UsersFilter!): [User!] + } + `, + resolvers: { + Query: { + usersInB( + _: {}, + { filter }: { filter: { offset?: number; first: number } } + ) { + if (typeof filter.offset !== "undefined") { + return []; + } + + return users; + }, + }, + User: { + __resolveReference(key: { id: string }) { + const user = users.find((user) => user.id === key.id); + + if (!user) { + return null; + } + + return user; + }, + }, + }, +}); diff --git a/src/test-cases/input-object-intersection/data.ts b/src/test-cases/input-object-intersection/data.ts new file mode 100644 index 0000000..c805248 --- /dev/null +++ b/src/test-cases/input-object-intersection/data.ts @@ -0,0 +1,10 @@ +export const users = [ + { + id: "u1", + name: "u1-name", + }, + { + id: "u2", + name: "u2-name", + }, +]; diff --git a/src/test-cases/input-object-intersection/index.ts b/src/test-cases/input-object-intersection/index.ts new file mode 100644 index 0000000..f8d2500 --- /dev/null +++ b/src/test-cases/input-object-intersection/index.ts @@ -0,0 +1,6 @@ +import { serve } from "../../supergraph"; +import a from "./a.subgraph"; +import b from "./b.subgraph"; +import test from "./test"; + +export default serve("input-object-intersection", [a, b], test); diff --git a/src/test-cases/input-object-intersection/test.ts b/src/test-cases/input-object-intersection/test.ts new file mode 100644 index 0000000..0cd1faf --- /dev/null +++ b/src/test-cases/input-object-intersection/test.ts @@ -0,0 +1,49 @@ +import { createTest } from "../../test"; + +export default [ + createTest( + /* GraphQL */ ` + query { + usersInA(filter: { first: 1 }) { + id + } + } + `, + { + data: { + usersInA: [ + { + id: "u1", + }, + { + id: "u2", + }, + ], + }, + } + ), + createTest( + /* GraphQL */ ` + query { + usersInA(filter: { first: 1, offset: 2 }) { + id + } + } + `, + { + errors: true, + } + ), + createTest( + /* GraphQL */ ` + query { + usersInB(filter: { first: 1, offset: 2 }) { + id + } + } + `, + { + errors: true, + } + ), +];