-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add visitor for types and use generic traversal #1084
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
Conversation
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.
JavaDoc on key types would be needed
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 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Java Doc and @internal of @publicapi would be needed
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.
TypeTraverser is similar to NodeTraverser. Shall I update both?
I consider NodeTraverser/TypeTraverser as @internal for now.
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please put these at the top of the file. Bit more idiomatic
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.
Simple JavaDoc please.
This probably deserves to be @publicapi eventually (as a help to write a 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.
Also naming as mentioned above GraphqlTypeVisitorStub
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this deprecated now?
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.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Class name: 'GraphQLTypeVisitor' not 'GrapqhlTypeVisitor'
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.
why the difference here between Interfaces and concrete types?
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
naming: GraphQL...
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.
unit testing is missing: have a look at NodeVisitorStubTest for inspiration.
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.
It is getting tested via TypeTraverserTest :) Is it good enough?
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.
naming: GraphQL...
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please remove it
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.
yes, please make it @Internal for now.
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private .. see above
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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