-
Notifications
You must be signed in to change notification settings - Fork 173
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
DictionaryResolverType should use return GraphQLObjectType from Schema rather than cached map #593
DictionaryResolverType should use return GraphQLObjectType from Schema rather than cached map #593
Conversation
@timward60 this looks good. Could you come up with a test scenario for this? I'm a little confused as to how you ran into this because the type resolvers run during |
Trying to wrap my head around how to best test this. The existing test validate there are no regressions. I could try coding up a integration test that post-transforms the schema, but it seems a bit heavy. I can try to code up some simpler unit tests. Any suggestions on what approach to take?
var baseGraphQLSchema = schemaParser.makeExecutableSchema();
var federatedGraphQLSchema = Federation.transform(baseGraphQLSchema)
.fetchEntities(federationDataFetcher.orElseThrow())
.resolveEntityType(federationTypeResolver.orElseThrow())
.build(); Basically the transforms occur after make executable schema. In addition to the example above using the Federation transform from GraphQL-Java-Federation, we have another transform that deletes fields which ends up mutating the GraphQL schema objects using the TreeTransformerUtil.* utilities. For example: final class VersionTransformer extends GraphQLTypeVisitorStub {
...
@Override
public TraversalControl visitGraphQLFieldDefinition(
GraphQLFieldDefinition node, TraverserContext<GraphQLSchemaElement> context) {
return visit(node, node, context);
}
...
private TraversalControl visit(
GraphQLSchemaElement element,
GraphQLDirectiveContainer directiveContainer,
TraverserContext<GraphQLSchemaElement> context) {
var optionalVersion = getVersion(directiveContainer);
if (optionalVersion.isEmpty()) {
return visitGraphQLType(element, context);
}
var fieldVersion = optionalVersion.get();
if (fieldVersion.compareTo(version) > 0) {
return TreeTransformerUtil.deleteNode(context);
}
return visitGraphQLType(element, context);
}
...
}
var baseGraphQLSchema = schemaParser.makeExecutableSchema();
var transformedGraphQLSchema = new SchemaTransformer().transform(baseGraphQLSchema, new VersionTransformer()); |
A test that builds a simple schema, transforms it (deletes a type?) and tries to run a query that would fail before the fix would be good.
If that's true then using the cached map should be ok because it's done before the transformer is executed. So I'm still not sure how does transforming the schema interferes with the dictionary resolver? |
I'll try my best, but the GraphQL-Java transformer logic is quite complex, trying to determine how to replicate this without bringing in our entire schema has been challenging.
That is the problem, the transformer results in a new instances of certain GraphQL types, which means the CacheMap is pointing to an old unreferenced instance from the pre-transformed schema. The GraphQL schema instance maintains the correct mapping. The consequence of not doing this is that later on when the GraphQL-Java is processing queries they use equality checks for GraphQL types which fail due to the cache map returning an orphaned GraphQL type instance. |
@oryan-block Added a test that reproduces the issue before my fix (private branch), let me know if there is anything else you need me to address? |
Thanks @timward60 I'll take a look soon. |
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.
Good stuff!
Just for my own clarity: the problem here was that the type resolvers are created and stored in the code registry before the transformer runs. These resolvers are then used when trying to run queries and they have an outdated reference to the schema objects so nothing is found.
Fixes #592
Checklist
Description
The DictionaryResolverType was returning GraphQL Schema Objects from a cache, however if the shema is transformed by SchemaTransformer, these GraphQL Schema Objects instances can change.
As such we should resolve the GraphQLObjectType from the schema object rather than a local cache.