Search in sources :

Example 1 with Breadcrumb

use of graphql.util.Breadcrumb 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);
}
Also used : TraversalControl(graphql.util.TraversalControl) Traverser(graphql.util.Traverser) SCHEMA_ELEMENT_ADAPTER(graphql.schema.GraphQLSchemaElementAdapter.SCHEMA_ELEMENT_ADAPTER) HashMap(java.util.HashMap) Multimap(com.google.common.collect.Multimap) NodeLocation(graphql.util.NodeLocation) StronglyConnectedComponentsTopologicallySorted.getStronglyConnectedComponentsTopologicallySorted(graphql.schema.impl.StronglyConnectedComponentsTopologicallySorted.getStronglyConnectedComponentsTopologicallySorted) TraverserContext(graphql.util.TraverserContext) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) Breadcrumb(graphql.util.Breadcrumb) Assert.assertShouldNeverHappen(graphql.Assert.assertShouldNeverHappen) NodeAdapter(graphql.util.NodeAdapter) Map(java.util.Map) SchemaElementChildrenContainer.newSchemaElementChildrenContainer(graphql.schema.SchemaElementChildrenContainer.newSchemaElementChildrenContainer) LinkedList(java.util.LinkedList) LinkedHashMultimap(com.google.common.collect.LinkedHashMultimap) LinkedHashSet(java.util.LinkedHashSet) REPLACE(graphql.util.NodeZipper.ModificationType.REPLACE) TraverserVisitor(graphql.util.TraverserVisitor) Iterator(java.util.Iterator) CONTINUE(graphql.util.TraversalControl.CONTINUE) Collection(java.util.Collection) Set(java.util.Set) DELETE(graphql.util.NodeZipper.ModificationType.DELETE) String.format(java.lang.String.format) Consumer(java.util.function.Consumer) NodeZipper(graphql.util.NodeZipper) List(java.util.List) PublicApi(graphql.PublicApi) Assert.assertNotNull(graphql.Assert.assertNotNull) Assert.assertNotEmpty(graphql.Assert.assertNotEmpty) Collections(java.util.Collections) ArrayList(java.util.ArrayList) TraverserContext(graphql.util.TraverserContext) LinkedHashMap(java.util.LinkedHashMap) TraverserVisitor(graphql.util.TraverserVisitor) TraversalControl(graphql.util.TraversalControl) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) List(java.util.List) SCHEMA_ELEMENT_ADAPTER(graphql.schema.GraphQLSchemaElementAdapter.SCHEMA_ELEMENT_ADAPTER) Breadcrumb(graphql.util.Breadcrumb) LinkedList(java.util.LinkedList) NodeZipper(graphql.util.NodeZipper)

Example 2 with Breadcrumb

use of graphql.util.Breadcrumb in project graphql-java by graphql-java.

the class SchemaTransformer method moveUp.

private NodeZipper<GraphQLSchemaElement> moveUp(GraphQLSchemaElement parent, Map<NodeZipper<GraphQLSchemaElement>, Breadcrumb<GraphQLSchemaElement>> sameParentsZipper) {
    Set<NodeZipper<GraphQLSchemaElement>> sameParent = sameParentsZipper.keySet();
    assertNotEmpty(sameParent, () -> "expected at least one zipper");
    Map<String, List<GraphQLSchemaElement>> childrenMap = new HashMap<>(SCHEMA_ELEMENT_ADAPTER.getNamedChildren(parent));
    Map<String, Integer> indexCorrection = new HashMap<>();
    List<ZipperWithOneParent> zipperWithOneParents = new ArrayList<>();
    for (NodeZipper<GraphQLSchemaElement> zipper : sameParent) {
        Breadcrumb<GraphQLSchemaElement> breadcrumb = sameParentsZipper.get(zipper);
        zipperWithOneParents.add(new ZipperWithOneParent(zipper, breadcrumb));
    }
    zipperWithOneParents.sort((zipperWithOneParent1, zipperWithOneParent2) -> {
        NodeZipper<GraphQLSchemaElement> zipper1 = zipperWithOneParent1.zipper;
        NodeZipper<GraphQLSchemaElement> zipper2 = zipperWithOneParent2.zipper;
        Breadcrumb<GraphQLSchemaElement> breadcrumb1 = zipperWithOneParent1.parent;
        Breadcrumb<GraphQLSchemaElement> breadcrumb2 = zipperWithOneParent2.parent;
        int index1 = breadcrumb1.getLocation().getIndex();
        int index2 = breadcrumb2.getLocation().getIndex();
        if (index1 != index2) {
            return Integer.compare(index1, index2);
        }
        NodeZipper.ModificationType modificationType1 = zipper1.getModificationType();
        NodeZipper.ModificationType modificationType2 = zipper2.getModificationType();
        if (modificationType1 == modificationType2) {
            return 0;
        }
        // always first replacing the node
        if (modificationType1 == REPLACE) {
            return -1;
        }
        // and then INSERT_BEFORE before INSERT_AFTER
        return modificationType1 == NodeZipper.ModificationType.INSERT_BEFORE ? -1 : 1;
    });
    for (ZipperWithOneParent zipperWithOneParent : zipperWithOneParents) {
        NodeZipper<GraphQLSchemaElement> zipper = zipperWithOneParent.zipper;
        Breadcrumb<GraphQLSchemaElement> breadcrumb = zipperWithOneParent.parent;
        NodeLocation location = breadcrumb.getLocation();
        Integer ixDiff = indexCorrection.getOrDefault(location.getName(), 0);
        int ix = location.getIndex() + ixDiff;
        String name = location.getName();
        List<GraphQLSchemaElement> childList = new ArrayList<>(childrenMap.get(name));
        switch(zipper.getModificationType()) {
            case REPLACE:
                childList.set(ix, zipper.getCurNode());
                break;
            case DELETE:
                childList.remove(ix);
                indexCorrection.put(name, ixDiff - 1);
                break;
            case INSERT_BEFORE:
                childList.add(ix, zipper.getCurNode());
                indexCorrection.put(name, ixDiff + 1);
                break;
            case INSERT_AFTER:
                childList.add(ix + 1, zipper.getCurNode());
                indexCorrection.put(name, ixDiff + 1);
                break;
        }
        childrenMap.put(name, childList);
    }
    GraphQLSchemaElement newNode = SCHEMA_ELEMENT_ADAPTER.withNewChildren(parent, childrenMap);
    final List<Breadcrumb<GraphQLSchemaElement>> oldBreadcrumbs = sameParent.iterator().next().getBreadcrumbs();
    List<Breadcrumb<GraphQLSchemaElement>> newBreadcrumbs;
    if (oldBreadcrumbs.size() > 1) {
        newBreadcrumbs = oldBreadcrumbs.subList(1, oldBreadcrumbs.size());
    } else {
        newBreadcrumbs = Collections.emptyList();
    }
    return new NodeZipper<>(newNode, newBreadcrumbs, SCHEMA_ELEMENT_ADAPTER);
}
Also used : HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ArrayList(java.util.ArrayList) Breadcrumb(graphql.util.Breadcrumb) NodeLocation(graphql.util.NodeLocation) NodeZipper(graphql.util.NodeZipper) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) List(java.util.List)

Aggregations

Breadcrumb (graphql.util.Breadcrumb)2 NodeLocation (graphql.util.NodeLocation)2 NodeZipper (graphql.util.NodeZipper)2 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 LinkedHashMap (java.util.LinkedHashMap)2 LinkedList (java.util.LinkedList)2 List (java.util.List)2 LinkedHashMultimap (com.google.common.collect.LinkedHashMultimap)1 Multimap (com.google.common.collect.Multimap)1 Assert.assertNotEmpty (graphql.Assert.assertNotEmpty)1 Assert.assertNotNull (graphql.Assert.assertNotNull)1 Assert.assertShouldNeverHappen (graphql.Assert.assertShouldNeverHappen)1 PublicApi (graphql.PublicApi)1 SCHEMA_ELEMENT_ADAPTER (graphql.schema.GraphQLSchemaElementAdapter.SCHEMA_ELEMENT_ADAPTER)1 SchemaElementChildrenContainer.newSchemaElementChildrenContainer (graphql.schema.SchemaElementChildrenContainer.newSchemaElementChildrenContainer)1 StronglyConnectedComponentsTopologicallySorted.getStronglyConnectedComponentsTopologicallySorted (graphql.schema.impl.StronglyConnectedComponentsTopologicallySorted.getStronglyConnectedComponentsTopologicallySorted)1 NodeAdapter (graphql.util.NodeAdapter)1 DELETE (graphql.util.NodeZipper.ModificationType.DELETE)1 REPLACE (graphql.util.NodeZipper.ModificationType.REPLACE)1