use of graphql.util.Traverser in project graphql-java by graphql-java.
the class SchemaTransformer method traverseAndTransform.
private boolean traverseAndTransform(DummyRoot dummyRoot, Map<String, GraphQLNamedType> changedTypes, Map<String, GraphQLTypeReference> typeReferences, GraphQLTypeVisitor visitor, GraphQLCodeRegistry.Builder codeRegistry) {
List<NodeZipper<GraphQLSchemaElement>> zippers = new LinkedList<>();
Map<GraphQLSchemaElement, NodeZipper<GraphQLSchemaElement>> zipperByNodeAfterTraversing = new LinkedHashMap<>();
Map<GraphQLSchemaElement, NodeZipper<GraphQLSchemaElement>> zipperByOriginalNode = new LinkedHashMap<>();
Map<NodeZipper<GraphQLSchemaElement>, List<List<Breadcrumb<GraphQLSchemaElement>>>> breadcrumbsByZipper = new LinkedHashMap<>();
Map<GraphQLSchemaElement, List<GraphQLSchemaElement>> reverseDependencies = new LinkedHashMap<>();
Map<String, List<GraphQLSchemaElement>> typeRefReverseDependencies = new LinkedHashMap<>();
TraverserVisitor<GraphQLSchemaElement> nodeTraverserVisitor = new TraverserVisitor<GraphQLSchemaElement>() {
@Override
public TraversalControl enter(TraverserContext<GraphQLSchemaElement> context) {
GraphQLSchemaElement currentSchemaElement = context.thisNode();
if (currentSchemaElement == dummyRoot) {
return TraversalControl.CONTINUE;
}
if (currentSchemaElement instanceof GraphQLTypeReference) {
GraphQLTypeReference typeRef = (GraphQLTypeReference) currentSchemaElement;
typeReferences.put(typeRef.getName(), typeRef);
}
NodeZipper<GraphQLSchemaElement> nodeZipper = new NodeZipper<>(currentSchemaElement, context.getBreadcrumbs(), SCHEMA_ELEMENT_ADAPTER);
context.setVar(NodeZipper.class, nodeZipper);
context.setVar(NodeAdapter.class, SCHEMA_ELEMENT_ADAPTER);
int zippersBefore = zippers.size();
TraversalControl result = currentSchemaElement.accept(context, visitor);
// detection if the node was changed
if (zippersBefore + 1 == zippers.size()) {
nodeZipper = zippers.get(zippers.size() - 1);
if (context.originalThisNode() instanceof GraphQLNamedType && context.isChanged()) {
GraphQLNamedType originalNamedType = (GraphQLNamedType) context.originalThisNode();
GraphQLNamedType changedNamedType = (GraphQLNamedType) context.thisNode();
if (!originalNamedType.getName().equals(changedNamedType.getName())) {
changedTypes.put(originalNamedType.getName(), changedNamedType);
}
}
}
zipperByOriginalNode.put(context.originalThisNode(), nodeZipper);
if (context.isDeleted()) {
zipperByNodeAfterTraversing.put(context.originalThisNode(), nodeZipper);
} else {
zipperByNodeAfterTraversing.put(context.thisNode(), nodeZipper);
}
breadcrumbsByZipper.put(nodeZipper, new ArrayList<>());
breadcrumbsByZipper.get(nodeZipper).add(context.getBreadcrumbs());
if (nodeZipper.getModificationType() != NodeZipper.ModificationType.DELETE) {
reverseDependencies.computeIfAbsent(context.thisNode(), ign -> new ArrayList<>()).add(context.getParentNode());
if (context.originalThisNode() instanceof GraphQLTypeReference) {
String typeName = ((GraphQLTypeReference) context.originalThisNode()).getName();
typeRefReverseDependencies.computeIfAbsent(typeName, ign -> new ArrayList<>()).add(context.getParentNode());
}
}
return result;
}
@Override
public TraversalControl leave(TraverserContext<GraphQLSchemaElement> context) {
return TraversalControl.CONTINUE;
}
@Override
public TraversalControl backRef(TraverserContext<GraphQLSchemaElement> context) {
NodeZipper<GraphQLSchemaElement> zipper = zipperByOriginalNode.get(context.thisNode());
breadcrumbsByZipper.get(zipper).add(context.getBreadcrumbs());
if (zipper.getModificationType() == DELETE) {
return CONTINUE;
}
visitor.visitBackRef(context);
List<GraphQLSchemaElement> reverseDependenciesForCurNode = reverseDependencies.get(zipper.getCurNode());
assertNotNull(reverseDependenciesForCurNode);
reverseDependenciesForCurNode.add(context.getParentNode());
return TraversalControl.CONTINUE;
}
};
Traverser<GraphQLSchemaElement> traverser = Traverser.depthFirstWithNamedChildren(SCHEMA_ELEMENT_ADAPTER::getNamedChildren, zippers, null);
if (codeRegistry != null) {
traverser.rootVar(GraphQLCodeRegistry.Builder.class, codeRegistry);
}
traverser.traverse(dummyRoot, nodeTraverserVisitor);
List<List<GraphQLSchemaElement>> stronglyConnectedTopologicallySorted = getStronglyConnectedComponentsTopologicallySorted(reverseDependencies, typeRefReverseDependencies);
return zipUpToDummyRoot(zippers, stronglyConnectedTopologicallySorted, breadcrumbsByZipper, zipperByNodeAfterTraversing);
}
Aggregations