33import static com .intuit .graphql .orchestrator .GraphQLOrchestrator .DATA_LOADER_REGISTRY_CONTEXT_KEY ;
44import static com .intuit .graphql .orchestrator .resolverdirective .FieldResolverDirectiveUtil .createFieldResolverOperationName ;
55import static graphql .language .AstPrinter .printAstCompact ;
6+ import static graphql .schema .GraphQLTypeUtil .unwrapAll ;
67
8+ import com .intuit .graphql .orchestrator .ServiceProvider ;
9+ import com .intuit .graphql .orchestrator .datafetcher .ServiceDataFetcher ;
710import com .intuit .graphql .orchestrator .fieldresolver .FieldResolverBatchSelectionSetSupplier ;
11+ import com .intuit .graphql .orchestrator .fieldresolver .FieldResolverGraphQLError ;
812import com .intuit .graphql .orchestrator .fieldresolver .QueryOperationFactory ;
913import com .intuit .graphql .orchestrator .resolverdirective .ResolverDirectiveDefinition ;
1014import com .intuit .graphql .orchestrator .schema .GraphQLObjects ;
15+ import com .intuit .graphql .orchestrator .schema .ServiceMetadata ;
1116import com .intuit .graphql .orchestrator .schema .transform .FieldResolverContext ;
17+ import com .intuit .graphql .orchestrator .xtext .FieldContext ;
1218import graphql .ExecutionInput ;
13- import graphql .ExecutionResult ;
14- import graphql .GraphQL ;
1519import graphql .GraphQLContext ;
16- import graphql .execution .AsyncExecutionStrategy ;
1720import graphql .execution .DataFetcherResult ;
21+ import graphql .language .AstTransformer ;
1822import graphql .language .Definition ;
1923import graphql .language .Document ;
2024import graphql .language .FragmentDefinition ;
2125import graphql .language .FragmentSpread ;
2226import graphql .language .OperationDefinition ;
2327import graphql .language .SelectionSet ;
28+ import graphql .schema .DataFetcher ;
2429import graphql .schema .DataFetchingEnvironment ;
30+ import graphql .schema .FieldCoordinates ;
31+ import graphql .schema .GraphQLCodeRegistry ;
32+ import graphql .schema .GraphQLFieldDefinition ;
33+ import graphql .schema .GraphQLFieldsContainer ;
34+ import graphql .schema .GraphQLObjectType ;
2535import graphql .schema .GraphQLSchema ;
2636import java .util .Collections ;
2737import java .util .List ;
38+ import java .util .Map ;
2839import java .util .Objects ;
2940import java .util .concurrent .CompletableFuture ;
3041import java .util .concurrent .CompletionStage ;
31- import java .util .function .Function ;
3242import java .util .stream .Collectors ;
3343import lombok .Builder ;
3444import org .apache .commons .collections4 .CollectionUtils ;
3747
3848public class FieldResolverBatchLoader implements BatchLoader <DataFetchingEnvironment , DataFetcherResult <Object >> {
3949
40- private static final Function <GraphQLSchema , GraphQL > DEFAULT_GRAPHQL_BUILDER = schema -> GraphQL
41- .newGraphQL (schema )
42- .queryExecutionStrategy (new AsyncExecutionStrategy ())
43- .build ();
44-
4550 private final QueryOperationModifier queryOperationModifier = new QueryOperationModifier ();
4651
4752 private final QueryResponseModifier queryResponseModifier = new DefaultQueryResponseModifier ();
@@ -54,6 +59,8 @@ public class FieldResolverBatchLoader implements BatchLoader<DataFetchingEnviron
5459
5560 private final QueryOperationFactory queryOperationFactory = new QueryOperationFactory ();
5661
62+ private static final AstTransformer AST_TRANSFORMER = new AstTransformer ();
63+
5764 @ Builder
5865 public FieldResolverBatchLoader (FieldResolverContext fieldResolverContext ) {
5966 Objects .requireNonNull (fieldResolverContext , "fieldResolverContext is required" );
@@ -71,31 +78,67 @@ public FieldResolverBatchLoader(FieldResolverContext fieldResolverContext) {
7178 public CompletionStage <List <DataFetcherResult <Object >>> load (final List <DataFetchingEnvironment > dataFetchingEnvironments ) {
7279
7380 String originalOperationName = dataFetchingEnvironments .get (0 ).getOperationDefinition ().getName ();
74- String operationName = createFieldResolverOperationName (originalOperationName );
81+ String downstreamQueryOpName = createFieldResolverOperationName (originalOperationName );
7582
7683 FieldResolverBatchSelectionSetSupplier fieldResolverBatchSelectionSetSupplier =
7784 new FieldResolverBatchSelectionSetSupplier (resolverSelectedFields , dataFetchingEnvironments , fieldResolverContext );
85+ SelectionSet selectionSet = fieldResolverBatchSelectionSetSupplier .get ();
86+ OperationDefinition downstreamQueryOpDef = queryOperationFactory .create (downstreamQueryOpName , selectionSet );
7887
79- OperationDefinition resolverQueryOpDef = queryOperationFactory .create (operationName , fieldResolverBatchSelectionSetSupplier );
88+ ServiceMetadata serviceMetadata = getServiceMetadata (dataFetchingEnvironments .get (0 ));
89+ if (serviceMetadata .hasFieldResolverDirective ()) {
90+ downstreamQueryOpDef = removeExternalFields (downstreamQueryOpDef , dataFetchingEnvironments .get (0 ), serviceMetadata );
91+ }
8092
8193 if (this .fieldResolverContext .isRequiresTypeNameInjection ()) {
82- resolverQueryOpDef = queryOperationModifier .modifyQuery (
94+ downstreamQueryOpDef = queryOperationModifier .modifyQuery (
8395 dataFetchingEnvironments .get (0 ).getGraphQLSchema (),
84- resolverQueryOpDef ,
96+ downstreamQueryOpDef ,
8597 // each DFE have identical fragmentsByName since this is a batch call for same field
8698 // Arguments on the field with @resolver now allowed, set variables empty
8799 dataFetchingEnvironments .get (0 ).getFragmentsByName (), Collections .emptyMap ());
88100 }
89101
90- List <Definition <FragmentDefinition >> resolverQueryFragmentDefinitions =
102+ List <Definition <FragmentDefinition >> downstreamQueryFragmentDefinitions =
91103 createResolverQueryFragmentDefinitions (dataFetchingEnvironments .get (0 ));
92104
93- return execute ( dataFetchingEnvironments . get ( 0 ), resolverQueryOpDef , resolverQueryFragmentDefinitions )
94- . thenApply ( ExecutionResult :: toSpecification )
105+ ServiceProvider serviceProvider = serviceMetadata . getServiceProvider ();
106+ return execute ( dataFetchingEnvironments . get ( 0 ), downstreamQueryOpDef , downstreamQueryFragmentDefinitions , serviceProvider )
95107 .thenApply (queryResponseModifier ::modify )
96108 .thenApply (result -> batchResultTransformer .toBatchResult (result , dataFetchingEnvironments ));
97109 }
98110
111+ private OperationDefinition removeExternalFields (OperationDefinition operationDefinition ,
112+ DataFetchingEnvironment dataFetchingEnvironment , ServiceMetadata serviceMetadata ) {
113+ GraphQLSchema graphQLSchema = dataFetchingEnvironment .getGraphQLSchema ();
114+ GraphQLObjectType rootType = graphQLSchema .getQueryType ();
115+ Map <String , FragmentDefinition > fragmentsByName = dataFetchingEnvironment .getFragmentsByName ();
116+ return (OperationDefinition ) AST_TRANSFORMER .transform (operationDefinition ,
117+ new NoExternalReferenceSelectionSetModifier ((GraphQLFieldsContainer ) unwrapAll (rootType ), serviceMetadata , fragmentsByName ));
118+ }
119+
120+ private ServiceMetadata getServiceMetadata (DataFetchingEnvironment dataFetchingEnvironment ) {
121+ GraphQLCodeRegistry graphQLCodeRegistry = dataFetchingEnvironment .getGraphQLSchema ().getCodeRegistry ();
122+ GraphQLFieldDefinition graphQLFieldDefinition = dataFetchingEnvironment .getFieldDefinition ();
123+
124+ FieldContext fieldContext = this .fieldResolverContext .getTargetFieldContext ();
125+ FieldCoordinates fieldCoordinates = fieldContext .getFieldCoordinates ();
126+
127+ DataFetcher <?> dataFetcher = graphQLCodeRegistry .getDataFetcher (fieldCoordinates , graphQLFieldDefinition );
128+ if (Objects .nonNull (dataFetcher ) && dataFetcher instanceof ServiceDataFetcher ) {
129+ ServiceDataFetcher serviceDataFetcher = (ServiceDataFetcher ) dataFetcher ;
130+ return serviceDataFetcher .getServiceMetadata ();
131+ } else {
132+ throw FieldResolverGraphQLError .builder ()
133+ .errorMessage ("ServiceDataFetcher not found." )
134+ .fieldName (fieldCoordinates .getFieldName ())
135+ .parentTypeName (fieldCoordinates .getTypeName ())
136+ .resolverDirectiveDefinition (this .fieldResolverContext .getResolverDirectiveDefinition ())
137+ .serviceNameSpace (fieldResolverContext .getServiceNamespace ())
138+ .build ();
139+ }
140+ }
141+
99142 private List <Definition <FragmentDefinition >> createResolverQueryFragmentDefinitions (DataFetchingEnvironment dataFetchingEnvironment ) {
100143 SelectionSet selectionSet = dataFetchingEnvironment .getField ().getSelectionSet ();
101144 if (selectionSet == null || CollectionUtils .isEmpty (selectionSet .getSelections ())) {
@@ -109,9 +152,10 @@ private List<Definition<FragmentDefinition>> createResolverQueryFragmentDefiniti
109152 .collect (Collectors .toList ());
110153 }
111154
112- private CompletableFuture <ExecutionResult > execute (DataFetchingEnvironment dataFetchingEnvironment ,
155+ private CompletableFuture <Map < String , Object > > execute (DataFetchingEnvironment dataFetchingEnvironment ,
113156 OperationDefinition resolverQueryOpDef ,
114- List <Definition <FragmentDefinition >> resolverQueryFragmentDefs
157+ List <Definition <FragmentDefinition >> resolverQueryFragmentDefs ,
158+ ServiceProvider serviceProvider
115159 ) {
116160 GraphQLContext context = dataFetchingEnvironment .getContext ();
117161
@@ -129,9 +173,7 @@ private CompletableFuture<ExecutionResult> execute(DataFetchingEnvironment dataF
129173 .operationName (resolverQueryOpDef .getName ())
130174 .build ();
131175
132- GraphQL graphQL = DEFAULT_GRAPHQL_BUILDER .apply (dataFetchingEnvironment .getGraphQLSchema ());
133-
134- return graphQL .executeAsync (resolverQueryExecutionInput );
176+ return serviceProvider .query (resolverQueryExecutionInput , dataFetchingEnvironment .getLocalContext ());
135177 }
136178
137179}
0 commit comments