-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Smarter schema visitor #3087
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
Smarter schema visitor #3087
Conversation
| */ | ||
| interface GraphQLFieldDefinitionVisitorEnvironment extends SmartTypeVisitorEnvironment { | ||
|
|
||
| GraphQLFieldsContainer getFieldsContainer(); |
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.
One other option here is to NOT have a per method interface but rather put this into method signature
visitGraphQLFieldDefinition(GraphQLFieldDefinition fieldDefinition, GraphQLFieldsContainer
container, SmartTypeVisitorEnvironment environment) {
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.
What else would go here to make it smarter ?
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.
What about some callback methods for the intermediate interfaces in the class hierarchy?
Like, I often find myself having to do stuff on all elements that can have directives.
Maybe a callback like visitGraphQLDirectiveContainer(GraphQLDirectiveContainer directiveContainer.....)? GraphQLFieldsContainer is another very common one.
Although that can quickly become convoluted - do we need one for each of those intermediate interfaces (GraphQLNamedInputType, GraphQLNullableType, etc...)? Probably not.
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.
maybe like a dynamic visitor method<T extends GraphQLSchemaElement> visitThing(Class<T> thingClass, BiConsumer<T, Context>) , and in the visitor we could check thingClass.isAssignableFrom(element.getClass()). Something like that...
Not sure if there's already something like that in the API, though.
| return TraversalControl.CONTINUE; | ||
| } | ||
|
|
||
|
|
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| * | ||
| * @return how to control the visitation processing | ||
| */ | ||
| TraversalControl visitGraphQLDirective(GraphQLDirective node, TraverserContext<GraphQLSchemaElement> context); |
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.
I ordered all the methods here in alphabetic order so I can know what's what
| } | ||
| if (schema != null) { | ||
| traverser.rootVar(GraphQLSchema.class, schema); | ||
| } |
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.
We now add the source schema as a root variable - which visitors can now access
| TraverserDelegateListVisitor traverserDelegateListVisitor = new TraverserDelegateListVisitor(typeVisitors); | ||
| return initTraverser().rootVars(rootVars).traverse(roots, traverserDelegateListVisitor); | ||
| Traverser<GraphQLSchemaElement> traverser = initTraverser().rootVars(rootVars).rootVar(GraphQLSchema.class, schema); | ||
| return traverser.traverse(roots, traverserDelegateListVisitor); |
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.
Same here on SchemaTraverser - the schema being traversed is now a root variable
| TraversalControl control = context.thisNode().accept(context, graphQLTypeVisitor); | ||
| if (control != CONTINUE) { | ||
| return control; | ||
| } |
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 was broken. I fixed it and now tests broke
So I wrote a new test for this case - when NOT CONTINUE is returned
| @@ -0,0 +1,81 @@ | |||
| package graphql.schema.visitor; | |||
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.
We have a different "control" that SchemaTraversalControl - so we can have better methods and "hide" the changeNode malarky we must do.
The only way to get a GraphQLSchemaTraversalControl (which is package level on creation) is by the helper methods and hence this simplifies the call API for consumers
| } | ||
| return TraversalControl.CONTINUE; | ||
| } | ||
| } |
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.
See how this hodes the TreeTransformerUtil malarky AND also we can detect intention from the GraphQLSchemaTraversalControl as a value and not a side effect
In short I want to schema visitors to easier to use. eg if I am on a field def, can I get its containing type. Not
context.getParentObject()and cast it but a type safe mechanism for that.This is more like the
graphql.analysis.QueryVisitor#visitFieldthat exists which gives out stuff likeSo this has now progressed and I have more environments available - all of the major types plus one catch all
GraphqlSchemaElementoneI dont visit Non nulls or Lists - I dont think this is useful
If you really want to do that - then use a plain old TypeVisitor - all the power without the nice ness