All Downloads are FREE. Search and download functionalities are using the official Maven repository.

graphql.util.DefaultTraverserContext Maven / Gradle / Ivy

package graphql.util;

import com.google.common.collect.ImmutableList;
import graphql.Internal;
import graphql.collect.ImmutableKit;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static graphql.Assert.assertFalse;
import static graphql.Assert.assertNotNull;
import static graphql.Assert.assertNull;
import static graphql.Assert.assertTrue;

@Internal
public class DefaultTraverserContext implements TraverserContext {

    private final T curNode;
    private T newNode;
    private boolean nodeDeleted;

    private final TraverserContext parent;
    private final Set visited;
    private final Map, Object> vars;
    private final Object sharedContextData;

    private Object newAccValue;
    private boolean hasNewAccValue;
    private Object curAccValue;
    private final NodeLocation location;
    private final boolean isRootContext;
    private boolean parallel;
    private Map>> children;
    private Phase phase;
    private final List> breadcrumbs;

    public DefaultTraverserContext(T curNode,
                                   TraverserContext parent,
                                   Set visited,
                                   Map, Object> vars,
                                   Object sharedContextData,
                                   NodeLocation location,
                                   boolean isRootContext,
                                   boolean parallel) {
        this.curNode = curNode;
        this.parent = parent;
        this.visited = visited;
        this.vars = vars;
        this.sharedContextData = sharedContextData;
        this.location = location;
        this.isRootContext = isRootContext;
        this.parallel = parallel;

        if (parent == null || parent.isRootContext()) {
            this.breadcrumbs = ImmutableKit.emptyList();
        } else {
            List> breadcrumbs = new ArrayList<>(parent.getBreadcrumbs().size() + 1);
            breadcrumbs.add(new Breadcrumb<>(this.parent.thisNode(), this.location));
            breadcrumbs.addAll(parent.getBreadcrumbs());
            this.breadcrumbs = ImmutableList.copyOf(breadcrumbs);
        }
    }

    public static  DefaultTraverserContext dummy() {
        return new DefaultTraverserContext<>(null, null, null, null, null, null, true, false);
    }

    public static  DefaultTraverserContext simple(T node) {
        return new DefaultTraverserContext<>(node, null, null, null, null, null, true, false);
    }

    @Override
    public T thisNode() {
        assertFalse(this.nodeDeleted, () -> "node is deleted");
        if (newNode != null) {
            return newNode;
        }
        return curNode;
    }

    @Override
    public T originalThisNode() {
        return curNode;
    }

    @Override
    public void changeNode(T newNode) {
        assertNotNull(newNode);
        assertFalse(this.nodeDeleted, () -> "node is deleted");
        this.newNode = newNode;
    }


    @Override
    public void deleteNode() {
        assertNull(this.newNode, () -> "node is already changed");
        assertFalse(this.nodeDeleted, () -> "node is already deleted");
        this.nodeDeleted = true;
    }

    @Override
    public boolean isDeleted() {
        return this.nodeDeleted;
    }

    @Override
    public boolean isChanged() {
        return this.newNode != null;
    }


    @Override
    public TraverserContext getParentContext() {
        return parent;
    }

    @Override
    public List getParentNodes() {
        List result = new ArrayList<>();
        TraverserContext curContext = parent;
        while (!curContext.isRootContext()) {
            result.add(curContext.thisNode());
            curContext = curContext.getParentContext();
        }
        return result;
    }

    @Override
    public List> getBreadcrumbs() {
        return breadcrumbs;
    }

    @Override
    public T getParentNode() {
        if (parent == null) {
            return null;
        }
        return parent.thisNode();
    }

    @Override
    public Set visitedNodes() {
        return visited;
    }

    @Override
    public boolean isVisited() {
        return visited.contains(curNode);
    }

    @Override
    public  S getVar(Class key) {
        return (S) key.cast(vars.get(key));
    }

    @Override
    public  TraverserContext setVar(Class key, S value) {
        vars.put(key, value);
        return this;
    }

    @Override
    public void setAccumulate(Object accumulate) {
        hasNewAccValue = true;
        newAccValue = accumulate;
    }

    @Override
    public  U getNewAccumulate() {
        if (hasNewAccValue) {
            return (U) newAccValue;
        } else {
            return (U) curAccValue;
        }
    }

    @Override
    public  U getCurrentAccumulate() {
        return (U) curAccValue;
    }


    @Override
    public Object getSharedContextData() {
        return sharedContextData;
    }

    /*
     * PRIVATE: Used by {@link Traverser}
     */
    void setCurAccValue(Object curAccValue) {
        hasNewAccValue = false;
        this.curAccValue = curAccValue;
    }

    @Override
    public NodeLocation getLocation() {
        return location;
    }

    @Override
    public boolean isRootContext() {
        return isRootContext;
    }

    @Override
    public  S getVarFromParents(Class key) {
        TraverserContext curContext = parent;
        while (curContext != null) {
            S var = curContext.getVar(key);
            if (var != null) {
                return var;
            }
            curContext = curContext.getParentContext();
        }
        return null;
    }

    /*
     * PRIVATE: Used by {@link Traverser}
     */
    void setChildrenContexts(Map>> children) {
        assertTrue(this.children == null, () -> "children already set");
        this.children = children;
    }


    @Override
    public Map>> getChildrenContexts() {
        assertNotNull(children, () -> "children not available");
        return children;
    }

    /*
     * PRIVATE: Used by {@link Traverser}
     */
    void setPhase(Phase phase) {
        this.phase = phase;
    }

    @Override
    public Phase getPhase() {
        return phase;
    }

    @Override
    public boolean isParallel() {
        return parallel;
    }
}