-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Xuorig Fix PR - Edge case with GraphQLTypeReference and Schema Transforms #2906
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
|
I debugged this further. The reason this blows up (even for SchemaTransformer changes along with direct ones) is this The first step of the schema build code calls this At this point the map is meant to contain a map of name -> ACTUAL types (and not type references) Later the type reference replacement code finds all type references and expects to find the actual type for them in the map above and its does not and asserts. However this particular edit means that the schema DOES have a field pointer to a actual type but the This makes sense in SDL generation because its impossible to create a situation where the actual type is not declared but code declaration can make this happen as demonstrated in this PR test case. |
|
Ok debugging more - this is more about the Traverser related code In this "edit case" we have a field Then the code does and edit and this gets rid of the direct reference to type B (which came via another field chain) but this field So Type B is still around in some form The and the callback to the So while the replace type is in place - its never used. The question is - should it be? |
|
The code rightly wants a DAG - if we change it, it starts to fail with
The challenge here is this. The edit caused the field to be the only reference to the It's as if the specific use case GraphQLTypeCollectingVisitor needs to grab dangling field references and do a fix up if they are missing - eg type referenced but not in the schema in some other way |
| } | ||
| type = unwrapOne(type); | ||
| } | ||
| return unwrapAllAs(type); |
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 was probably a mistake to have the well named unwrapAll return GraphQLUnmodifiedType which excludes GraphqlTypeReferences - but API is API so leave it as is
I did change how it works internally here
| GraphQLNamedType type = unwrapAllAs(node.getType()); | ||
| if (! (type instanceof GraphQLTypeReference)) { | ||
| fieldActualTypes.put(type.getName(), type); | ||
| } |
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 only puts in fields that unwrap to be an actual type
| private Map<String, GraphQLNamedType> fixFieldDanglingTypes(Map<String, GraphQLNamedType> visitedTypes) { | ||
| for (GraphQLNamedType fieldPointerType : fieldActualTypes.values()) { | ||
| String typeName = fieldPointerType.getName(); | ||
| visitedTypes.putIfAbsent(typeName, fieldPointerType); |
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.
if we have a type pointed to by a field AND it's not the the list of visited types, we add it since the field is the only pointer to it say
| throw new AssertException(format("All types within a GraphQL schema must have unique names. No two provided types may have the same name.\n" + | ||
| "No provided type may have a name which conflicts with any built in types (including Scalar and Introspection types).\n" + | ||
| "You have redefined the type '%s' from being a '%s' to a '%s'", | ||
| type.getName(), existingType.getClass().getSimpleName(), type.getClass().getSimpleName())); |
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.
made a common method here
|
|
||
| then: | ||
| transformed.containsType("B") | ||
|
|
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.
Andres original test that was failing
| GraphQLSchema transformed = SchemaTransformer.transformSchema(schema, visitor) | ||
|
|
||
| then: | ||
| transformed.containsType("B") |
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 SchemaTransformer test that was failing and now passing
| then: | ||
| schema.getType("A") != null | ||
| schema.getType("B") != null | ||
| } |
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.
Direct object test case (no SDL) that was failing and is now passing
| then: | ||
| typeRef instanceof GraphQLTypeReference | ||
| (typeRef as GraphQLTypeReference).name == "A" | ||
|
|
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.
Extra tests as unwrapAllAs was not previously covered
|
|
||
| when: | ||
| def schema = TestUtil.schema(sdl) | ||
| // When field `a` is filtered out |
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.
b is filtered out
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.
updated
| assertTypeUniqueness(node, result); | ||
| save(node.getName(), node); | ||
| return super.visitGraphQLScalarType(node, context); | ||
| return CONTINUE; |
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.
all of this super code boiled down to CONTINUE!
xuorig
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.
Appreciate the fix! Very similar solution to the workaround I implemented but much much nicer now that it is built in in the type collector. Thanks 🙇
* 19.3: (709 commits) use class loader in getResource (graphql-java#3038) Stable port of graphql-java#2940 (graphql-java#2947) Stable port of Diff counts are the same (graphql-java#2946) Stable port of Fix printing directives when they contain something like a formatting specifier (graphql-java#2919) (graphql-java#2920) (graphql-java#2945) Stable port of Fix field visibility bug with enum with enum args (graphql-java#2926) (graphql-java#2944) Stable fix for graphql-java#2943 (graphql-java#2943) Added test fore intersection Xuorig Fix PR - Edge case with GraphQLTypeReference and Schema Transforms (graphql-java#2906) Fix typo in description of skip directive (graphql-java#2915) Add smaller set first optimisation Cheaper calculation for narrowing down possible objects in ENO Handles isDeprecated not being present in the json Defaults Locale when calling validation (graphql-java#2908) DF SelectionSet Benchmark (graphql-java#2893) Test stability (graphql-java#2903) Donna's catch! (graphql-java#2900) Deprecate Apollo Cache Control READY - Stop DOS attacks by making the lexer stop early on evil input. (graphql-java#2892) Bump java-dataloader ahead of release State is passed explicitly to instrumentation and parameters are NOT mutated (graphql-java#2769) ... # Conflicts: # README.md # build.gradle # src/main/java/graphql/GraphQL.java # src/main/java/graphql/Scalars.java # src/main/java/graphql/execution/ValuesResolver.java # src/main/java/graphql/relay/SimpleListConnection.java # src/main/java/graphql/schema/DataFetchingEnvironmentImpl.java
This is the same code as #2905 but with an extra test for
SchemaTransformerwhich also fails