Skip to content

Conversation

@bbakerman
Copy link
Member

@bbakerman bbakerman commented Feb 6, 2023

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#visitField that exists which gives out stuff like

default TraversalControl visitFieldWithControl(QueryVisitorFieldEnvironment queryVisitorFieldEnvironment) {
        visitField(queryVisitorFieldEnvironment);
        return TraversalControl.CONTINUE;
    }

    void visitInlineFragment(QueryVisitorInlineFragmentEnvironment queryVisitorInlineFragmentEnvironment);

    void visitFragmentSpread(QueryVisitorFragmentSpreadEnvironment queryVisitorFragmentSpreadEnvironment);

    default void visitFragmentDefinition(QueryVisitorFragmentDefinitionEnvironment queryVisitorFragmentDefinitionEnvironment) {

    }

So this has now progressed and I have more environments available - all of the major types plus one catch all GraphqlSchemaElement one

I 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

*/
interface GraphQLFieldDefinitionVisitorEnvironment extends SmartTypeVisitorEnvironment {

GraphQLFieldsContainer getFieldsContainer();
Copy link
Member Author

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) {

Copy link
Member Author

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 ?

Copy link
Member

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.

Copy link
Member

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.

@bbakerman bbakerman changed the title WIP - Smarter type visitor Smarter schema visitor Feb 27, 2023
*
* @return how to control the visitation processing
*/
TraversalControl visitGraphQLDirective(GraphQLDirective node, TraverserContext<GraphQLSchemaElement> context);
Copy link
Member Author

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);
}
Copy link
Member Author

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);
Copy link
Member Author

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;
}
Copy link
Member Author

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;
Copy link
Member Author

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;
}
}
Copy link
Member Author

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

@dondonz dondonz added this to the 20.1 milestone Mar 14, 2023
@andimarek andimarek modified the milestones: April 2023, July 2023 Mar 21, 2023
@bbakerman bbakerman added this pull request to the merge queue May 29, 2023
Merged via the queue into master with commit 8649ea6 May 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants