-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add support for traversing directives #1213
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
|
Thanks for this. This will be a powerful capability over time. Out directive journey is really just beginning and hence we need to make them more first class. This is great PR. Once you have the test I want to merge it. 👍 💯 |
|
@exbe can you have a look at this? your thoughts? thx |
Tests for directive traversal
| Map<String, GraphQLType> allTypes(final GraphQLSchema schema, final Set<GraphQLType> additionalTypes) { | ||
| List<GraphQLType> roots = new ArrayList<GraphQLType>() {{ | ||
| add(schema.getQueryType()); | ||
| List<GraphQLType> roots = new ArrayList<>(); |
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.
The anon class keeps a reference to the outer instance, which is irrelevant here but I figured it might become relevant as the code gets refactored in the future. This is the only reason I removed the anon class.
|
Added the additional directives as roots for type reference resolution traversal which I was missing the first time and the tests for #1208 and general directive reachability during the traversal. I think it's now ready, but I'm happy to add/change anything if needed. |
| final Map<String, GraphQLType> typeMap = schema.getTypeMap(); | ||
| TRAVERSER.depthFirst(new GraphQLTypeResolvingVisitor(typeMap), typeMap.values()); | ||
| List<GraphQLType> roots = new ArrayList<>(typeMap.values()); | ||
| roots.addAll(schema.getDirectives()); |
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.
GraphQLArgument had previously only been found on a GraphQLFieldDefinition which itself could only been found on a GraphQLObjectType which is regular type. As a result, a type reference in an argument would only be possible within a hierarchy of another type. Now, a GraphQLArgument can be found directly on a directive which is not a real type. As a result, a type reference on an argument can be found outside of a hierarchy of a real type, thus it will not be in the schema's type map. And for those to be replaced correctly, directives need to be added as roots. This may result in a duplicated traversal in some cases (if the type of the directive argument is complex and has a reference inside, and does end up in the type map), but outside of a small performance hit, it has no negative consequences.
I guess it would also be possible for GraphQLTypeCollectingVisitor to also keep track of all top-level references in a separate collection. I'm personally OK with my current approach, but am open to changing it if you wish.
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 see what you are proposing, but not sure I have good enough picture about possible use and edge cases.
Do we allow directives with same names and different arguments?
Can I have a directive, which accepts a complex type which has yet another directive and another type?
Will it matter to distinguish type traversal from traversal of a type under directive(s)?
Please bear with my questions, I will try to catch up with directives and clear my vision.
So far most simplest solution is probably the best strategy :)
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.
- Directives with same names but different arguments - As far as I know, this is not allowed (same unique-name policy as with types). There might already be such a validation in place.
- Directives accepting complex types with further types and directives - Yes, I believe this is legit and is covered.
- Type traversal vs directive type traversal - I don't think there should be anything special about types under directives.
The edge cases I was referring to are mostly about type reference replacement. E.g. if a directive refers to a type found elsewhere in the schema, the reference must be replaced correctly. And vice versa, if another schema element referes to a type first defined on a directive it should work as usual. I tried to cover this in the tests.
For what it's worth, I've been using my fork for a few days now in rather complex scenarios (directives with complex types with references to other complex types with further directives) and it's behaving exactly as I'd expect.
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.
But what I think is worth pointing out is that I don't change any rules in this PR. Everything doable with my changes is also doable without them. You can already add directives to anything, assign arguments of complex types, add further directives to those arguments etc.
All that the change does is make directives reachable by the traverser and, using that, make sure the reference replacement and type collection work in a consistent manner across schema elements.
|
I have to play with it, but so far looks good... let me try to run it. |
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.
LGTM @kaqqao .. great work.
As mentioned here I think we have a general issue with being GraphqlType the Node root interface, but this PR is consistent with the current approach so I am fine with treating GraphQLDirective as GraphQLType.
Is this PR ready for merge in your opinion? You mentioned before tests are missing. I see good tests, but maybe you have more in mind.
Thanks!
|
Yes, I think it's ready. I've added the tests, indeed. |
This both fixes #1208 and adds traversal support for directives as a general feature.
Still needs tests, which I'll add tomorrow.