Skip to content

Commit 8c5bc0c

Browse files
n1ru4lkamilkisiela
andauthored
fix: @provides with union type selection set (#147)
```graphql # A extend schema @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key", "@Shareable", "@provides", "@external"]) type Query { unouser: User } type User @key(fields: "id") { id: ID! name: String! age: String! } ``` ```graphql # B extend schema @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key", "@provides", "@Shareable", "@external"]) type Query { userOrCar: UserOrCar @provides(fields: "... on User { id } ") } union UserOrCar = User | Car type User { id: ID! @external } type Car { uid: ID! } ``` ![graphviz](https://github.com/user-attachments/assets/fe8d022e-7988-4dfc-8b3f-8e79b906c611) --------- Co-authored-by: Kamil Kisiela <[email protected]>
1 parent 9bd8016 commit 8c5bc0c

File tree

8 files changed

+537
-337
lines changed

8 files changed

+537
-337
lines changed

.changeset/sour-spiders-brush.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
"@theguild/federation-composition": patch
3+
---
4+
5+
Add support for `@provides` fragment selection sets on union type fields.
6+
7+
```graphql
8+
type Query {
9+
media: [Media] @shareable @provides(fields: "... on Book { title }")
10+
}
11+
union Media = Book | Movie
12+
```

__tests__/subgraph/errors/PROVIDES_ON_NON_OBJECT_FIELD.spec.ts

Lines changed: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import { expect, test } from "vitest";
2-
import { graphql, testVersions } from "../../shared/testkit.js";
2+
import {
3+
assertCompositionSuccess,
4+
graphql,
5+
testVersions,
6+
} from "../../shared/testkit.js";
37

48
testVersions((api, version) => {
59
test("PROVIDES_ON_NON_OBJECT_FIELD", () => {
@@ -47,4 +51,144 @@ testVersions((api, version) => {
4751
}),
4852
);
4953
});
54+
55+
test("PROVIDES_ON_NON_OBJECT_FIELD: is not raised for union field with fragment object type selection sets", () => {
56+
const errors = api.composeServices([
57+
{
58+
name: "users",
59+
typeDefs: graphql`
60+
extend schema
61+
@link(
62+
url: "https://specs.apollo.dev/federation/${version}"
63+
import: ["@key", "@provides", "@external"]
64+
)
65+
66+
type Query {
67+
result: ResultType
68+
}
69+
70+
type EntityA {
71+
field1: String @external
72+
field2: String @external
73+
}
74+
75+
type EntityB {
76+
field1: String @external
77+
field2: String @external
78+
field3: String @external
79+
}
80+
81+
union UnionType = EntityA | EntityB
82+
83+
type ResultType {
84+
results: [UnionType!]! @provides(fields: "... on EntityA { field1 field2 } ... on EntityB { field1 field2 field3 }")
85+
}
86+
`,
87+
},
88+
{
89+
name: "other",
90+
typeDefs: graphql`
91+
extend schema
92+
@link(
93+
url: "https://specs.apollo.dev/federation/${version}"
94+
import: ["@key", "@shareable"]
95+
)
96+
97+
type Query {
98+
a: EntityA
99+
b: EntityB
100+
}
101+
102+
union UnionType = EntityA | EntityB
103+
104+
type EntityA @key(fields: "field1") {
105+
field1: String @shareable
106+
field2: String @shareable
107+
}
108+
109+
type EntityB @key(fields: "field1") {
110+
field1: String @shareable
111+
field2: String @shareable
112+
field3: String @shareable
113+
}
114+
`,
115+
},
116+
]).errors;
117+
expect(errors).toEqual(undefined);
118+
});
119+
120+
test("PROVIDES_ON_NON_OBJECT_FIELD: is not raised for union field with fragment object type selection sets (variant)", () => {
121+
const result = api.composeServices([
122+
{
123+
name: "a",
124+
typeDefs: graphql`
125+
extend schema
126+
@link(
127+
url: "https://specs.apollo.dev/federation/v2.3"
128+
import: ["@key", "@shareable", "@external"]
129+
)
130+
131+
type Query {
132+
media: [Media] @shareable
133+
}
134+
135+
union Media = Book | Movie
136+
137+
type Book @key(fields: "id") {
138+
id: ID!
139+
}
140+
141+
type Movie @key(fields: "id") {
142+
id: ID!
143+
}
144+
`,
145+
},
146+
{
147+
name: "b",
148+
typeDefs: graphql`
149+
extend schema
150+
@link(
151+
url: "https://specs.apollo.dev/federation/v2.3"
152+
import: ["@key", "@shareable", "@provides", "@external"]
153+
)
154+
155+
type Query {
156+
media: [Media] @shareable @provides(fields: "... on Book { title }")
157+
}
158+
159+
union Media = Book | Movie
160+
161+
type Book @key(fields: "id") {
162+
id: ID!
163+
title: String @external
164+
}
165+
166+
type Movie @key(fields: "id") {
167+
id: ID!
168+
}
169+
`,
170+
},
171+
{
172+
name: "c",
173+
typeDefs: graphql`
174+
extend schema
175+
@link(
176+
url: "https://specs.apollo.dev/federation/v2.3"
177+
import: ["@key", "@shareable"]
178+
)
179+
180+
type Book @key(fields: "id") {
181+
id: ID!
182+
title: String @shareable
183+
}
184+
185+
type Movie @key(fields: "id") {
186+
id: ID!
187+
title: String @shareable
188+
}
189+
`,
190+
},
191+
]);
192+
assertCompositionSuccess(result);
193+
});
50194
});

__tests__/todo.spec.ts

Lines changed: 0 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -172,80 +172,4 @@ testImplementations((api) => {
172172
console.log(result.errors);
173173
assertCompositionSuccess(result);
174174
});
175-
176-
test.todo("provides-on-union", () => {
177-
const result = api.composeServices([
178-
{
179-
name: "a",
180-
typeDefs: parse(/* GraphQL */ `
181-
extend schema
182-
@link(
183-
url: "https://specs.apollo.dev/federation/v2.3"
184-
import: ["@key", "@shareable", "@external"]
185-
)
186-
187-
type Query {
188-
media: [Media] @shareable
189-
}
190-
191-
union Media = Book | Movie
192-
193-
type Book @key(fields: "id") {
194-
id: ID!
195-
}
196-
197-
type Movie @key(fields: "id") {
198-
id: ID!
199-
}
200-
`),
201-
},
202-
{
203-
name: "b",
204-
typeDefs: parse(/* GraphQL */ `
205-
extend schema
206-
@link(
207-
url: "https://specs.apollo.dev/federation/v2.3"
208-
import: ["@key", "@shareable", "@provides", "@external"]
209-
)
210-
211-
type Query {
212-
media: [Media] @shareable @provides(fields: "... on Book { title }")
213-
}
214-
215-
union Media = Book | Movie
216-
217-
type Book @key(fields: "id") {
218-
id: ID!
219-
title: String @external
220-
}
221-
222-
type Movie @key(fields: "id") {
223-
id: ID!
224-
}
225-
`),
226-
},
227-
{
228-
name: "c",
229-
typeDefs: parse(/* GraphQL */ `
230-
extend schema
231-
@link(
232-
url: "https://specs.apollo.dev/federation/v2.3"
233-
import: ["@key", "@shareable"]
234-
)
235-
236-
type Book @key(fields: "id") {
237-
id: ID!
238-
title: String @shareable
239-
}
240-
241-
type Movie @key(fields: "id") {
242-
id: ID!
243-
title: String @shareable
244-
}
245-
`),
246-
},
247-
]);
248-
console.log(result.errors);
249-
assertCompositionSuccess(result);
250-
});
251175
});

0 commit comments

Comments
 (0)