Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,13 @@ public TraversalControl visitFragmentDefinition(FragmentDefinition node, Travers
return TraversalControl.ABORT;
}

QueryVisitorFragmentDefinitionEnvironment fragmentEnvironment = new QueryVisitorFragmentDefinitionEnvironmentImpl(node, context);

if (context.getVar(NodeTraverser.LeaveOrEnter.class) == LEAVE) {
postOrderCallback.visitFragmentDefinition(fragmentEnvironment);
return TraversalControl.CONTINUE;
}

preOrderCallback.visitFragmentDefinition(fragmentEnvironment);

QueryTraversalContext parentEnv = context.getVarFromParents(QueryTraversalContext.class);
GraphQLCompositeType typeCondition = (GraphQLCompositeType) schema.getType(node.getTypeCondition().getName());
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/graphql/analysis/QueryVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,8 @@ public interface QueryVisitor {

void visitFragmentSpread(QueryVisitorFragmentSpreadEnvironment queryVisitorFragmentSpreadEnvironment);

default void visitFragmentDefinition(QueryVisitorFragmentDefinitionEnvironment queryVisitorFragmentDefinitionEnvironment) {

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package graphql.analysis;

import graphql.PublicApi;
import graphql.language.FragmentDefinition;
import graphql.language.Node;
import graphql.util.TraverserContext;

@PublicApi
public interface QueryVisitorFragmentDefinitionEnvironment {
FragmentDefinition getFragmentDefinition();

TraverserContext<Node> getTraverserContext();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package graphql.analysis;

import graphql.Internal;
import graphql.language.FragmentDefinition;
import graphql.language.Node;
import graphql.util.TraverserContext;

import java.util.Objects;

@Internal
public class QueryVisitorFragmentDefinitionEnvironmentImpl implements QueryVisitorFragmentDefinitionEnvironment {

private final FragmentDefinition fragmentDefinition;
private final TraverserContext<Node> traverserContext;


public QueryVisitorFragmentDefinitionEnvironmentImpl(FragmentDefinition fragmentDefinition, TraverserContext<Node> traverserContext) {
this.fragmentDefinition = fragmentDefinition;
this.traverserContext = traverserContext;
}

@Override
public FragmentDefinition getFragmentDefinition() {
return fragmentDefinition;
}

@Override
public TraverserContext<Node> getTraverserContext() {
return traverserContext;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
QueryVisitorFragmentDefinitionEnvironmentImpl that = (QueryVisitorFragmentDefinitionEnvironmentImpl) o;
return Objects.equals(fragmentDefinition, that.fragmentDefinition);
}

@Override
public int hashCode() {
return Objects.hash(fragmentDefinition);
}

@Override
public String toString() {
return "QueryVisitorFragmentDefinitionEnvironmentImpl{" +
"fragmentDefinition=" + fragmentDefinition +
'}';
}
}

14 changes: 12 additions & 2 deletions src/test/groovy/graphql/analysis/QueryTransformerTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import graphql.language.Document
import graphql.language.Field
import graphql.language.NodeUtil
import graphql.language.SelectionSet
import graphql.language.TypeName
import graphql.parser.Parser
import graphql.schema.GraphQLSchema
import spock.lang.Specification
Expand Down Expand Up @@ -207,7 +208,7 @@ class QueryTransformerTest extends Specification {
0 * _
}

def "named fragment is traversed if it is a root and can be transformed"() {
def "fragment definition is traversed if it is a root and can be transformed"() {
def query = TestUtil.parseQuery('''
{
root {
Expand Down Expand Up @@ -241,13 +242,22 @@ class QueryTransformerTest extends Specification {
})
}
}

@Override
void visitFragmentDefinition(QueryVisitorFragmentDefinitionEnvironment env) {
def changed = env.fragmentDefinition.transform({ builder ->
builder.typeCondition(TypeName.newTypeName("newTypeName").build())
.name("newFragName")
})
changeNode(env.traverserContext, changed)
}
}


when:
def newFragment = queryTransformer.transform(visitor)
then:
printAstCompact(newFragment) ==
"fragment frag on Root {fooA {midA {newChild1 newChild2}}}"
"fragment newFragName on newTypeName {fooA {midA {newChild1 newChild2}}}"
}
}
49 changes: 49 additions & 0 deletions src/test/groovy/graphql/analysis/QueryTraversalTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import graphql.language.FragmentDefinition
import graphql.language.FragmentSpread
import graphql.language.InlineFragment
import graphql.language.NodeTraverser
import graphql.language.NodeUtil
import graphql.parser.Parser
import graphql.schema.GraphQLNonNull
import graphql.schema.GraphQLObjectType
Expand Down Expand Up @@ -302,6 +303,54 @@ class QueryTraversalTest extends Specification {

}


def "test preOrder and postOrder order for fragment definitions"() {
given:
def schema = TestUtil.schema("""
type Query{
foo: Foo
bar: String
}
type Foo {
subFoo: String
}
""")
def visitor = Mock(QueryVisitor)
def query = createQuery("""
{
...F1
}

fragment F1 on Query {
foo {
subFoo
}
}
""")

def fragments = NodeUtil.getFragmentsByName(query)

QueryTraversal queryTraversal = QueryTraversal.newQueryTraversal()
.schema(schema)
.root(fragments["F1"])
.rootParentType(schema.getQueryType())
.fragmentsByName(fragments)
.variables([:])
.build()

when:
queryTraversal.visitPreOrder(visitor)

then:
1 * visitor.visitFragmentDefinition({ QueryVisitorFragmentDefinitionEnvironment env -> env.fragmentDefinition == fragments["F1"] })

when:
queryTraversal.visitPostOrder(visitor)

then:
1 * visitor.visitFragmentDefinition({ QueryVisitorFragmentDefinitionEnvironment env -> env.fragmentDefinition == fragments["F1"] })
}

def "works for mutations()"() {
given:
def schema = TestUtil.schema("""
Expand Down