Skip to content

Commit b869dce

Browse files
committed
Now with control methods in the env
1 parent c92b102 commit b869dce

6 files changed

Lines changed: 217 additions & 56 deletions

File tree

src/main/java/graphql/schema/GraphQLTypeVisitor.java

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,54 +13,56 @@
1313
*/
1414
@PublicApi
1515
public interface GraphQLTypeVisitor {
16-
TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext<GraphQLSchemaElement> context);
17-
18-
TraversalControl visitGraphQLInterfaceType(GraphQLInterfaceType node, TraverserContext<GraphQLSchemaElement> context);
19-
20-
TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext<GraphQLSchemaElement> context);
21-
22-
TraversalControl visitGraphQLEnumValueDefinition(GraphQLEnumValueDefinition node, TraverserContext<GraphQLSchemaElement> context);
23-
24-
TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext<GraphQLSchemaElement> context);
25-
2616
/**
27-
* This method will be called twice. Once for a directive definition in a schema and then do each time a directive is applied to a schema element
17+
* This method will be called when a directive is applied to a schema element.
2818
*
29-
* When it's applied to a schema element then {@link TraverserContext#getParentNode()} will be the schema element that this is applied to.
19+
* The {@link TraverserContext#getParentNode()} will be the schema element that this is applied to.
3020
*
3121
* The graphql-java code base is trying to slowly move away from using {@link GraphQLDirective}s when they really should be {@link GraphQLAppliedDirective}s
32-
* and this is another place that has been left in. In the future this behavior will change and this will only visit directive definitions of a schema, not where
33-
* they are applied.
3422
*
35-
* @param node the directive
23+
* @param node the applied directive
3624
* @param context the traversal context
25+
*
3726
* @return how to control the visitation processing
3827
*/
39-
TraversalControl visitGraphQLDirective(GraphQLDirective node, TraverserContext<GraphQLSchemaElement> context);
28+
default TraversalControl visitGraphQLAppliedDirective(GraphQLAppliedDirective node, TraverserContext<GraphQLSchemaElement> context) {
29+
return TraversalControl.CONTINUE;
30+
}
31+
32+
default TraversalControl visitGraphQLAppliedDirectiveArgument(GraphQLAppliedDirectiveArgument node, TraverserContext<GraphQLSchemaElement> context) {
33+
return TraversalControl.CONTINUE;
34+
}
35+
36+
TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext<GraphQLSchemaElement> context);
4037

4138
/**
42-
* This method will be called when a directive is applied to a schema element.
39+
* This method will be called twice. Once for a directive definition in a schema and then do each time a directive is applied to a schema element
4340
*
44-
* The {@link TraverserContext#getParentNode()} will be the schema element that this is applied to.
41+
* When it's applied to a schema element then {@link TraverserContext#getParentNode()} will be the schema element that this is applied to.
4542
*
4643
* The graphql-java code base is trying to slowly move away from using {@link GraphQLDirective}s when they really should be {@link GraphQLAppliedDirective}s
44+
* and this is another place that has been left in. In the future this behavior will change and this will only visit directive definitions of a schema, not where
45+
* they are applied.
4746
*
48-
* @param node the applied directive
47+
* @param node the directive
4948
* @param context the traversal context
49+
*
5050
* @return how to control the visitation processing
5151
*/
52-
default TraversalControl visitGraphQLAppliedDirective(GraphQLAppliedDirective node, TraverserContext<GraphQLSchemaElement> context) {
53-
return TraversalControl.CONTINUE;
54-
}
52+
TraversalControl visitGraphQLDirective(GraphQLDirective node, TraverserContext<GraphQLSchemaElement> context);
5553

56-
default TraversalControl visitGraphQLAppliedDirectiveArgument(GraphQLAppliedDirectiveArgument node, TraverserContext<GraphQLSchemaElement> context) {
57-
return TraversalControl.CONTINUE;
58-
}
54+
TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext<GraphQLSchemaElement> context);
55+
56+
TraversalControl visitGraphQLEnumValueDefinition(GraphQLEnumValueDefinition node, TraverserContext<GraphQLSchemaElement> context);
57+
58+
TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext<GraphQLSchemaElement> context);
5959

6060
TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField node, TraverserContext<GraphQLSchemaElement> context);
6161

6262
TraversalControl visitGraphQLInputObjectType(GraphQLInputObjectType node, TraverserContext<GraphQLSchemaElement> context);
6363

64+
TraversalControl visitGraphQLInterfaceType(GraphQLInterfaceType node, TraverserContext<GraphQLSchemaElement> context);
65+
6466
TraversalControl visitGraphQLList(GraphQLList node, TraverserContext<GraphQLSchemaElement> context);
6567

6668
TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContext<GraphQLSchemaElement> context);
@@ -86,10 +88,6 @@ default TraversalControl visitBackRef(TraverserContext<GraphQLSchemaElement> con
8688
}
8789

8890
// Marker interfaces
89-
default TraversalControl visitGraphQLModifiedType(GraphQLModifiedType node, TraverserContext<GraphQLSchemaElement> context) {
90-
throw new UnsupportedOperationException();
91-
}
92-
9391
default TraversalControl visitGraphQLCompositeType(GraphQLCompositeType node, TraverserContext<GraphQLSchemaElement> context) {
9492
throw new UnsupportedOperationException();
9593
}
@@ -110,6 +108,10 @@ default TraversalControl visitGraphQLInputType(GraphQLInputType node, TraverserC
110108
throw new UnsupportedOperationException();
111109
}
112110

111+
default TraversalControl visitGraphQLModifiedType(GraphQLModifiedType node, TraverserContext<GraphQLSchemaElement> context) {
112+
throw new UnsupportedOperationException();
113+
}
114+
113115
default TraversalControl visitGraphQLNullableType(GraphQLNullableType node, TraverserContext<GraphQLSchemaElement> context) {
114116
throw new UnsupportedOperationException();
115117
}

src/main/java/graphql/schema/visitor/GraphQLSchemaVisitor.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,10 @@
1616
@PublicSpi
1717
public interface GraphQLSchemaVisitor {
1818

19-
interface ObjectVisitorEnvironment extends GraphQLSchemaVisitorEnvironment {
20-
}
21-
2219
default TraversalControl visitGraphQLObjectType(GraphQLObjectType objectType, ObjectVisitorEnvironment environment) {
2320
return TraversalControl.CONTINUE;
2421
}
2522

26-
/**
27-
* This is a class specific for visiting {@link GraphQLFieldDefinition}s
28-
*/
29-
interface FieldVisitorEnvironment extends GraphQLSchemaVisitorEnvironment {
30-
31-
GraphQLFieldsContainer getFieldsContainer();
32-
33-
}
34-
3523
/**
3624
* Each method has a specific env say or some do - TBD
3725
*
@@ -44,7 +32,6 @@ default TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition fiel
4432
return TraversalControl.CONTINUE;
4533
}
4634

47-
4835
/**
4936
* This allows you to turn this smarter visitr into the base {@link graphql.schema.GraphQLTypeVisitor}
5037
*
@@ -53,4 +40,17 @@ default TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition fiel
5340
default GraphQLTypeVisitor toTypeVisitor() {
5441
return new GraphQLSchemaVisitorAdapter(this);
5542
}
43+
44+
interface ObjectVisitorEnvironment extends GraphQLSchemaVisitorEnvironment<GraphQLObjectType> {
45+
}
46+
47+
/**
48+
* This is a class specific for visiting {@link GraphQLFieldDefinition}s
49+
*/
50+
interface FieldVisitorEnvironment extends GraphQLSchemaVisitorEnvironment<GraphQLFieldDefinition> {
51+
52+
GraphQLFieldsContainer getFieldsContainer();
53+
54+
}
55+
5656
}

src/main/java/graphql/schema/visitor/GraphQLSchemaVisitorAdapter.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,29 @@ class GraphQLSchemaVisitorAdapter extends GraphQLTypeVisitorStub {
2121
this.smartTypeVisitor = smartTypeVisitor;
2222
}
2323

24+
@Override
25+
public TraversalControl visitGraphQLObjectType(GraphQLObjectType node, TraverserContext<GraphQLSchemaElement> context) {
26+
return smartTypeVisitor.visitGraphQLObjectType(node, new ObjectEnv(context));
27+
}
28+
29+
@Override
30+
public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext<GraphQLSchemaElement> context) {
31+
return smartTypeVisitor.visitGraphQLFieldDefinition(node, new FieldEnv(context));
32+
}
33+
2434
/* ------------------------------
2535
* GraphQLObjectType
2636
* ------------------------------ */
27-
static class ObjectEnv extends GraphQLSchemaVisitorEnvironmentImpl implements ObjectVisitorEnvironment {
37+
static class ObjectEnv extends GraphQLSchemaVisitorEnvironmentImpl<GraphQLObjectType> implements ObjectVisitorEnvironment {
2838
public ObjectEnv(TraverserContext<GraphQLSchemaElement> context) {
2939
super(context);
3040
}
3141
}
3242

33-
@Override
34-
public TraversalControl visitGraphQLObjectType(GraphQLObjectType node, TraverserContext<GraphQLSchemaElement> context) {
35-
return smartTypeVisitor.visitGraphQLObjectType(node, new ObjectEnv(context));
36-
}
37-
3843
/* ------------------------------
3944
* GraphQLFieldDefinition
4045
* ------------------------------ */
41-
static class FieldEnv extends GraphQLSchemaVisitorEnvironmentImpl implements FieldVisitorEnvironment {
46+
static class FieldEnv extends GraphQLSchemaVisitorEnvironmentImpl<GraphQLFieldDefinition> implements FieldVisitorEnvironment {
4247

4348
public FieldEnv(TraverserContext<GraphQLSchemaElement> context) {
4449
super(context);
@@ -49,9 +54,4 @@ public GraphQLFieldsContainer getFieldsContainer() {
4954
return (GraphQLFieldsContainer) context.getParentNode();
5055
}
5156
}
52-
53-
@Override
54-
public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext<GraphQLSchemaElement> context) {
55-
return smartTypeVisitor.visitGraphQLFieldDefinition(node, new FieldEnv(context));
56-
}
5757
}
Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,64 @@
11
package graphql.schema.visitor;
22

33
import graphql.schema.GraphQLCodeRegistry;
4+
import graphql.schema.GraphQLSchemaElement;
5+
import graphql.util.TraversalControl;
46

5-
public interface GraphQLSchemaVisitorEnvironment {
7+
public interface GraphQLSchemaVisitorEnvironment<T extends GraphQLSchemaElement> {
68

79
GraphQLCodeRegistry.Builder getCodeRegistry();
10+
11+
12+
/**
13+
* @return When returned the traversal will continue as planned.
14+
* A synonym method for {@link TraversalControl#CONTINUE}
15+
*/
16+
TraversalControl ok();
17+
18+
/**
19+
* @return When returned from a {@link GraphQLSchemaVisitor}'s method, indicates exiting the traversal.
20+
* A synonym method for {@link TraversalControl#QUIT}
21+
*/
22+
TraversalControl quit();
23+
24+
/**
25+
* @return When returned from a {@link GraphQLSchemaVisitor}'s method, indicates skipping traversal of a subtree.
26+
* A synonym method for {@link TraversalControl#ABORT}
27+
*/
28+
TraversalControl abort();
29+
30+
/**
31+
* Called to change the current node to the specific node
32+
*
33+
* @param schemaElement the schema element to change
34+
*
35+
* @return This will always be {@link TraversalControl#CONTINUE}
36+
*/
37+
TraversalControl changeNode(T schemaElement);
38+
39+
/**
40+
* Called to delete the current node
41+
*
42+
* @return This will always be {@link TraversalControl#CONTINUE}
43+
*/
44+
TraversalControl deleteNode();
45+
46+
/**
47+
* Called to insert the current schema element after the specified schema element
48+
*
49+
* @param schemaElement the schema element to after before
50+
*
51+
* @return This will always be {@link TraversalControl#CONTINUE}
52+
*/
53+
TraversalControl insertAfter(T schemaElement);
54+
55+
/**
56+
* Called to insert the current schema element before the specified schema element
57+
*
58+
* @param schemaElement the schema element to insert before
59+
*
60+
* @return This will always be {@link TraversalControl#CONTINUE}
61+
*/
62+
TraversalControl insertBefore(T schemaElement);
63+
864
}

src/main/java/graphql/schema/visitor/GraphQLSchemaVisitorEnvironmentImpl.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
import graphql.Internal;
44
import graphql.schema.GraphQLCodeRegistry;
55
import graphql.schema.GraphQLSchemaElement;
6+
import graphql.util.TraversalControl;
67
import graphql.util.TraverserContext;
8+
import graphql.util.TreeTransformerUtil;
79

810
@Internal
9-
class GraphQLSchemaVisitorEnvironmentImpl implements GraphQLSchemaVisitorEnvironment {
11+
class GraphQLSchemaVisitorEnvironmentImpl<T extends GraphQLSchemaElement> implements GraphQLSchemaVisitorEnvironment<T> {
1012

1113
protected final TraverserContext<GraphQLSchemaElement> context;
1214

@@ -18,4 +20,43 @@ class GraphQLSchemaVisitorEnvironmentImpl implements GraphQLSchemaVisitorEnviron
1820
public GraphQLCodeRegistry.Builder getCodeRegistry() {
1921
return context.getVarFromParents(GraphQLCodeRegistry.Builder.class);
2022
}
23+
24+
@Override
25+
public TraversalControl ok() {
26+
return TraversalControl.CONTINUE;
27+
}
28+
29+
@Override
30+
public TraversalControl quit() {
31+
return TraversalControl.QUIT;
32+
}
33+
34+
@Override
35+
public TraversalControl abort() {
36+
return TraversalControl.ABORT;
37+
}
38+
39+
@Override
40+
public TraversalControl changeNode(T schemaElement) {
41+
TreeTransformerUtil.changeNode(context, schemaElement);
42+
return TraversalControl.CONTINUE;
43+
}
44+
45+
@Override
46+
public TraversalControl deleteNode() {
47+
TreeTransformerUtil.deleteNode(context);
48+
return TraversalControl.CONTINUE;
49+
}
50+
51+
@Override
52+
public TraversalControl insertAfter(T schemaElement) {
53+
TreeTransformerUtil.insertAfter(context, schemaElement);
54+
return TraversalControl.CONTINUE;
55+
}
56+
57+
@Override
58+
public TraversalControl insertBefore(T schemaElement) {
59+
TreeTransformerUtil.insertBefore(context, schemaElement);
60+
return TraversalControl.CONTINUE;
61+
}
2162
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package graphql.schema.visitor
2+
3+
import graphql.TestUtil
4+
import graphql.schema.GraphQLFieldDefinition
5+
import graphql.schema.GraphQLObjectType
6+
import graphql.schema.SchemaTraverser
7+
import graphql.util.TraversalControl
8+
import spock.lang.Specification
9+
10+
import static graphql.util.TraversalControl.CONTINUE
11+
12+
class GraphQLSchemaVisitorTest extends Specification {
13+
14+
def uberSDL = '''
15+
type Query {
16+
object : ObjectTypeA
17+
}
18+
19+
type ObjectTypeA {
20+
fieldA : String
21+
}
22+
23+
24+
25+
'''
26+
27+
def schema = TestUtil.schema(uberSDL)
28+
29+
30+
class CapturingSchemaVisitor implements GraphQLSchemaVisitor {
31+
32+
def types = [:]
33+
def fields = [:]
34+
35+
@Override
36+
TraversalControl visitGraphQLObjectType(GraphQLObjectType objectType, ObjectVisitorEnvironment environment) {
37+
types[objectType.getName()] = objectType
38+
return CONTINUE
39+
}
40+
41+
@Override
42+
TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition fieldDefinition, FieldVisitorEnvironment environment) {
43+
fields[environment.fieldsContainer.getName() + "." + fieldDefinition.getName()] = fieldDefinition
44+
45+
return CONTINUE
46+
}
47+
}
48+
49+
def "will visit things"() {
50+
51+
def visitor = new CapturingSchemaVisitor()
52+
53+
when:
54+
new SchemaTraverser().depthFirstFullSchema(visitor.toTypeVisitor(), schema)
55+
56+
then:
57+
visitor.types["ObjectTypeA"] instanceof GraphQLObjectType
58+
59+
visitor.fields["ObjectTypeA.fieldA"] instanceof GraphQLFieldDefinition
60+
61+
}
62+
}

0 commit comments

Comments
 (0)