Search in sources :

Example 1 with NodeZipper

use of graphql.util.NodeZipper 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 NodeZipper

use of graphql.util.NodeZipper 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)

Example 3 with NodeZipper

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

the class BatchedExecutionStrategy method resolveNodes.

// all multizipper have the same root
private CompletableFuture<NodeMultiZipper<ExecutionResultNode>> resolveNodes(ExecutionContext executionContext, List<NodeMultiZipper<ExecutionResultNode>> unresolvedNodes) {
    assertNotEmpty(unresolvedNodes, () -> "unresolvedNodes can't be empty");
    ExecutionResultNode commonRoot = unresolvedNodes.get(0).getCommonRoot();
    CompletableFuture<List<List<NodeZipper<ExecutionResultNode>>>> listListCF = Async.flatMap(unresolvedNodes, executionResultMultiZipper -> fetchAndAnalyze(executionContext, executionResultMultiZipper.getZippers()));
    return flatList(listListCF).thenApply(zippers -> new NodeMultiZipper<ExecutionResultNode>(commonRoot, zippers, RESULT_NODE_ADAPTER));
}
Also used : ExecutionResultNode(graphql.execution.nextgen.result.ExecutionResultNode) ObjectExecutionResultNode(graphql.execution.nextgen.result.ObjectExecutionResultNode) RootExecutionResultNode(graphql.execution.nextgen.result.RootExecutionResultNode) NodeZipper(graphql.util.NodeZipper) ArrayList(java.util.ArrayList) FpKit.flatList(graphql.util.FpKit.flatList) ImmutableList(com.google.common.collect.ImmutableList) List(java.util.List)

Aggregations

NodeZipper (graphql.util.NodeZipper)3 ArrayList (java.util.ArrayList)3 List (java.util.List)3 Breadcrumb (graphql.util.Breadcrumb)2 NodeLocation (graphql.util.NodeLocation)2 HashMap (java.util.HashMap)2 LinkedHashMap (java.util.LinkedHashMap)2 LinkedList (java.util.LinkedList)2 ImmutableList (com.google.common.collect.ImmutableList)1 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 ExecutionResultNode (graphql.execution.nextgen.result.ExecutionResultNode)1 ObjectExecutionResultNode (graphql.execution.nextgen.result.ObjectExecutionResultNode)1 RootExecutionResultNode (graphql.execution.nextgen.result.RootExecutionResultNode)1 SCHEMA_ELEMENT_ADAPTER (graphql.schema.GraphQLSchemaElementAdapter.SCHEMA_ELEMENT_ADAPTER)1 SchemaElementChildrenContainer.newSchemaElementChildrenContainer (graphql.schema.SchemaElementChildrenContainer.newSchemaElementChildrenContainer)1