Skip to content

Commit c311d06

Browse files
author
Carlo Feliciano Aureus
committed
Support fragments while handling aliased entity keys
1 parent f8a9f81 commit c311d06

File tree

3 files changed

+145
-10
lines changed

3 files changed

+145
-10
lines changed

src/main/java/com/intuit/graphql/orchestrator/batch/EntityFetcherBatchLoader.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
import com.intuit.graphql.orchestrator.federation.metadata.FederationMetadata;
1313
import com.intuit.graphql.orchestrator.federation.metadata.KeyDirectiveMetadata;
1414
import com.intuit.graphql.orchestrator.schema.ServiceMetadata;
15+
import com.intuit.graphql.orchestrator.utils.SelectionCollector;
1516
import graphql.GraphQLContext;
1617
import graphql.execution.DataFetcherResult;
1718
import graphql.execution.MergedField;
1819
import graphql.introspection.Introspection;
1920
import graphql.language.Field;
21+
import graphql.language.FragmentDefinition;
2022
import graphql.language.InlineFragment;
2123
import graphql.language.SelectionSet;
2224
import graphql.language.TypeName;
@@ -25,14 +27,14 @@
2527
import graphql.schema.GraphQLTypeUtil;
2628
import java.util.ArrayList;
2729
import java.util.Collection;
30+
import java.util.Collections;
2831
import java.util.HashMap;
2932
import java.util.List;
3033
import java.util.Map;
3134
import java.util.Objects;
3235
import java.util.concurrent.CompletionStage;
3336
import java.util.stream.Collectors;
3437
import org.apache.commons.collections4.CollectionUtils;
35-
import org.apache.commons.collections4.MapUtils;
3638
import org.dataloader.BatchLoader;
3739

3840
public class EntityFetcherBatchLoader implements BatchLoader<DataFetchingEnvironment, DataFetcherResult<Object>> {
@@ -98,6 +100,7 @@ private List<String> generateRepresentationTemplate(FederationMetadata.EntityExt
98100
.build();
99101
}
100102

103+
101104
if(CollectionUtils.isNotEmpty(metadata.getRequiredFields(fieldName))) {
102105
metadata.getRequiredFields(fieldName)
103106
.stream()
@@ -169,11 +172,13 @@ private Map<String, Object> createRepresentation(
169172
*/
170173
private Map<String, String> buildkeyToAliasMap(DataFetchingEnvironment dataFetchingEnvironment) {
171174
MergedField parentField = dataFetchingEnvironment.getExecutionStepInfo().getParent().getField();
172-
return parentField.getSingleField().getSelectionSet().getSelections()
175+
176+
SelectionCollector selectionCollector = new SelectionCollector(dataFetchingEnvironment.getFragmentsByName());
177+
return selectionCollector.collectFields(parentField.getSingleField().getSelectionSet())
178+
.values()
173179
.stream()
174-
.filter(selection -> selection instanceof Field)
175-
.map(selection -> (Field) selection)
176180
.filter(field -> this.representationFieldTemplate.contains(field.getName()))
177181
.collect(Collectors.toMap(field -> field.getName(), field -> field.getAlias() == null? field.getName() : field.getAlias()));
178182
}
183+
179184
}

src/test/groovy/com/intuit/graphql/orchestrator/integration/federation/FederationQueryWithFieldSelectionsOnlySpec.groovy

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,6 @@ class FederationQueryWithFieldSelectionsOnlySpec extends BaseIntegrationTestSpec
117117
data: [
118118
_entities: [
119119
[
120-
__typename : "Author",
121-
id : "12345",
122120
(fnameField): "Charles"
123121
]
124122
]
@@ -212,17 +210,13 @@ class FederationQueryWithFieldSelectionsOnlySpec extends BaseIntegrationTestSpec
212210
(FNAME_ENTITY_FETCH_QUERY): [data: [
213211
_entities: [
214212
[
215-
__typename: "Author",
216-
id : "12345",
217213
firstName : "Charles"
218214
]
219215
]
220216
]],
221217
(LNAME_ENTITY_FETCH_QUERY): [data: [
222218
_entities: [
223219
[
224-
__typename: "Author",
225-
id : "12345",
226220
lastName : "Charles-LastName"
227221
]
228222
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package com.intuit.graphql.orchestrator.integration.federation
2+
3+
import com.google.common.collect.ImmutableMap
4+
import com.intuit.graphql.orchestrator.GraphQLOrchestrator
5+
import com.intuit.graphql.orchestrator.ServiceProvider
6+
import graphql.ExecutionInput
7+
import helpers.BaseIntegrationTestSpecification
8+
9+
class FederationQueryWithFragmentSpec extends BaseIntegrationTestSpecification {
10+
11+
GraphQLOrchestrator specUnderTest
12+
13+
private def bookSchema = '''
14+
type Query {
15+
bookById(id: ID): Book
16+
}
17+
18+
type Book {
19+
id: ID
20+
name: String
21+
pageCount: Int
22+
author: Author
23+
}
24+
25+
type Author @key(fields: "id") {
26+
id: String
27+
}
28+
'''
29+
30+
private def authorSchema = '''
31+
type Query {
32+
authorByid(id: ID!): Author
33+
}
34+
35+
type Author @extends @key(fields: "id") {
36+
id: String @external
37+
firstName: String!
38+
lastName: String!
39+
}
40+
'''
41+
42+
def setup() {
43+
}
44+
45+
def "Query multiple field of entity extension with fragment and inline fragment"() {
46+
given:
47+
48+
def testQuery = '''
49+
query {
50+
bookById(id: "12345") {
51+
id
52+
name
53+
pageCount
54+
author {
55+
... authorBaseQuery
56+
... on Author {
57+
lastName
58+
}
59+
}
60+
}
61+
}
62+
63+
fragment authorBaseQuery on Author {
64+
idAlias:id
65+
fname:firstName
66+
}
67+
'''
68+
69+
def bookResponse = [
70+
data: [
71+
bookById: [
72+
id : "book-1",
73+
name : "GraphQuilt: The future of Schema Stitching",
74+
pageCount: 100,
75+
author : ["idAlias": "12345"]
76+
]
77+
78+
]
79+
]
80+
81+
def FNAME_ENTITY_FETCH_QUERY = "query (\$REPRESENTATIONS:[_Any!]!) {_entities(representations:\$REPRESENTATIONS) {... on Author {fname:firstName}}}"
82+
def LNAME_ENTITY_FETCH_QUERY = "query (\$REPRESENTATIONS:[_Any!]!) {_entities(representations:\$REPRESENTATIONS) {... on Author {lastName}}}"
83+
def authorResponse = [
84+
(FNAME_ENTITY_FETCH_QUERY): [data: [
85+
_entities: [
86+
[
87+
fname : "Charles"
88+
]
89+
]
90+
]],
91+
(LNAME_ENTITY_FETCH_QUERY): [data: [
92+
_entities: [
93+
[
94+
lastName : "Charles-LastName"
95+
]
96+
]
97+
]]
98+
99+
]
100+
101+
ServiceProvider bookService = createSimpleMockService("bookService",
102+
ServiceProvider.ServiceType.FEDERATION_SUBGRAPH, bookSchema, bookResponse)
103+
104+
105+
ServiceProvider authorService = createQueryMatchingService("authorService",
106+
ServiceProvider.ServiceType.FEDERATION_SUBGRAPH, authorSchema, authorResponse)
107+
108+
109+
ServiceProvider[] services = [bookService, authorService]
110+
specUnderTest = createGraphQLOrchestrator(services)
111+
112+
when:
113+
ExecutionInput booksAndPetsEI = ExecutionInput.newExecutionInput().query(testQuery)
114+
.variables(ImmutableMap.of("includeType", Boolean.TRUE))
115+
.build()
116+
117+
Map<String, Object> executionResult = specUnderTest.execute(booksAndPetsEI).get().toSpecification()
118+
119+
then:
120+
executionResult.get("errors") == null
121+
executionResult.get("data") != null
122+
123+
executionResult?.data?.bookById?.id == "book-1"
124+
executionResult?.data?.bookById?.name == "GraphQuilt: The future of Schema Stitching"
125+
executionResult?.data?.bookById?.pageCount == 100
126+
127+
executionResult?.data?.bookById?.author.idAlias == "12345"
128+
executionResult?.data?.bookById?.author.fname == "Charles"
129+
executionResult?.data?.bookById?.author.lastName == "Charles-LastName"
130+
131+
Map<String, Object> dataValue = (Map<String, Object>) executionResult.get("data")
132+
dataValue.keySet().containsAll("bookById")
133+
((Map<String, Objects>) dataValue.get("bookById")).keySet().size() == 4
134+
}
135+
136+
}

0 commit comments

Comments
 (0)