graphql.util.NodeZipper Maven / Gradle / Ivy
package graphql.util;
import com.google.common.collect.ImmutableList;
import graphql.PublicApi;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import static graphql.Assert.assertNotNull;
@PublicApi
public class NodeZipper {
public enum ModificationType {
REPLACE,
DELETE,
INSERT_AFTER,
INSERT_BEFORE
}
private final T curNode;
private final NodeAdapter nodeAdapter;
// reverse: the breadCrumbs start from curNode upwards
private final List> breadcrumbs;
private final ModificationType modificationType;
public NodeZipper(T curNode, List> breadcrumbs, NodeAdapter nodeAdapter) {
this(curNode, breadcrumbs, nodeAdapter, ModificationType.REPLACE);
}
public NodeZipper(T curNode, List> breadcrumbs, NodeAdapter nodeAdapter, ModificationType modificationType) {
this.curNode = assertNotNull(curNode);
this.breadcrumbs = ImmutableList.copyOf(assertNotNull(breadcrumbs));
this.nodeAdapter = nodeAdapter;
this.modificationType = modificationType;
}
public ModificationType getModificationType() {
return modificationType;
}
public T getCurNode() {
return curNode;
}
public List> getBreadcrumbs() {
return breadcrumbs;
}
public T getParent() {
return breadcrumbs.get(0).getNode();
}
public static NodeZipper rootZipper(T rootNode, NodeAdapter nodeAdapter) {
return new NodeZipper(rootNode, new ArrayList<>(), nodeAdapter);
}
public NodeZipper modifyNode(Function transform) {
return new NodeZipper(transform.apply(curNode), breadcrumbs, nodeAdapter, this.modificationType);
}
public NodeZipper deleteNode() {
return new NodeZipper(this.curNode, breadcrumbs, nodeAdapter, ModificationType.DELETE);
}
public NodeZipper insertAfter(T toInsertAfter) {
return new NodeZipper(toInsertAfter, breadcrumbs, nodeAdapter, ModificationType.INSERT_AFTER);
}
public NodeZipper insertBefore(T toInsertBefore) {
return new NodeZipper(toInsertBefore, breadcrumbs, nodeAdapter, ModificationType.INSERT_BEFORE);
}
public NodeZipper withNewNode(T newNode) {
return new NodeZipper(newNode, breadcrumbs, nodeAdapter, this.modificationType);
}
public NodeZipper moveUp() {
T node = getParent();
List> newBreadcrumbs = breadcrumbs.subList(1, breadcrumbs.size());
return new NodeZipper<>(node, newBreadcrumbs, nodeAdapter, this.modificationType);
}
/**
* @return null if it is the root node and marked as deleted, otherwise never null
*/
public T toRoot() {
if (breadcrumbs.size() == 0 && modificationType != ModificationType.DELETE) {
return this.curNode;
}
if (breadcrumbs.size() == 0 && modificationType == ModificationType.DELETE) {
return null;
}
T curNode = this.curNode;
Breadcrumb firstBreadcrumb = breadcrumbs.get(0);
Map> childrenForParent = new HashMap<>(nodeAdapter.getNamedChildren(firstBreadcrumb.getNode()));
NodeLocation locationInParent = firstBreadcrumb.getLocation();
int ix = locationInParent.getIndex();
String name = locationInParent.getName();
List childList = new ArrayList<>(childrenForParent.get(name));
switch (modificationType) {
case REPLACE:
childList.set(ix, curNode);
break;
case DELETE:
childList.remove(ix);
break;
case INSERT_BEFORE:
childList.add(ix, curNode);
break;
case INSERT_AFTER:
childList.add(ix + 1, curNode);
break;
}
childrenForParent.put(name, childList);
curNode = nodeAdapter.withNewChildren(firstBreadcrumb.getNode(), childrenForParent);
if (breadcrumbs.size() == 1) {
return curNode;
}
for (Breadcrumb breadcrumb : breadcrumbs.subList(1, breadcrumbs.size())) {
// just handle replace
Map> newChildren = new LinkedHashMap<>(nodeAdapter.getNamedChildren(breadcrumb.getNode()));
final T newChild = curNode;
NodeLocation location = breadcrumb.getLocation();
List list = new ArrayList<>(newChildren.get(location.getName()));
list.set(location.getIndex(), newChild);
newChildren.put(location.getName(), list);
curNode = nodeAdapter.withNewChildren(breadcrumb.getNode(), newChildren);
}
return curNode;
}
@Override
public String toString() {
return "NodeZipper{" +
"curNode=" + curNode +
", breadcrumbs.size=" + breadcrumbs.size() +
", modificationType=" + modificationType +
'}';
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy