Skip to content

Commit

Permalink
fix: tweaked optimization pre-condition
Browse files Browse the repository at this point in the history
  • Loading branch information
id-ilych committed Jun 23, 2020
1 parent 15ac1cc commit 8eb655b
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,58 @@ expect.addSnapshotSerializer(astSerializer);
expect.addSnapshotSerializer(queryPlanSerializer);

const videos = [{ id: 1, url: 'https://foobar.com/videos/1' }];
const articles = [{ id: 1, url: 'https://foobar.com/articles/1' }];
const news = [{ id: 1, url: 'https://foobar.com/news/1' }];
const reviews = [{ id: 1, url: 'https://foobar.com/reviews/1' }];
const audios = [{ id: 1, audioUrl: 'https://foobar.com/audios/1' }];

const contentService: ServiceDefinitionModule = {
name: 'contentService',
typeDefs: gql`
type Query {
content: [Content!]!
articles: [Article!]!
}
union Content = Video | Article | Audio
union Content = Video | News | Audio
union Article = News | Review
extend type Video @key(fields: "id") {
id: ID @external
}
extend type Audio @key(fields: "id") {
id: ID @external
}
extend type Article @key(fields: "id") {
extend type News @key(fields: "id") {
id: ID @external
}
extend type Review @key(fields: "id") {
id: ID @external
}
`,
resolvers: {
Query: {
content() {
return [
...articles.map((a) => ({ ...a, type: 'Article' })),
...news.map((a) => ({ ...a, type: 'News' })),
...audios.map(({ id }) => ({ id, type: 'Audio' })),
...videos.map(({ id }) => ({ id, type: 'Video' })),
];
},
articles() {
return [
...news.map((a) => ({ ...a, type: 'News' })),
...reviews.map(({ id }) => ({ id, type: 'Review' })),
];
},
},
Content: {
__resolveType(object) {
return object.type;
},
},
Article: {
__resolveType(object) {
return object.type;
},
},
},
};

Expand All @@ -50,17 +67,30 @@ const articleService: ServiceDefinitionModule = {
interface WebResource {
url: String
}
type Article implements WebResource @key(fields: "id") {
type News implements WebResource @key(fields: "id") {
id: ID
url: String
}
type Review implements WebResource @key(fields: "id") {
id: ID
url: String
}
`,
resolvers: {
Article: {
News: {
__resolveReference(object) {
return articles.find(
(article) => article.id === parseInt(object.id, 10),
);
return news.find((news) => news.id === parseInt(object.id, 10));
},
id(object) {
return object.id;
},
url(object) {
return object.url;
},
},
Review: {
__resolveReference(object) {
return reviews.find((review) => review.id === parseInt(object.id, 10));
},
id(object) {
return object.id;
Expand Down Expand Up @@ -132,6 +162,11 @@ it('handles unions from different services which implements value interfaces', a
url: audioUrl
}
}
articles {
... on WebResource {
url
}
}
}
`;

Expand All @@ -154,7 +189,7 @@ it('handles unions from different services which implements value interfaces', a
__typename
id
}
... on Article {
... on News {
__typename
id
}
Expand All @@ -163,6 +198,17 @@ it('handles unions from different services which implements value interfaces', a
id
}
}
articles {
__typename
... on News {
__typename
id
}
... on Review {
__typename
id
}
}
}
},
Parallel {
Expand All @@ -184,13 +230,13 @@ it('handles unions from different services which implements value interfaces', a
Flatten(path: "content.@") {
Fetch(service: "articleService") {
{
... on Article {
... on News {
__typename
id
}
} =>
{
... on Article {
... on News {
url
}
}
Expand All @@ -211,15 +257,41 @@ it('handles unions from different services which implements value interfaces', a
}
},
},
Flatten(path: "articles.@") {
Fetch(service: "articleService") {
{
... on News {
__typename
id
}
... on Review {
__typename
id
}
} =>
{
... on News {
url
}
... on Review {
url
}
}
},
},
},
},
}
`);
expect(data).toEqual({
content: [
{ url: 'https://foobar.com/articles/1' },
{ url: 'https://foobar.com/news/1' },
{ url: 'https://foobar.com/audios/1' },
{ url: 'https://foobar.com/videos/1' },
],
articles: [
{ url: 'https://foobar.com/news/1' },
{ url: 'https://foobar.com/reviews/1' },
],
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,24 @@ expect.addSnapshotSerializer(astSerializer);
expect.addSnapshotSerializer(queryPlanSerializer);

const videos = [{ id: 1, url: 'https://foobar.com/videos/1' }];
const articles = [{ id: 1, url: 'https://foobar.com/articles/1' }];
const news = [{ id: 1, url: 'https://foobar.com/news/1' }];
const reviews = [{ id: 1, url: 'https://foobar.com/reviews/1' }];
const audios = [{ id: 1, audioUrl: 'https://foobar.com/audios/1' }];

const contentService: ServiceDefinitionModule = {
name: 'contentService',
typeDefs: gql`
type Query {
content: [Content!]!
articles: [Article!]!
}
union Content = Video | Article | Audio
type Article implements WebResource @key(fields: "id") {
union Content = Video | News | Audio
union Article = News | Review
type News implements WebResource @key(fields: "id") {
id: ID
url: String
}
type Review implements WebResource @key(fields: "id") {
id: ID
url: String
}
Expand All @@ -34,21 +41,45 @@ const contentService: ServiceDefinitionModule = {
Query: {
content() {
return [
...articles.map((a) => ({ ...a, type: 'Article' })),
...news.map((a) => ({ ...a, type: 'News' })),
...audios.map(({ id }) => ({ id, type: 'Audio' })),
...videos.map(({ id }) => ({ id, type: 'Video' })),
];
},
articles() {
return [
...news.map(a => ({ ...a, type: 'News'})),
...reviews.map(a => ({ ...a, type: 'Review'})),
]
}
},
Content: {
__resolveType(object) {
return object.type;
},
},
Article: {
__resolveType(object) {
return object.type;
},
},
News: {
__resolveReference(object) {
return articles.find(
(article) => article.id === parseInt(object.id, 10),
return news.find(
(news) => news.id === parseInt(object.id, 10),
);
},
id(object) {
return object.id;
},
url(object) {
return object.url;
},
},
Review: {
__resolveReference(object) {
return reviews.find(
(review) => review.id === parseInt(object.id, 10),
);
},
id(object) {
Expand Down Expand Up @@ -121,6 +152,11 @@ it('handles unions from different services which implements value interfaces', a
url: audioUrl
}
}
articles {
... on WebResource {
url
}
}
}
`;

Expand All @@ -142,14 +178,20 @@ it('handles unions from different services which implements value interfaces', a
__typename
id
}
... on Article {
... on News {
url
}
... on Audio {
__typename
id
}
}
articles {
__typename
... on WebResource {
url
}
}
}
},
Parallel {
Expand Down Expand Up @@ -189,9 +231,13 @@ it('handles unions from different services which implements value interfaces', a
`);
expect(data).toEqual({
content: [
{ url: 'https://foobar.com/articles/1' },
{ url: 'https://foobar.com/news/1' },
{ url: 'https://foobar.com/audios/1' },
{ url: 'https://foobar.com/videos/1' },
],
articles: [
{ url: 'https://foobar.com/news/1' },
{ url: 'https://foobar.com/reviews/1' },
]
});
});
25 changes: 19 additions & 6 deletions packages/apollo-gateway/src/buildQueryPlan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -576,13 +576,26 @@ function splitFields(

// With no extending field definitions, we can engage the optimization
if (hasNoExtendingFieldDefs) {
const parentTypeOwningService = context.getOwningService((field as Field<GraphQLObjectType>).scope.parentType, fieldDef);
if (scope.possibleTypes.every(t => context.getOwningService(t, fieldDef) === parentTypeOwningService)) {
const group = groupForField(field as Field<GraphQLObjectType>);
group.fields.push(
completeField(context, scope, group, path, fieldsForResponseName)
const findEnclosingService = (scope?: Scope<GraphQLCompositeType>): string | null => {
if (!scope) {
return null;
}
const service = context.getOwningService(scope.parentType as GraphQLObjectType, fieldDef)
return service || findEnclosingService(scope.enclosingScope);
};
const currentService = findEnclosingService(field.scope);
if (currentService) {
const allPossibleTypesAreLocal = scope.possibleTypes.every(
possibleType =>
context.getOwningService(possibleType, fieldDef) === currentService
);
continue;
if (allPossibleTypesAreLocal) {
const group = groupForField(field as Field<GraphQLObjectType>);
group.fields.push(
completeField(context, scope, group, path, fieldsForResponseName)
);
continue;
}
}
}

Expand Down

0 comments on commit 8eb655b

Please sign in to comment.