Skip to content

Commit 94b8f68

Browse files
pozylonfreiksenet
authored andcommitted
Fix fragment filtering edge case when a type implements multiple interfaces (#546)
* add failing test for multi interface issue * interface / interface always implements an abstract type * changelog * the linter always should be happy * Update CHANGELOG.md
1 parent 608414b commit 94b8f68

File tree

4 files changed

+125
-2
lines changed

4 files changed

+125
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
### vNEXT
44

5+
* Fix a bug where inline fragments got filtered in merged schemas when a type implemented multiple interfaces [PR #546](https://github.com/apollographql/graphql-tools/pull/546)
56
* IEnumResolver value can be a `number` type
67

78
### v2.17.0

src/stitching/delegateToSchema.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,11 @@ function implementsAbstractType(
510510
child instanceof GraphQLObjectType
511511
) {
512512
return child.getInterfaces().indexOf(parent) !== -1;
513+
} else if (
514+
parent instanceof GraphQLInterfaceType &&
515+
child instanceof GraphQLInterfaceType
516+
) {
517+
return true;
513518
} else if (
514519
parent instanceof GraphQLUnionType &&
515520
child instanceof GraphQLObjectType

src/test/testMergeSchemas.ts

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,36 @@ import {
1313
import mergeSchemas from '../stitching/mergeSchemas';
1414
import {
1515
propertySchema as localPropertySchema,
16+
productSchema as localProductSchema,
1617
bookingSchema as localBookingSchema,
1718
subscriptionSchema as localSubscriptionSchema,
1819
remoteBookingSchema,
1920
remotePropertySchema,
21+
remoteProductSchema,
2022
subscriptionPubSub,
2123
subscriptionPubSubTrigger,
2224
} from './testingSchemas';
2325
import { forAwaitEach } from 'iterall';
2426
import { makeExecutableSchema } from '../schemaGenerator';
2527

2628
const testCombinations = [
27-
{ name: 'local', booking: localBookingSchema, property: localPropertySchema },
29+
{
30+
name: 'local',
31+
booking: localBookingSchema,
32+
property: localPropertySchema,
33+
product: localProductSchema,
34+
},
2835
{
2936
name: 'remote',
3037
booking: remoteBookingSchema,
3138
property: remotePropertySchema,
39+
product: remoteProductSchema,
3240
},
3341
{
3442
name: 'hybrid',
3543
booking: localBookingSchema,
3644
property: remotePropertySchema,
45+
product: localProductSchema,
3746
},
3847
];
3948

@@ -101,7 +110,6 @@ let linkSchema = `
101110
id: ID!
102111
}
103112
104-
105113
extend type Booking implements Node {
106114
"""
107115
The property of the booking.
@@ -222,16 +230,19 @@ testCombinations.forEach(async combination => {
222230
describe('merging ' + combination.name, () => {
223231
let mergedSchema: GraphQLSchema,
224232
propertySchema: GraphQLSchema,
233+
productSchema: GraphQLSchema,
225234
bookingSchema: GraphQLSchema;
226235

227236
before(async () => {
228237
propertySchema = await combination.property;
229238
bookingSchema = await combination.booking;
239+
productSchema = await combination.product;
230240

231241
mergedSchema = mergeSchemas({
232242
schemas: [
233243
propertySchema,
234244
bookingSchema,
245+
productSchema,
235246
scalarTest,
236247
enumTest,
237248
linkSchema,
@@ -1820,6 +1831,39 @@ bookingById(id: $b1) {
18201831
// });
18211832
// });
18221833

1834+
it('multi-interface filter', async () => {
1835+
const result = await graphql(
1836+
mergedSchema,
1837+
`
1838+
query {
1839+
products {
1840+
id
1841+
__typename
1842+
... on Sellable {
1843+
price
1844+
}
1845+
}
1846+
}
1847+
`,
1848+
);
1849+
1850+
expect(result).to.deep.equal({
1851+
data: {
1852+
products: [
1853+
{
1854+
id: 'pd1',
1855+
__typename: 'SimpleProduct',
1856+
price: 100,
1857+
},
1858+
{
1859+
id: 'pd2',
1860+
__typename: 'DownloadableProduct',
1861+
},
1862+
],
1863+
},
1864+
});
1865+
});
1866+
18231867
it('arbitrary transforms that return interfaces', async () => {
18241868
const result = await graphql(
18251869
mergedSchema,

src/test/testingSchemas.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ export type Property = {
2525
};
2626
};
2727

28+
export type Product = {
29+
id: string;
30+
price?: number;
31+
url?: string,
32+
type: string,
33+
};
34+
2835
export type Booking = {
2936
id: string;
3037
propertyId: string;
@@ -49,10 +56,23 @@ export type Vehicle = {
4956

5057
export const sampleData: {
5158
Property: { [key: string]: Property };
59+
Product: { [key: string]: Product };
5260
Booking: { [key: string]: Booking };
5361
Customer: { [key: string]: Customer };
5462
Vehicle: { [key: string]: Vehicle };
5563
} = {
64+
Product: {
65+
pd1: {
66+
id: 'pd1',
67+
type: 'simple',
68+
price: 100,
69+
},
70+
pd2: {
71+
id: 'pd2',
72+
type: 'download',
73+
url: 'https://graphql.org',
74+
},
75+
},
5676
Property: {
5777
p1: {
5878
id: 'p1',
@@ -349,6 +369,53 @@ const propertyResolvers: IResolvers = {
349369
},
350370
};
351371

372+
const productTypeDefs = `
373+
interface Product {
374+
id: ID!
375+
}
376+
377+
interface Sellable {
378+
price: Int!
379+
}
380+
381+
interface Downloadable {
382+
url: String!
383+
}
384+
385+
type SimpleProduct implements Product, Sellable {
386+
id: ID!
387+
price: Int!
388+
}
389+
390+
type DownloadableProduct implements Product, Downloadable {
391+
id: ID!
392+
url: String!
393+
}
394+
395+
type Query {
396+
products: [Product]
397+
}
398+
`;
399+
400+
const productResolvers: IResolvers = {
401+
Query: {
402+
products(root) {
403+
const list = values(sampleData.Product);
404+
return list;
405+
},
406+
},
407+
408+
Product: {
409+
__resolveType(obj) {
410+
if (obj.type === 'simple') {
411+
return 'SimpleProduct';
412+
} else {
413+
return 'DownloadableProduct';
414+
}
415+
},
416+
},
417+
};
418+
352419
const customerAddressTypeDef = `
353420
type Customer implements Person {
354421
id: ID!
@@ -551,6 +618,11 @@ export const propertySchema: GraphQLSchema = makeExecutableSchema({
551618
resolvers: propertyResolvers,
552619
});
553620

621+
export const productSchema: GraphQLSchema = makeExecutableSchema({
622+
typeDefs: productTypeDefs,
623+
resolvers: productResolvers,
624+
});
625+
554626
export const bookingSchema: GraphQLSchema = makeExecutableSchema({
555627
typeDefs: bookingAddressTypeDefs,
556628
resolvers: bookingResolvers,
@@ -648,6 +720,7 @@ async function makeExecutableSchemaFromFetcher(schema: GraphQLSchema) {
648720
}
649721

650722
export const remotePropertySchema = makeSchemaRemoteFromLink(propertySchema);
723+
export const remoteProductSchema = makeSchemaRemoteFromLink(productSchema);
651724
export const remoteBookingSchema = makeExecutableSchemaFromFetcher(
652725
bookingSchema,
653726
);

0 commit comments

Comments
 (0)