-
Notifications
You must be signed in to change notification settings - Fork 1.1k
This introduces a Traversal Options to allow skipping the coercing of field arguments #3651
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,6 +30,7 @@ | |
| import graphql.util.TraversalControl; | ||
| import graphql.util.TraverserContext; | ||
|
|
||
| import java.util.Collections; | ||
| import java.util.Locale; | ||
| import java.util.Map; | ||
|
|
||
|
|
@@ -50,13 +51,20 @@ public class NodeVisitorWithTypeTracking extends NodeVisitorStub { | |
| private final GraphQLSchema schema; | ||
| private final Map<String, FragmentDefinition> fragmentsByName; | ||
| private final ConditionalNodes conditionalNodes = new ConditionalNodes(); | ||
|
|
||
| public NodeVisitorWithTypeTracking(QueryVisitor preOrderCallback, QueryVisitor postOrderCallback, Map<String, Object> variables, GraphQLSchema schema, Map<String, FragmentDefinition> fragmentsByName) { | ||
| private final QueryTraversalOptions options; | ||
|
|
||
| public NodeVisitorWithTypeTracking(QueryVisitor preOrderCallback, | ||
| QueryVisitor postOrderCallback, | ||
| Map<String, Object> variables, | ||
| GraphQLSchema schema, | ||
| Map<String, FragmentDefinition> fragmentsByName, | ||
| QueryTraversalOptions options) { | ||
| this.preOrderCallback = preOrderCallback; | ||
| this.postOrderCallback = postOrderCallback; | ||
| this.variables = variables; | ||
| this.schema = schema; | ||
| this.fragmentsByName = fragmentsByName; | ||
| this.options = options; | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -156,12 +164,17 @@ public TraversalControl visitField(Field field, TraverserContext<Node> context) | |
| boolean isTypeNameIntrospectionField = fieldDefinition == schema.getIntrospectionTypenameFieldDefinition(); | ||
| GraphQLFieldsContainer fieldsContainer = !isTypeNameIntrospectionField ? (GraphQLFieldsContainer) unwrapAll(parentEnv.getOutputType()) : null; | ||
| GraphQLCodeRegistry codeRegistry = schema.getCodeRegistry(); | ||
| Map<String, Object> argumentValues = ValuesResolver.getArgumentValues(codeRegistry, | ||
| fieldDefinition.getArguments(), | ||
| field.getArguments(), | ||
| CoercedVariables.of(variables), | ||
| GraphQLContext.getDefault(), | ||
| Locale.getDefault()); | ||
| Map<String, Object> argumentValues; | ||
| if (options.isCoerceFieldArguments()) { | ||
| argumentValues = ValuesResolver.getArgumentValues(codeRegistry, | ||
| fieldDefinition.getArguments(), | ||
| field.getArguments(), | ||
| CoercedVariables.of(variables), | ||
| GraphQLContext.getDefault(), | ||
| Locale.getDefault()); | ||
| } else { | ||
| argumentValues = Collections.emptyMap(); | ||
| } | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. main change |
||
| QueryVisitorFieldEnvironment environment = new QueryVisitorFieldEnvironmentImpl(isTypeNameIntrospectionField, | ||
| field, | ||
| fieldDefinition, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,20 +36,22 @@ public class QueryTransformer { | |
| private final GraphQLSchema schema; | ||
| private final Map<String, FragmentDefinition> fragmentsByName; | ||
| private final Map<String, Object> variables; | ||
|
|
||
| private final GraphQLCompositeType rootParentType; | ||
| private final QueryTraversalOptions options; | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. QueryTransformer also uses the NodeTracking code and hence this can apply here as well - why not |
||
|
|
||
|
|
||
| private QueryTransformer(GraphQLSchema schema, | ||
| Node root, | ||
| GraphQLCompositeType rootParentType, | ||
| Map<String, FragmentDefinition> fragmentsByName, | ||
| Map<String, Object> variables) { | ||
| Map<String, Object> variables, | ||
| QueryTraversalOptions options) { | ||
| this.schema = assertNotNull(schema, () -> "schema can't be null"); | ||
| this.variables = assertNotNull(variables, () -> "variables can't be null"); | ||
| this.root = assertNotNull(root, () -> "root can't be null"); | ||
| this.rootParentType = assertNotNull(rootParentType); | ||
| this.fragmentsByName = assertNotNull(fragmentsByName, () -> "fragmentsByName can't be null"); | ||
| this.options = assertNotNull(options, () -> "options can't be null"); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -65,12 +67,17 @@ private QueryTransformer(GraphQLSchema schema, | |
| */ | ||
| public Node transform(QueryVisitor queryVisitor) { | ||
| QueryVisitor noOp = new QueryVisitorStub(); | ||
| NodeVisitorWithTypeTracking nodeVisitor = new NodeVisitorWithTypeTracking(queryVisitor, noOp, variables, schema, fragmentsByName); | ||
| NodeVisitorWithTypeTracking nodeVisitor = new NodeVisitorWithTypeTracking(queryVisitor, | ||
| noOp, | ||
| variables, | ||
| schema, | ||
| fragmentsByName, | ||
| options); | ||
|
|
||
| Map<Class<?>, Object> rootVars = new LinkedHashMap<>(); | ||
| rootVars.put(QueryTraversalContext.class, new QueryTraversalContext(rootParentType, null, null, GraphQLContext.getDefault())); | ||
|
|
||
| TraverserVisitor<Node> nodeTraverserVisitor = new TraverserVisitor<Node>() { | ||
| TraverserVisitor<Node> nodeTraverserVisitor = new TraverserVisitor<>() { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tiny fix up - not need for generic |
||
|
|
||
| @Override | ||
| public TraversalControl enter(TraverserContext<Node> context) { | ||
|
|
@@ -98,6 +105,7 @@ public static class Builder { | |
| private Node root; | ||
| private GraphQLCompositeType rootParentType; | ||
| private Map<String, FragmentDefinition> fragmentsByName; | ||
| private QueryTraversalOptions options = QueryTraversalOptions.defaultOptions(); | ||
|
|
||
|
|
||
| /** | ||
|
|
@@ -160,8 +168,25 @@ public Builder fragmentsByName(Map<String, FragmentDefinition> fragmentsByName) | |
| return this; | ||
| } | ||
|
|
||
| /** | ||
| * Sets the options to use while traversing | ||
| * | ||
| * @param options the options to use | ||
| * @return this builder | ||
| */ | ||
| public Builder options(QueryTraversalOptions options) { | ||
| this.options = assertNotNull(options, () -> "options can't be null"); | ||
| return this; | ||
| } | ||
|
|
||
| public QueryTransformer build() { | ||
| return new QueryTransformer(schema, root, rootParentType, fragmentsByName, variables); | ||
| return new QueryTransformer( | ||
| schema, | ||
| root, | ||
| rootParentType, | ||
| fragmentsByName, | ||
| variables, | ||
| options); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package graphql.analysis; | ||
|
|
||
| import graphql.PublicApi; | ||
|
|
||
| /** | ||
| * This options object controls how {@link QueryTraverser} works | ||
| */ | ||
| @PublicApi | ||
| public class QueryTraversalOptions { | ||
|
|
||
| private final boolean coerceFieldArguments; | ||
|
|
||
| private QueryTraversalOptions(boolean coerceFieldArguments) { | ||
| this.coerceFieldArguments = coerceFieldArguments; | ||
| } | ||
|
|
||
| /** | ||
| * @return true if field arguments should be coerced. This is true by default. | ||
| */ | ||
| public boolean isCoerceFieldArguments() { | ||
| return coerceFieldArguments; | ||
| } | ||
|
|
||
| public static QueryTraversalOptions defaultOptions() { | ||
| return new QueryTraversalOptions(true); | ||
| } | ||
|
|
||
| public QueryTraversalOptions coerceFieldArguments(boolean coerceFieldArguments) { | ||
| return new QueryTraversalOptions(coerceFieldArguments); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package graphql.analysis | ||
|
|
||
| import spock.lang.Specification | ||
|
|
||
| class QueryTraversalOptionsTest extends Specification { | ||
|
|
||
| def "defaulting works as expected"() { | ||
| when: | ||
| def options = QueryTraversalOptions.defaultOptions() | ||
|
|
||
| then: | ||
| options.isCoerceFieldArguments() | ||
|
|
||
| when: | ||
| options = QueryTraversalOptions.defaultOptions().coerceFieldArguments(false) | ||
|
|
||
| then: | ||
| !options.isCoerceFieldArguments() | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is public but marked as @internal