Add visitor for types and use generic traversal#1084
Add visitor for types and use generic traversal#1084andimarek merged 13 commits intographql-java:masterfrom
Conversation
There was a problem hiding this comment.
JavaDoc on key types would be needed
There was a problem hiding this comment.
I find this one a real stretch in terms of saying this is "better"...There are 2 conditions -scalar and enum and there is some unwrapping to be done.
If I look at this code is an indirection that is low value.
That said the others have more value
There was a problem hiding this comment.
Unwrapping is using recursion, which is based on a fixed stack.
Large and deep graphs have a chance to overflow stack. VERY large graphql type system will overflow it for sure.
Recursion is also application-dependent at runtime. If this lib will be called after web server, IoC framework, other application layers .... this all eats up stack leaving less and less room. Not to mention hypothetical cycles in graphql type system...
Another hypothetical case is there application developer would run graphql in a thread with custom (and small) execution stack.
Traverser is free from all above issues. It relies on a true stack, which would grow in size if needed and tracks visited types as it goes.
There was a problem hiding this comment.
In theory - perhaps
but in practice, given a graphql type it can only be 1 of 6 different types (enum, scalar, object, input, interface and union) or the wrappers like (list, null, type reference)
So in order to blow the stack given a single graphql type, then you would need megabytes of wrapping
eg [![![![![![![![![![![![![![SomeTypeHere]]]]]]]]]]]
Given a simple graphql type there is no infinite tree.
Now if you include graphql.schema.GraphQLFieldDefinition (which does not derive from GraphqlType) then yes you can have a large tree.
My point is that not ALL uses case of recursion are problematic. And in this case where we have a single GraphqlType, not at all.
There was a problem hiding this comment.
My point is that not ALL uses case of recursion are problematic.
Agree on 100%. Do you think that traverser gives too much of overhead?
This case might be trivial, but it is still type traversal. Traverser looks good enough to cover this case too. Would you prefer to have custom algorithm here instead?
There was a problem hiding this comment.
Java Doc and @internal of @publicapi would be needed
There was a problem hiding this comment.
TypeTraverser is similar to NodeTraverser. Shall I update both?
I consider NodeTraverser/TypeTraverser as @internal for now.
There was a problem hiding this comment.
yes, please make it @Internal for now.
|
The build is failing with
I am not sure what they means however. Can you re-pull master onto this branch so as to perhaps fix this. I did this on other branches and it seem to work. Like I said I am not sure what this is?? |
There was a problem hiding this comment.
There is enough visitor code here that it deserves its own file.
Perhaps not one class per visitor so I would create a package protected holder of these classes called say "TypeVisitors" that contained these classes
There was a problem hiding this comment.
please put these at the top of the file. Bit more idiomatic
There was a problem hiding this comment.
Simple JavaDoc please.
This probably deserves to be @publicapi eventually (as a help to write a visitor)
There was a problem hiding this comment.
Also naming as mentioned above GraphqlTypeVisitorStub
There was a problem hiding this comment.
Naming is hard but I would call this (and the others) GraphqlTypeVisitor
My reasoning is that we have runtime types and AST types and its already confusing
So we have GraphqlType / GraphqlObjectType and so on to help with that
Hence I visitor of GraphqlType thigns should have the GraphqlTypeVisitor naming. Same with the stubb and so on
bbakerman
left a comment
There was a problem hiding this comment.
I would like to see more unit tests of the specific traversal on all types.
I know existing tests around SchemaUtil probably test this by accident
But I think we need a test that demonstrates that given all the GraphqlType derived things, that a visitor will in fact see them all.
|
@bbakerman Build failure is coming from gradle function (here), but it seems execution of the git command itself was ok. I think it has something to do with gradle thread... not sure. I will try to re-base/re-sync with latest master and see what happens. From travis log. Thank you for review, I will follow up with comments. |
|
@bbakerman I feel confused with usage of @PublicAPI/@internal. Is there guide anywhere besides javadoc? Basically I would love to wait few release before switching it to public. Probably we could od same thing for NodeVisitorStub/NodeVisitor - they are @internal, but I believe they should be @public as well. Let me ping you about test cases on gitter. I might need to clarify some use cases. |
|
PS close-reopen PR helps to "fix" build failure on travis CI |
|
@exbe yes: the current build (getting the git hash part) is sometimes flaky. |
There was a problem hiding this comment.
@andimarek This method was part of older recursive reference resolution algorithm.
This PR uses getChildren() to unwrap actual type and replaceType(GraphQLInputType type) to set it.
I am not sure if anyone else is using it (e.g. clients), so I have marked it as @deprecated.
Ideally, if it is not part of some use case, this can be removed in future versions.
If I miss some use case, I would be happy to learn about it and add support.
There was a problem hiding this comment.
please remove them: they are not used anywhere else and were only for one purpose
|
@bbakerman @andimarek I think I responded to all comments. |
andimarek
left a comment
There was a problem hiding this comment.
Thanks for this PR.
In general I think it is a real improvement compared to the manual traversing. 👍
Please see my other comments for what to change.
Also: Please use the graphql-java formatter https://github.com/graphql-java/graphql-java/blob/master/graphql-java-code-style.xml and format your code with that.
Thanks
There was a problem hiding this comment.
Class name: 'GraphQLTypeVisitor' not 'GrapqhlTypeVisitor'
There was a problem hiding this comment.
why the difference here between Interfaces and concrete types?
There was a problem hiding this comment.
For convince, which is based on assumption that in most cases developers won't need to visit marker interface very often (even stub doesn't care).
Not a big deal - I can move default implementation under GraphQLTypeVisitorStub.
What is your preference @bbakerman and @andimarek?
There was a problem hiding this comment.
unit testing is missing: have a look at NodeVisitorStubTest for inspiration.
There was a problem hiding this comment.
It is getting tested via TypeTraverserTest :) Is it good enough?
There was a problem hiding this comment.
please make every class public and extract in a extra file. Don't make them package protected, but mark them as @Internal
There was a problem hiding this comment.
yes, please make it @Internal for now.
There was a problem hiding this comment.
why protected? I would say make it private. We don't really design for inheritance: if there is something that should be customizable it should be done in another way.
There was a problem hiding this comment.
private static please if we keep it, but more important: simplify it please by only caring about enter, because we only support depthFirst atm.
There was a problem hiding this comment.
I agree with @bbakerman: the original code for isLeafType and isInputType is so much simpler and I don't really see a non theoretical argument to replace that. So please revert it to the original code and delete the LeafVisitor.
|
@bbakerman @andimarek do you see anything else, which I should change in a scope of this PR? |
|
@bbakerman @andimarek any updates on this one? |
|
I am really sorry for the delay @exbe. Will try to review it soon. |
|
@andimarek no worries, take your time :) |
andimarek
left a comment
There was a problem hiding this comment.
Looks good, see my comments for some final thoughts.
| import graphql.util.TraversalControl; | ||
| import graphql.util.TraverserContext; | ||
|
|
||
| @Internal |
There was a problem hiding this comment.
This should be public: we recently made the general Traverser also public, so nothing prevents us from making this public too
| public TraversalControl visitGraphQLTypeReference(GraphQLTypeReference node, TraverserContext<GraphQLType> context) { | ||
|
|
||
| final GraphQLType resolvedType = typeMap.get(node.getName()); | ||
| Assert.assertTrue(resolvedType != null, "type %s not found in schema", node.getName()); |
There was a problem hiding this comment.
just as a hint: we also have assertNoNull
| import graphql.util.TraverserContext; | ||
|
|
||
| @Internal | ||
| public class GraphQLTypeRefResolvingVisitor extends GraphQLTypeVisitorStub { |
There was a problem hiding this comment.
what do you think about putting this class into the other one GraphQLTypeResolvingVisitor? it is a very hard dependency and it would make it more readable imho
…lver - type visitor promoted to public api - better code style for assertion
|
@andimarek please check |
|
@exbe thanks for the patience ... looks good |
? extends GraphQLTypecan be traversed using TypeTraverser