From 2e664b4adba2c2922de674e968b56c2376af4717 Mon Sep 17 00:00:00 2001 From: Brad Baker Date: Wed, 7 Sep 2022 13:26:08 +1000 Subject: [PATCH] Stable fix for #2943 Merge pull request #2934 from graphql-java/Renamed_scalar_still_present_in_the_schema_if_used_as_directive_argument Reproduction of renaming scalars and applied directives bug # Conflicts: # src/test/groovy/graphql/schema/SchemaTransformerTest.groovy --- .../GraphQLAppliedDirectiveArgument.java | 13 +++- src/main/java/graphql/util/Breadcrumb.java | 10 ++- src/main/java/graphql/util/NodeLocation.java | 2 +- .../schema/SchemaTransformerTest.groovy | 75 +++++++++++++++++++ 4 files changed, 95 insertions(+), 5 deletions(-) diff --git a/src/main/java/graphql/schema/GraphQLAppliedDirectiveArgument.java b/src/main/java/graphql/schema/GraphQLAppliedDirectiveArgument.java index dd595a539..594242520 100644 --- a/src/main/java/graphql/schema/GraphQLAppliedDirectiveArgument.java +++ b/src/main/java/graphql/schema/GraphQLAppliedDirectiveArgument.java @@ -11,6 +11,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; @@ -34,6 +35,8 @@ public class GraphQLAppliedDirectiveArgument implements GraphQLNamedSchemaElemen private final Argument definition; + public static final String CHILD_TYPE = "type"; + private GraphQLAppliedDirectiveArgument(String name, InputValueWithState value, GraphQLInputType type, @@ -104,19 +107,23 @@ public Argument getDefinition() { @Override public List getChildren() { - return ImmutableKit.emptyList(); + List children = new ArrayList<>(); + children.add(getType()); + return children; } - @Override public SchemaElementChildrenContainer getChildrenWithTypeReferences() { return SchemaElementChildrenContainer.newSchemaElementChildrenContainer() + .child(CHILD_TYPE, originalType) .build(); } @Override public GraphQLAppliedDirectiveArgument withNewChildren(SchemaElementChildrenContainer newChildren) { - return this; + return transform(builder -> + builder.type(newChildren.getChildOrNull(CHILD_TYPE)) + ); } @Override diff --git a/src/main/java/graphql/util/Breadcrumb.java b/src/main/java/graphql/util/Breadcrumb.java index cae637efd..ad1415a00 100644 --- a/src/main/java/graphql/util/Breadcrumb.java +++ b/src/main/java/graphql/util/Breadcrumb.java @@ -3,6 +3,7 @@ import graphql.PublicApi; import java.util.Objects; +import java.util.StringJoiner; /** * A specific {@link NodeLocation} inside a node. This means {@link #getNode()} returns a Node which has a child @@ -47,9 +48,16 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = 1; - result = 31 * result + Objects.hashCode(node); + result = 31 * result + Objects.hashCode(node); result = 31 * result + Objects.hashCode(location); return result; } + @Override + public String toString() { + return new StringJoiner(", ", "[", "]") + .add("" + location) + .add("" + node) + .toString(); + } } diff --git a/src/main/java/graphql/util/NodeLocation.java b/src/main/java/graphql/util/NodeLocation.java index 61851b0b6..8a1f9f10b 100644 --- a/src/main/java/graphql/util/NodeLocation.java +++ b/src/main/java/graphql/util/NodeLocation.java @@ -33,7 +33,7 @@ public int getIndex() { @Override public String toString() { - return "NodeLocation{" + + return "{" + "name='" + name + '\'' + ", index=" + index + '}'; diff --git a/src/test/groovy/graphql/schema/SchemaTransformerTest.groovy b/src/test/groovy/graphql/schema/SchemaTransformerTest.groovy index 4d41f672b..c315553f1 100644 --- a/src/test/groovy/graphql/schema/SchemaTransformerTest.groovy +++ b/src/test/groovy/graphql/schema/SchemaTransformerTest.groovy @@ -841,4 +841,79 @@ type Query { } ''' } + + def "can rename scalars"() { + + def schema = TestUtil.schema(""" + scalar Foo + type Query { + field : Foo + } +""") + + def visitor = new GraphQLTypeVisitorStub() { + + @Override + TraversalControl visitGraphQLScalarType(GraphQLScalarType node, TraverserContext context) { + if (node.getName().equals("Foo")) { + GraphQLScalarType newNode = node.transform({sc -> sc.name("Bar")}) + return changeNode(context, newNode) + } + return super.visitGraphQLScalarType(node, context) + } + } + + when: + def newSchema = SchemaTransformer.transformSchema(schema, visitor) + then: + newSchema.getType("Bar") instanceof GraphQLScalarType + newSchema.getType("Foo") == null + (newSchema.getObjectType("Query").getFieldDefinition("field").getType() as GraphQLScalarType).getName() == "Bar" + } + + def "rename scalars are changed in applied arguments"() { + + def schema = TestUtil.schema(""" + scalar Foo + directive @myDirective(fooArgOnDirective: Foo) on FIELD_DEFINITION + type Query { + foo(fooArgOnField: Foo) : Foo @myDirective + } +""") + + def visitor = new GraphQLTypeVisitorStub() { + + @Override + TraversalControl visitGraphQLScalarType(GraphQLScalarType node, TraverserContext context) { + if (node.getName().equals("Foo")) { + GraphQLScalarType newNode = node.transform({sc -> sc.name("Bar")}) + return changeNode(context, newNode) + } + return super.visitGraphQLScalarType(node, context) + } + } + + when: + def newSchema = SchemaTransformer.transformSchema(schema, visitor) + then: + + def fieldDef = newSchema.getObjectType("Query").getFieldDefinition("foo") + def appliedDirective = fieldDef.getAppliedDirective("myDirective") + def oldSkoolDirective = fieldDef.getDirective("myDirective") + def argument = fieldDef.getArgument("fooArgOnField") + def directiveDecl = newSchema.getDirective("myDirective") + def directiveArgument = directiveDecl.getArgument("fooArgOnDirective") + + (fieldDef.getType() as GraphQLScalarType).getName() == "Bar" + (argument.getType() as GraphQLScalarType).getName() == "Bar" + (directiveArgument.getType() as GraphQLScalarType).getName() == "Bar" + + (oldSkoolDirective.getArgument("fooArgOnDirective").getType() as GraphQLScalarType).getName() == "Bar" + + newSchema.getType("Bar") instanceof GraphQLScalarType + + // not working at this stage + (appliedDirective.getArgument("fooArgOnDirective").getType() as GraphQLScalarType).getName() == "Bar" + newSchema.getType("Foo") == null + } }