Skip to content

Commit 9eee255

Browse files
authored
fix(batch-delegate): respect the parent type name (#5998)
* fix(batch-delegate): respect the parent type name for the batch delegation * Use returnType * Add tests * Fix test
1 parent 6cf507f commit 9eee255

File tree

10 files changed

+242
-67
lines changed

10 files changed

+242
-67
lines changed

.changeset/tricky-mice-crash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@graphql-tools/batch-delegate": patch
3+
---
4+
5+
Add parentType name to the batch delegation key

packages/batch-delegate/src/getLoader.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ export function getLoader<K = any, V = any, C = K>(
8787

8888
let cacheKey = fieldName;
8989

90+
if (info.returnType) {
91+
const namedType = getNamedType(info.returnType);
92+
cacheKey += '@' + namedType.name;
93+
}
94+
9095
if (selectionSet != null) {
9196
cacheKey += memoizedPrint(selectionSet);
9297
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
type Query {
2+
discounts(first: Int = 5): [Discount]
3+
}
4+
5+
extend type Product @key(fields: "upc") {
6+
upc: String! @external
7+
discounts: [Discount!]!
8+
}
9+
10+
extend type Category @key(fields: "id") {
11+
id: ID! @external
12+
discounts: [Discount!]!
13+
}
14+
15+
type Discount @key(fields: "id") {
16+
id: ID!
17+
discount: Int!
18+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { readFileSync } from 'fs';
2+
import { join } from 'path';
3+
import { IResolvers } from '@graphql-tools/utils';
4+
5+
export const typeDefs = readFileSync(join(__dirname, './discount.graphql'), 'utf8');
6+
7+
export const resolvers: IResolvers = {
8+
Product: {
9+
__resolveReference(object) {
10+
return {
11+
...object,
12+
discounts,
13+
};
14+
},
15+
},
16+
Category: {
17+
__resolveReference(object) {
18+
return {
19+
...object,
20+
discounts,
21+
};
22+
},
23+
},
24+
Discount: {
25+
__resolveReference(object) {
26+
return {
27+
...object,
28+
...discounts.find(discount => discount.id === object.id),
29+
};
30+
},
31+
},
32+
Query: {
33+
discounts(_, args) {
34+
return discounts.slice(0, args.first);
35+
},
36+
},
37+
};
38+
const discounts = [
39+
{ id: '1', discount: 10 },
40+
{ id: '2', discount: 20 },
41+
{ id: '3', discount: 30 },
42+
];

packages/federation/test/fixtures/gateway/products/index.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,52 @@ export const typeDefs = readFileSync(join(__dirname, './products.graphql'), 'utf
66

77
const listSize = parseInt(process.env['PRODUCTS_SIZE'] || '3');
88

9+
const categories = [
10+
{
11+
id: 'c_1',
12+
name: 'Furniture',
13+
},
14+
{
15+
id: 'c_2',
16+
name: 'Kitchen',
17+
},
18+
];
19+
920
const definedProducts = [
1021
{
1122
upc: '1',
1223
name: 'Table',
1324
price: 899,
1425
weight: 100,
26+
categories: [categories[0]],
1527
},
1628
{
1729
upc: '2',
1830
name: 'Couch',
1931
price: 1299,
2032
weight: 1000,
33+
categories: [categories[0]],
2134
},
2235
{
2336
upc: '3',
2437
name: 'Chair',
2538
price: 54,
2639
weight: 50,
40+
categories: [categories[0]],
41+
},
42+
{
43+
upc: '4',
44+
name: 'Knife',
45+
price: 54,
46+
weight: 50,
47+
categories: [categories[1]],
48+
},
49+
{
50+
id: 'p_5',
51+
name: 'Spoon',
52+
price: 54,
53+
weight: 50,
54+
categories: [categories[1]],
2755
},
2856
];
2957
const products = [...Array(listSize)].map((_, index) => definedProducts[index % 3]);
@@ -34,6 +62,14 @@ export const resolvers: IResolvers = {
3462
return products.find(product => product.upc === object.upc);
3563
},
3664
},
65+
Category: {
66+
__resolveReference(object) {
67+
return {
68+
...object,
69+
...categories.find(category => category.id === object.id),
70+
};
71+
},
72+
},
3773
Query: {
3874
topProducts(_, args) {
3975
return args.first ? products.slice(0, args.first) : products;

packages/federation/test/fixtures/gateway/products/products.graphql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,10 @@ type Product @key(fields: "upc") {
77
name: String
88
price: Int
99
weight: Int
10+
categories: [Category!]!
11+
}
12+
13+
type Category @key(fields: "id") {
14+
id: ID!
15+
name: String!
1016
}
Lines changed: 62 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,98 @@
11
schema
2-
@link(url: "https://specs.apollo.dev/link/v1.0")
3-
@link(url: "https://specs.apollo.dev/join/v0.3", for: EXECUTION) {
2+
@core(feature: "https://specs.apollo.dev/core/v0.2")
3+
@core(feature: "https://specs.apollo.dev/join/v0.1", for: EXECUTION) {
44
query: Query
55
}
66

7-
directive @join__enumValue(graph: join__Graph!) repeatable on ENUM_VALUE
7+
directive @core(as: String, feature: String!, for: core__Purpose) repeatable on SCHEMA
88

99
directive @join__field(
1010
graph: join__Graph
11-
requires: join__FieldSet
1211
provides: join__FieldSet
13-
type: String
14-
external: Boolean
15-
override: String
16-
usedOverridden: Boolean
17-
) repeatable on FIELD_DEFINITION | INPUT_FIELD_DEFINITION
12+
requires: join__FieldSet
13+
) on FIELD_DEFINITION
1814

1915
directive @join__graph(name: String!, url: String!) on ENUM_VALUE
2016

21-
directive @join__implements(
22-
graph: join__Graph!
23-
interface: String!
24-
) repeatable on OBJECT | INTERFACE
25-
26-
directive @join__type(
27-
graph: join__Graph!
28-
key: join__FieldSet
29-
extension: Boolean! = false
30-
resolvable: Boolean! = true
31-
isInterfaceObject: Boolean! = false
32-
) repeatable on OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT | SCALAR
33-
34-
directive @join__unionMember(graph: join__Graph!, member: String!) repeatable on UNION
35-
36-
directive @link(
37-
url: String
38-
as: String
39-
for: link__Purpose
40-
import: [link__Import]
41-
) repeatable on SCHEMA
17+
directive @join__owner(graph: join__Graph!) on INTERFACE | OBJECT
4218

43-
scalar join__FieldSet
19+
directive @join__type(graph: join__Graph!, key: join__FieldSet) repeatable on INTERFACE | OBJECT
4420

45-
enum join__Graph {
46-
accounts @join__graph(name: "accounts", url: "http://accounts:4001/graphql")
47-
inventory @join__graph(name: "inventory", url: "http://inventory:4002/graphql")
48-
products @join__graph(name: "products", url: "http://products:4003/graphql")
49-
reviews @join__graph(name: "reviews", url: "http://reviews:4004/graphql")
21+
type Category
22+
@join__owner(graph: products)
23+
@join__type(graph: products, key: "id")
24+
@join__type(graph: discount, key: "id") {
25+
discounts: [Discount!]! @join__field(graph: discount)
26+
id: ID! @join__field(graph: products)
27+
name: String! @join__field(graph: products)
5028
}
5129

52-
scalar link__Import
53-
54-
enum link__Purpose {
55-
"""
56-
`SECURITY` features provide metadata necessary to securely resolve fields.
57-
"""
58-
SECURITY
59-
60-
"""
61-
`EXECUTION` features provide metadata necessary for operation execution.
62-
"""
63-
EXECUTION
30+
type Discount @join__owner(graph: discount) @join__type(graph: discount, key: "id") {
31+
discount: Int! @join__field(graph: discount)
32+
id: ID! @join__field(graph: discount)
6433
}
6534

6635
type Product
67-
@join__type(graph: inventory, key: "upc")
36+
@join__owner(graph: products)
6837
@join__type(graph: products, key: "upc")
38+
@join__type(graph: discount, key: "upc")
39+
@join__type(graph: inventory, key: "upc")
6940
@join__type(graph: reviews, key: "upc") {
70-
upc: String!
71-
weight: Int @join__field(graph: inventory, external: true) @join__field(graph: products)
72-
price: Int @join__field(graph: inventory, external: true) @join__field(graph: products)
41+
categories: [Category!]! @join__field(graph: products)
42+
discounts: [Discount!]! @join__field(graph: discount)
7343
inStock: Boolean @join__field(graph: inventory)
74-
shippingEstimate: Int @join__field(graph: inventory, requires: "price weight")
7544
name: String @join__field(graph: products)
45+
price: Int @join__field(graph: products)
7646
reviews: [Review] @join__field(graph: reviews)
47+
shippingEstimate: Int @join__field(graph: inventory, requires: "price weight")
48+
upc: String! @join__field(graph: products)
49+
weight: Int @join__field(graph: products)
7750
}
7851

79-
type Query
80-
@join__type(graph: accounts)
81-
@join__type(graph: inventory)
82-
@join__type(graph: products)
83-
@join__type(graph: reviews) {
52+
type Query {
53+
discounts(first: Int = 5): [Discount] @join__field(graph: discount)
8454
me: User @join__field(graph: accounts)
85-
users: [User] @join__field(graph: accounts)
8655
topProducts(first: Int): [Product] @join__field(graph: products)
56+
users: [User] @join__field(graph: accounts)
8757
}
8858

89-
type Review @join__type(graph: reviews, key: "id") {
90-
id: ID!
91-
body: String
92-
product: Product
59+
type Review @join__owner(graph: reviews) @join__type(graph: reviews, key: "id") {
9360
author: User @join__field(graph: reviews, provides: "username")
61+
body: String @join__field(graph: reviews)
62+
id: ID! @join__field(graph: reviews)
63+
product: Product @join__field(graph: reviews)
9464
}
9565

96-
type User @join__type(graph: accounts, key: "id") @join__type(graph: reviews, key: "id") {
97-
id: ID!
98-
name: String @join__field(graph: accounts)
99-
username: String @join__field(graph: accounts) @join__field(graph: reviews, external: true)
66+
type User
67+
@join__owner(graph: accounts)
68+
@join__type(graph: accounts, key: "id")
69+
@join__type(graph: reviews, key: "id") {
10070
birthDate: String @join__field(graph: accounts)
71+
id: ID! @join__field(graph: accounts)
72+
name: String @join__field(graph: accounts)
10173
numberOfReviews: Int @join__field(graph: reviews)
10274
reviews: [Review] @join__field(graph: reviews)
75+
username: String @join__field(graph: accounts)
76+
}
77+
78+
enum core__Purpose {
79+
"""
80+
`EXECUTION` features provide metadata necessary to for operation execution.
81+
"""
82+
EXECUTION
83+
84+
"""
85+
`SECURITY` features provide metadata necessary to securely resolve fields.
86+
"""
87+
SECURITY
88+
}
89+
90+
scalar join__FieldSet
91+
92+
enum join__Graph {
93+
accounts @join__graph(name: "accounts", url: "http://www.accounts.com")
94+
discount @join__graph(name: "discount", url: "http://www.discount.com")
95+
inventory @join__graph(name: "inventory", url: "http://www.inventory.com")
96+
products @join__graph(name: "products", url: "http://www.products.com")
97+
reviews @join__graph(name: "reviews", url: "http://www.reviews.com")
10398
}

packages/federation/test/fixtures/gateway/supergraph.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,7 @@ subgraphs:
1515
routing_url: http://www.inventory.com
1616
schema:
1717
file: ./inventory/inventory.graphql
18+
discount:
19+
routing_url: http://www.discount.com
20+
schema:
21+
file: ./discount/discount.graphql

0 commit comments

Comments
 (0)