|
11 | 11 | import com.intuit.graphql.orchestrator.schema.transform.FieldResolverContext; |
12 | 12 | import com.intuit.graphql.orchestrator.utils.SelectionCollector; |
13 | 13 | import graphql.GraphQLContext; |
| 14 | +import graphql.GraphQLException; |
14 | 15 | import graphql.GraphqlErrorException; |
15 | 16 | import graphql.language.Argument; |
16 | 17 | import graphql.language.BooleanValue; |
17 | 18 | import graphql.language.Directive; |
18 | 19 | import graphql.language.Field; |
19 | 20 | import graphql.language.FragmentDefinition; |
| 21 | +import graphql.language.FragmentSpread; |
20 | 22 | import graphql.language.InlineFragment; |
21 | 23 | import graphql.language.Node; |
22 | 24 | import graphql.language.NodeVisitorStub; |
@@ -74,6 +76,7 @@ public class AuthDownstreamQueryModifier extends NodeVisitorStub { |
74 | 76 | private static final ArgumentValueResolver ARGUMENT_VALUE_RESOLVER = new ArgumentValueResolver(); // thread-safe |
75 | 77 | private final List<SelectionSetMetadata> processedSelectionSetMetadata = new ArrayList<>(); |
76 | 78 | private final List<GraphqlErrorException> declinedFieldsErrors = new ArrayList<>(); |
| 79 | + private final List<String> fragmentSpreadsRemoved = new ArrayList<>(); |
77 | 80 |
|
78 | 81 | private boolean hasEmptySelectionSet; |
79 | 82 |
|
@@ -105,20 +108,9 @@ public TraversalControl visitField(Field node, TraverserContext<Node> context) { |
105 | 108 | return deleteNode(context); |
106 | 109 | } |
107 | 110 |
|
108 | | - if(!node.getDirectives(DEFER_DIRECTIVE_NAME).isEmpty()) { |
109 | | - Argument deferArg = node.getDirectives(DEFER_DIRECTIVE_NAME).get(0).getArgument(DEFER_IF_ARG); |
110 | | - if(graphQLContext.getOrDefault(USE_DEFER, false) && (deferArg == null || ((BooleanValue)deferArg.getValue()).isValue())) { |
111 | | - decreaseParentSelectionSetCount(context.getParentContext()); |
112 | | - return deleteNode(context); |
113 | | - } else { |
114 | | - //remove directive from query since directive is not built in and will fail downstream if added |
115 | | - List<Directive> directives = node.getDirectives() |
116 | | - .stream() |
117 | | - .filter(directive -> !DEFER_DIRECTIVE_NAME.equals(directive.getName())) |
118 | | - .collect(Collectors.toList()); |
119 | | - |
120 | | - return changeNode(context, node.transform(builder -> builder.directives(directives))); |
121 | | - } |
| 111 | + List<Directive> directives = node.getDirectives(); |
| 112 | + if(containsDeferDirective(directives)) { |
| 113 | + return pruneDeferInfo(node, context, directives); |
122 | 114 | } |
123 | 115 |
|
124 | 116 | if(!serviceMetadata.getRenamedMetadata().getOriginalFieldNamesByRenamedName().isEmpty()) { |
@@ -232,6 +224,24 @@ public TraversalControl visitFragmentDefinition( |
232 | 224 | public TraversalControl visitInlineFragment(InlineFragment node, TraverserContext<Node> context) { |
233 | 225 | String typeName = node.getTypeCondition().getName(); |
234 | 226 | context.setVar(GraphQLType.class, this.graphQLSchema.getType(typeName)); |
| 227 | + |
| 228 | + List<Directive> directives = node.getDirectives(); |
| 229 | + if(containsDeferDirective(directives)) { |
| 230 | + return pruneDeferInfo(node, context, directives); |
| 231 | + } |
| 232 | + |
| 233 | + return TraversalControl.CONTINUE; |
| 234 | + } |
| 235 | + |
| 236 | + @Override |
| 237 | + public TraversalControl visitFragmentSpread(FragmentSpread node, TraverserContext<Node> context) { |
| 238 | + context.setVar(GraphQLType.class, this.graphQLSchema.getType(node.getName())); |
| 239 | + |
| 240 | + List<Directive> directives = node.getDirectives(); |
| 241 | + if(containsDeferDirective(directives)) { |
| 242 | + return pruneDeferInfo(node, context, directives); |
| 243 | + } |
| 244 | + |
235 | 245 | return TraversalControl.CONTINUE; |
236 | 246 | } |
237 | 247 |
|
@@ -319,10 +329,52 @@ private GraphQLType getParentType(TraverserContext<Node> context) { |
319 | 329 | return GraphQLTypeUtil.unwrapAll(parentType); |
320 | 330 | } |
321 | 331 |
|
| 332 | + private boolean containsDeferDirective(List<Directive> directives) { |
| 333 | + return directives != null && directives.stream() |
| 334 | + .anyMatch(directive -> DEFER_DIRECTIVE_NAME.equals(directive.getName())); |
| 335 | + } |
| 336 | + |
| 337 | + private TraversalControl pruneDeferInfo(Node node, TraverserContext<Node> context, List<Directive> nodeDirectives) { |
| 338 | + Directive deferDirective = nodeDirectives |
| 339 | + .stream() |
| 340 | + .filter(directive -> DEFER_DIRECTIVE_NAME.equals(directive.getName())) |
| 341 | + .findFirst() |
| 342 | + .get(); |
| 343 | + |
| 344 | + Argument deferArg = deferDirective.getArgument(DEFER_IF_ARG); |
| 345 | + if(graphQLContext.getOrDefault(USE_DEFER, false) && (deferArg == null || ((BooleanValue)deferArg.getValue()).isValue())) { |
| 346 | + decreaseParentSelectionSetCount(context.getParentContext()); |
| 347 | + if(node instanceof FragmentSpread) { |
| 348 | + this.fragmentSpreadsRemoved.add(((FragmentSpread)node).getName()); |
| 349 | + } |
| 350 | + |
| 351 | + return deleteNode(context); |
| 352 | + } else { |
| 353 | + final List<Directive> directives = nodeDirectives |
| 354 | + .stream() |
| 355 | + .filter(directive -> !DEFER_DIRECTIVE_NAME.equals(directive.getName())) |
| 356 | + .collect(Collectors.toList()); |
| 357 | + //remove directive from query since directive is not built in and will fail downstream if added |
| 358 | + if(node instanceof Field) { |
| 359 | + return changeNode(context, ((Field)node).transform(builder -> builder.directives(directives))); |
| 360 | + } else if(node instanceof InlineFragment) { |
| 361 | + return changeNode(context, ((InlineFragment)node).transform(builder -> builder.directives(directives))); |
| 362 | + } else if(node instanceof FragmentSpread) { |
| 363 | + return changeNode(context, ((FragmentSpread)node).transform(builder -> builder.directives(directives))); |
| 364 | + } else { |
| 365 | + throw new GraphQLException("Not Supported Defer Location."); |
| 366 | + } |
| 367 | + } |
| 368 | + } |
| 369 | + |
322 | 370 | public List<GraphqlErrorException> getDeclineFieldErrors() { |
323 | 371 | return declinedFieldsErrors; |
324 | 372 | } |
325 | 373 |
|
| 374 | + public List<String> getFragmentSpreadsRemoved() { |
| 375 | + return this.fragmentSpreadsRemoved; |
| 376 | + } |
| 377 | + |
326 | 378 | public List<SelectionSetMetadata> getEmptySelectionSets() { |
327 | 379 | return this.processedSelectionSetMetadata.stream() |
328 | 380 | .filter(selectionSetMetadata -> selectionSetMetadata.getRemainingSelectionsCount() == 0) |
|
0 commit comments