Make node values type-safe

This commit is contained in:
ChronosX88 2023-11-16 23:17:38 +03:00
parent b83e3ee14e
commit 45e013098f
Signed by: ChronosXYZ
GPG Key ID: 52A90DE5862D8321
21 changed files with 433 additions and 189 deletions

View File

@ -1,88 +0,0 @@
package io.github.chronosx88.JGUN;
import io.github.chronosx88.JGUN.models.MemoryGraph;
import io.github.chronosx88.JGUN.models.Node;
import io.github.chronosx88.JGUN.models.NodeLink;
import io.github.chronosx88.JGUN.models.NodeMetadata;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
public class NodeArrayBuilder {
private final MemoryGraph graph;
private final Node rootNode;
private final List<Object> innerArray;
protected static final String ARRAY_FIELD = "__ARRAY__";
public NodeArrayBuilder() {
this.graph = MemoryGraph.builder().build();
this.innerArray = new ArrayList<>();
this.rootNode = Node.builder()
.metadata(NodeMetadata.builder()
.nodeID(null)
.states(new HashMap<>(Map.of(ARRAY_FIELD, System.currentTimeMillis())))
.build())
.values(Map.of(ARRAY_FIELD, innerArray))
.build();
graph.nodes.put(GraphNodeBuilder.ROOT_NODE, this.rootNode);
}
private NodeArrayBuilder addScalar(Object value) {
this.innerArray.add(value);
this.rootNode.getMetadata().getStates().put(ARRAY_FIELD, System.currentTimeMillis());
return this;
}
public NodeArrayBuilder add(String value) {
return addScalar(value);
}
public NodeArrayBuilder add(BigInteger value) {
return addScalar(value);
}
public NodeArrayBuilder add(BigDecimal value) {
return addScalar(value);
}
public NodeArrayBuilder add(int value) {
return addScalar(value);
}
public NodeArrayBuilder add(long value) {
return addScalar(value);
}
public NodeArrayBuilder add(double value) {
return addScalar(value);
}
public NodeArrayBuilder add(boolean value) {
return addScalar(value);
}
public NodeArrayBuilder addNull(String name) {
return addScalar(null);
}
public NodeArrayBuilder add(GraphNodeBuilder builder) {
String newNodeID = UUID.randomUUID().toString();
//noinspection unchecked
List<Object> innerArray = (List<Object>) rootNode.values.get(ARRAY_FIELD);
innerArray.add(NodeLink.builder()
.link(newNodeID)
.build());
MemoryGraph innerGraph = builder.build();
innerGraph.nodes.get(GraphNodeBuilder.ROOT_NODE).getMetadata().setNodeID(newNodeID);
innerGraph.nodes.put(newNodeID, innerGraph.nodes.get(GraphNodeBuilder.ROOT_NODE));
innerGraph.nodes.remove(GraphNodeBuilder.ROOT_NODE);
this.graph.nodes.putAll(innerGraph.nodes);
return this;
}
public MemoryGraph build() {
return this.graph;
}
}

View File

@ -1,6 +1,6 @@
package io.github.chronosx88.JGUN; package io.github.chronosx88.JGUN.api;
import io.github.chronosx88.JGUN.models.Node; import io.github.chronosx88.JGUN.models.graph.Node;
@FunctionalInterface @FunctionalInterface
public interface NodeChangeListener { public interface NodeChangeListener {

View File

@ -0,0 +1,87 @@
package io.github.chronosx88.JGUN.api.graph;
import io.github.chronosx88.JGUN.models.graph.MemoryGraph;
import io.github.chronosx88.JGUN.models.graph.Node;
import io.github.chronosx88.JGUN.models.graph.NodeValue;
import io.github.chronosx88.JGUN.models.graph.values.*;
import io.github.chronosx88.JGUN.models.graph.NodeMetadata;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
public class ArrayBuilder {
private final MemoryGraph graph;
private final Node rootNode;
private final List<NodeValue> innerArray;
protected static final String ARRAY_FIELD = "__ARRAY__";
public ArrayBuilder() {
this.graph = new MemoryGraph();
this.innerArray = new ArrayList<>();
this.rootNode = Node.builder()
.metadata(NodeMetadata.builder()
.nodeID(null)
.states(new HashMap<>(Map.of(ARRAY_FIELD, System.currentTimeMillis())))
.build())
.values(Map.of(ARRAY_FIELD, new ArrayValue(this.innerArray)))
.build();
graph.nodes.put(NodeBuilder.ROOT_NODE, this.rootNode);
}
private ArrayBuilder addScalar(NodeValue value) {
this.innerArray.add(value);
this.rootNode.getMetadata().getStates().put(ARRAY_FIELD, System.currentTimeMillis());
return this;
}
public ArrayBuilder add(String value) {
return addScalar(new StringValue(value));
}
public ArrayBuilder add(BigInteger value) {
return addScalar(new IntValue(value));
}
public ArrayBuilder add(BigDecimal value) {
return addScalar(new DecimalValue(value));
}
public ArrayBuilder add(int value) {
return addScalar(new IntValue(value));
}
public ArrayBuilder add(long value) {
return addScalar(new IntValue(value));
}
public ArrayBuilder add(double value) {
return addScalar(new DecimalValue(value));
}
public ArrayBuilder add(boolean value) {
return addScalar(new BooleanValue(value));
}
public ArrayBuilder addNull(String name) {
return addScalar(null);
}
public ArrayBuilder add(NodeBuilder builder) {
String newNodeID = UUID.randomUUID().toString();
List<NodeValue> innerArray = ((ArrayValue) rootNode.values.get(ARRAY_FIELD)).getValue();
innerArray.add(NodeLinkValue.builder()
.link(newNodeID)
.build());
MemoryGraph innerGraph = builder.build();
innerGraph.nodes.get(NodeBuilder.ROOT_NODE).getMetadata().setNodeID(newNodeID);
innerGraph.nodes.put(newNodeID, innerGraph.nodes.get(NodeBuilder.ROOT_NODE));
innerGraph.nodes.remove(NodeBuilder.ROOT_NODE);
this.graph.nodes.putAll(innerGraph.nodes);
return this;
}
public MemoryGraph build() {
return this.graph;
}
}

View File

@ -1,22 +1,21 @@
package io.github.chronosx88.JGUN; package io.github.chronosx88.JGUN.api.graph;
import io.github.chronosx88.JGUN.models.MemoryGraph; import io.github.chronosx88.JGUN.models.graph.*;
import io.github.chronosx88.JGUN.models.Node; import io.github.chronosx88.JGUN.models.graph.values.*;
import io.github.chronosx88.JGUN.models.NodeLink; import io.github.chronosx88.JGUN.models.graph.NodeValue;
import io.github.chronosx88.JGUN.models.NodeMetadata;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
public class GraphNodeBuilder { public class NodeBuilder {
private final MemoryGraph graph; private final MemoryGraph graph;
private final Node rootNode; private final Node rootNode;
protected static final String ROOT_NODE = "__ROOT__"; protected static final String ROOT_NODE = "__ROOT__";
public GraphNodeBuilder() { public NodeBuilder() {
this.graph = MemoryGraph.builder().build(); this.graph = new MemoryGraph();
this.rootNode = Node.builder() this.rootNode = Node.builder()
.metadata(NodeMetadata.builder() .metadata(NodeMetadata.builder()
.nodeID(null) .nodeID(null)
@ -25,48 +24,47 @@ public class GraphNodeBuilder {
graph.nodes.put(ROOT_NODE, this.rootNode); graph.nodes.put(ROOT_NODE, this.rootNode);
} }
private GraphNodeBuilder addScalar(String name, Object value) { private NodeBuilder addScalar(String name, NodeValue value) {
rootNode.values.put(name, value); rootNode.values.put(name, value);
rootNode.getMetadata().getStates().put(name, System.currentTimeMillis()); rootNode.getMetadata().getStates().put(name, System.currentTimeMillis());
return this; return this;
} }
public GraphNodeBuilder add(String name, String value) { public NodeBuilder add(String name, String value) {
return addScalar(name, value); return addScalar(name, new StringValue(value));
} }
public GraphNodeBuilder add(String name, BigInteger value) { public NodeBuilder add(String name, BigInteger value) {
return addScalar(name, value); return addScalar(name, new IntValue(value));
} }
public GraphNodeBuilder add(String name, BigDecimal value) { public NodeBuilder add(String name, BigDecimal value) {
return addScalar(name, value); return addScalar(name, new DecimalValue(value));
} }
public GraphNodeBuilder add(String name, int value) { public NodeBuilder add(String name, int value) {
return addScalar(name, value); return addScalar(name, new IntValue(value));
} }
public GraphNodeBuilder add(String name, long value) { public NodeBuilder add(String name, long value) {
return addScalar(name, value); return addScalar(name, new IntValue(value));
} }
public GraphNodeBuilder add(String name, double value) { public NodeBuilder add(String name, double value) {
return addScalar(name, value); return addScalar(name, new DecimalValue(value));
} }
public GraphNodeBuilder add(String name, boolean value) { public NodeBuilder add(String name, boolean value) {
return addScalar(name, value); return addScalar(name, new BooleanValue(value));
} }
public GraphNodeBuilder addNull(String name) { public NodeBuilder addNull(String name) {
return addScalar(name, null); return addScalar(name, null);
} }
public GraphNodeBuilder add(String name, GraphNodeBuilder builder) { public NodeBuilder add(String name, NodeBuilder builder) {
String newNodeID = UUID.randomUUID().toString(); String newNodeID = UUID.randomUUID().toString();
rootNode.values.put(name, NodeLink.builder() rootNode.values.put(name, NodeLinkValue.builder()
.link(newNodeID) .link(newNodeID)
.build()); .build());
MemoryGraph innerGraph = builder.build(); MemoryGraph innerGraph = builder.build();
@ -77,17 +75,16 @@ public class GraphNodeBuilder {
return this; return this;
} }
public GraphNodeBuilder add(String name, NodeArrayBuilder builder) { public NodeBuilder add(String name, ArrayBuilder builder) {
MemoryGraph innerGraph = builder.build(); MemoryGraph innerGraph = builder.build();
//noinspection unchecked var innerArray = (NodeValue) innerGraph.nodes.get(ROOT_NODE).values.get(ArrayBuilder.ARRAY_FIELD);
var innerArray = (List<Object>) innerGraph.nodes.get(ROOT_NODE).values.get(NodeArrayBuilder.ARRAY_FIELD);
rootNode.values.put(name, innerArray); rootNode.values.put(name, innerArray);
rootNode.getMetadata().getStates().put(name, innerGraph rootNode.getMetadata().getStates().put(name, innerGraph
.nodes .nodes
.get(ROOT_NODE) .get(ROOT_NODE)
.getMetadata() .getMetadata()
.getStates() .getStates()
.get(NodeArrayBuilder.ARRAY_FIELD)); .get(ArrayBuilder.ARRAY_FIELD));
innerGraph.nodes.remove(ROOT_NODE); innerGraph.nodes.remove(ROOT_NODE);
graph.nodes.putAll(innerGraph.nodes); graph.nodes.putAll(innerGraph.nodes);
return this; return this;

View File

@ -1,14 +0,0 @@
package io.github.chronosx88.JGUN.models;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder;
import lombok.Data;
import lombok.extern.jackson.Jacksonized;
@Data
@Builder
@Jacksonized
public class NodeLink {
@JsonProperty("#")
String link;
}

View File

@ -1,8 +1,7 @@
package io.github.chronosx88.JGUN.models.acks; package io.github.chronosx88.JGUN.models.acks;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import io.github.chronosx88.JGUN.models.MemoryGraph; import io.github.chronosx88.JGUN.models.graph.MemoryGraph;
import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.experimental.SuperBuilder; import lombok.experimental.SuperBuilder;

View File

@ -1,6 +1,4 @@
package io.github.chronosx88.JGUN.models; package io.github.chronosx88.JGUN.models.graph;
import lombok.Getter;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Delayed; import java.util.concurrent.Delayed;
@ -9,7 +7,7 @@ import java.util.concurrent.TimeUnit;
public class DeferredNode extends Node implements Delayed { public class DeferredNode extends Node implements Delayed {
private long deferredUntil = 0; private long deferredUntil = 0;
DeferredNode(NodeMetadata metadata, Map<String, Object> values) { DeferredNode(NodeMetadata metadata, Map<String, NodeValue> values) {
super(metadata, values); super(metadata, values);
} }

View File

@ -1,4 +1,4 @@
package io.github.chronosx88.JGUN.models; package io.github.chronosx88.JGUN.models.graph;
import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonAnySetter;
@ -11,12 +11,9 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
@Data @Data
@Builder
@Jacksonized
public class MemoryGraph { public class MemoryGraph {
@JsonIgnore @JsonIgnore
@Builder.Default public Map<String, Node> nodes = new LinkedHashMap<>();
public final Map<String, Node> nodes = new LinkedHashMap<>();
@JsonAnyGetter @JsonAnyGetter
public Map<String, Node> nodes() { public Map<String, Node> nodes() {

View File

@ -1,34 +1,38 @@
package io.github.chronosx88.JGUN.models; package io.github.chronosx88.JGUN.models.graph;
import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.extern.jackson.Jacksonized; import lombok.NoArgsConstructor;
import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
@Data @Data
@Jacksonized
@Builder @Builder
@NoArgsConstructor
@AllArgsConstructor
public class Node { public class Node {
@JsonProperty("_") @JsonProperty("_")
private NodeMetadata metadata; @Builder.Default
private final NodeMetadata metadata = new NodeMetadata(new HashMap<>(), null);
@JsonIgnore @JsonIgnore
@Builder.Default @Builder.Default
public Map<String, Object> values = new LinkedHashMap<>(); // Data public final Map<String, NodeValue> values = new LinkedHashMap<>(); // Data
@JsonAnyGetter @JsonAnyGetter
public Map<String, Object> getValues() { public Map<String, NodeValue> getValues() {
return values; return values;
} }
@JsonAnySetter @JsonAnySetter
public void allSetter(String key, String value) { public void allSetter(String key, NodeValue value) {
values.put(key, value); values.put(key, value);
} }
} }

View File

@ -1,4 +1,4 @@
package io.github.chronosx88.JGUN.models; package io.github.chronosx88.JGUN.models.graph;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder; import lombok.Builder;

View File

@ -0,0 +1,19 @@
package io.github.chronosx88.JGUN.models.graph;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
//@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
@JsonDeserialize(using = NodeValueDeserializer.class)
public interface NodeValue {
enum ValueType {
ARRAY,
STRING,
INTEGER,
DECIMAL,
BOOLEAN,
NULL,
LINK
}
ValueType getValueType();
}

View File

@ -0,0 +1,55 @@
package io.github.chronosx88.JGUN.models.graph;
import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import io.github.chronosx88.JGUN.models.graph.values.*;
import java.io.IOException;
import java.util.ArrayList;
public class NodeValueDeserializer extends JsonDeserializer<NodeValue> {
@Override
public NodeValue deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
JsonNode node = p.readValueAsTree();
return parseValue(node);
}
private NodeValue parseValue(JsonNode node) throws JsonProcessingException {
if (node.isBoolean()) {
return new BooleanValue(node.booleanValue());
} else if (node.isBigDecimal()) {
return new DecimalValue(node.decimalValue());
} else if (node.isFloat()) {
return new DecimalValue(node.floatValue());
} else if (node.isDouble()) {
return new DecimalValue(node.doubleValue());
} else if (node.isTextual()) {
return new StringValue(node.textValue());
} else if (node.isInt()) {
return new IntValue(node.intValue());
} else if (node.isBigInteger()) {
return new IntValue(node.bigIntegerValue());
} else if (node.isLong()) {
return new IntValue(node.longValue());
} else if (node.isObject()) {
if (node.has("#")) {
return NodeLinkValue.builder()
.link(node.get("#").textValue())
.build();
} else {
throw new IllegalArgumentException("node can have only links, not actual objects");
}
} else if (node.isArray()) {
ArrayValue value = new ArrayValue();
for (JsonNode arrayItem : node) {
value.getValue().add(parseValue(arrayItem));
}
return value;
}
throw new IllegalArgumentException("unsupported node value");
}
}

View File

@ -0,0 +1,31 @@
package io.github.chronosx88.JGUN.models.graph.values;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import io.github.chronosx88.JGUN.models.graph.NodeValue;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Getter
@NoArgsConstructor
public class ArrayValue implements NodeValue {
@JsonValue
private List<NodeValue> value = new ArrayList<>();
@JsonCreator
public ArrayValue(NodeValue[] value) {
this.value = new ArrayList<>(List.of(value));
}
public ArrayValue(List<NodeValue> value) {
this.value = value;
}
@Override
public ValueType getValueType() {
return ValueType.ARRAY;
}
}

View File

@ -0,0 +1,22 @@
package io.github.chronosx88.JGUN.models.graph.values;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import io.github.chronosx88.JGUN.models.graph.NodeValue;
import lombok.Getter;
@Getter
public class BooleanValue implements NodeValue {
@JsonValue
private boolean value;
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
public BooleanValue(boolean value) {
this.value = value;
}
@Override
public NodeValue.ValueType getValueType() {
return NodeValue.ValueType.BOOLEAN;
}
}

View File

@ -0,0 +1,40 @@
package io.github.chronosx88.JGUN.models.graph.values;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import io.github.chronosx88.JGUN.models.graph.NodeValue;
import java.math.BigDecimal;
public class DecimalValue implements NodeValue {
@JsonValue
private BigDecimal value;
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
public DecimalValue(double num) {
this.value = BigDecimal.valueOf(num);
}
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
public DecimalValue(float num) {
this.value = BigDecimal.valueOf(num);
}
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
public DecimalValue(BigDecimal value) {
this.value = value;
}
@Override
public ValueType getValueType() {
return ValueType.DECIMAL;
}
public double getDouble() {
return value.floatValue();
}
public float getFloat() {
return value.floatValue();
}
}

View File

@ -0,0 +1,44 @@
package io.github.chronosx88.JGUN.models.graph.values;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import io.github.chronosx88.JGUN.models.graph.NodeValue;
import java.math.BigInteger;
public class IntValue implements NodeValue {
@JsonValue
public BigInteger value;
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
public IntValue(int value) {
this.value = BigInteger.valueOf(value);
}
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
public IntValue(long value) {
this.value = BigInteger.valueOf(value);
}
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
public IntValue(BigInteger value) {
this.value = value;
}
public int getInt() {
return value.intValue();
}
public BigInteger getBig() {
return value;
}
public long getLong() {
return value.longValue();
}
@Override
public ValueType getValueType() {
return ValueType.INTEGER;
}
}

View File

@ -0,0 +1,22 @@
package io.github.chronosx88.JGUN.models.graph.values;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.github.chronosx88.JGUN.models.graph.NodeValue;
import lombok.Builder;
import lombok.Data;
import lombok.extern.jackson.Jacksonized;
@Data
@Builder
@Jacksonized
public class NodeLinkValue implements NodeValue {
@JsonProperty("#")
private String link;
@Override
@JsonIgnore
public ValueType getValueType() {
return ValueType.LINK;
}
}

View File

@ -0,0 +1,23 @@
package io.github.chronosx88.JGUN.models.graph.values;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import io.github.chronosx88.JGUN.models.graph.NodeValue;
import lombok.Getter;
@Getter
public class StringValue implements NodeValue {
@JsonValue
private String value;
@JsonCreator
public StringValue(String value) {
this.value = value;
}
@Override
public ValueType getValueType() {
return ValueType.STRING;
}
}

View File

@ -3,8 +3,8 @@ package io.github.chronosx88.JGUN.storage;
import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.Expiry; import com.github.benmanes.caffeine.cache.Expiry;
import io.github.chronosx88.JGUN.models.DeferredNode; import io.github.chronosx88.JGUN.models.graph.DeferredNode;
import io.github.chronosx88.JGUN.models.Node; import io.github.chronosx88.JGUN.models.graph.Node;
import org.checkerframework.checker.index.qual.NonNegative; import org.checkerframework.checker.index.qual.NonNegative;
import java.util.Collection; import java.util.Collection;

View File

@ -1,11 +1,8 @@
package io.github.chronosx88.JGUN.storage; package io.github.chronosx88.JGUN.storage;
import io.github.chronosx88.JGUN.HAM; import io.github.chronosx88.JGUN.api.NodeChangeListener;
import io.github.chronosx88.JGUN.NodeChangeListener; import io.github.chronosx88.JGUN.models.graph.*;
import io.github.chronosx88.JGUN.models.DeferredNode; import io.github.chronosx88.JGUN.models.graph.NodeValue;
import io.github.chronosx88.JGUN.models.MemoryGraph;
import io.github.chronosx88.JGUN.models.Node;
import io.github.chronosx88.JGUN.models.NodeMetadata;
import java.util.*; import java.util.*;
@ -36,7 +33,7 @@ public abstract class Storage {
*/ */
public void mergeUpdate(MemoryGraph update) { public void mergeUpdate(MemoryGraph update) {
long machine = System.currentTimeMillis(); long machine = System.currentTimeMillis();
MemoryGraph diff = MemoryGraph.builder().build(); MemoryGraph diff = new MemoryGraph();
for (Map.Entry<String, Node> entry : update.getNodes().entrySet()) { for (Map.Entry<String, Node> entry : update.getNodes().entrySet()) {
Node node = entry.getValue(); Node node = entry.getValue();
Node diffNode = this.mergeNode(node, machine); Node diffNode = this.mergeNode(node, machine);
@ -57,7 +54,7 @@ public abstract class Storage {
changeListeners.get(diffEntry.getKey()).forEach((e) -> e.onChange(diffEntry.getValue())); changeListeners.get(diffEntry.getKey()).forEach((e) -> e.onChange(diffEntry.getValue()));
} }
if (mapChangeListeners.containsKey(diffEntry.getKey())) { if (mapChangeListeners.containsKey(diffEntry.getKey())) {
for (Map.Entry<String, Object> nodeEntry : changedNode.getValues().entrySet()) { for (Map.Entry<String, NodeValue> nodeEntry : changedNode.getValues().entrySet()) {
mapChangeListeners.get(nodeEntry.getKey()).forEach((e) -> e.onChange(nodeEntry.getKey(), nodeEntry.getValue())); mapChangeListeners.get(nodeEntry.getKey()).forEach((e) -> e.onChange(nodeEntry.getKey(), nodeEntry.getValue()));
} }
} }
@ -75,7 +72,7 @@ public abstract class Storage {
public Node mergeNode(Node incomingNode, long machineState) { public Node mergeNode(Node incomingNode, long machineState) {
Node changedNode = null; Node changedNode = null;
for (String key : incomingNode.getValues().keySet()) { for (String key : incomingNode.getValues().keySet()) {
Object value = incomingNode.getValues().get(key); NodeValue value = incomingNode.getValues().get(key);
long state = incomingNode.getMetadata().getStates().get(key); long state = incomingNode.getMetadata().getStates().get(key);
long previousState = -1; long previousState = -1;
Object currentValue = null; Object currentValue = null;

View File

@ -3,61 +3,72 @@ package io.github.chronosx88.JGUN;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import io.github.chronosx88.JGUN.api.graph.NodeBuilder;
import io.github.chronosx88.JGUN.api.graph.ArrayBuilder;
import io.github.chronosx88.JGUN.models.graph.MemoryGraph;
import io.github.chronosx88.JGUN.models.graph.values.IntValue;
import io.github.chronosx88.JGUN.models.graph.values.NodeLinkValue;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
class GraphNodeBuilderTest { class GraphNodeBuilderTest {
@Test @Test
void Test_sampleGraph1() { void Test_sampleGraph1() throws JsonProcessingException {
var objectMapper = new ObjectMapper(); var objectMapper = new ObjectMapper();
objectMapper.registerModule(new Jdk8Module()); objectMapper.registerModule(new Jdk8Module());
var graph = new GraphNodeBuilder() var graph = new NodeBuilder()
.add("firstName", "John") .add("firstName", "John")
.add("lastName", "Smith") .add("lastName", "Smith")
.add("age", 25) .add("age", 25)
.add("address", new GraphNodeBuilder() .add("address", new NodeBuilder()
.add("streetAddress", "21 2nd Street") .add("streetAddress", "21 2nd Street")
.add("city", "New York") .add("city", "New York")
.add("state", "NY") .add("state", "NY")
.add("postalCode", "10021")) .add("postalCode", "10021"))
.add("phoneNumber", new NodeArrayBuilder() .add("phoneNumber", new ArrayBuilder()
.add(new GraphNodeBuilder() .add(new NodeBuilder()
.add("type", "home") .add("type", "home")
.add("number", "212 555-1234")) .add("number", "212 555-1234"))
.add(new GraphNodeBuilder() .add(new NodeBuilder()
.add("type", "fax") .add("type", "fax")
.add("number", "646 555-4567"))) .add("number", "646 555-4567")))
.addNull("heh")
.build(); .build();
String graphJSON = null; String graphJSON1 = objectMapper.writeValueAsString(graph);
try { System.out.println(graphJSON1);
graphJSON = objectMapper.writeValueAsString(graph);
} catch (JsonProcessingException e) { graph = objectMapper.readValue(graphJSON1, MemoryGraph.class);
throw new RuntimeException(e); String graphJSON2 = objectMapper.writeValueAsString(graph);
} System.out.println(graphJSON2);
System.out.println(graphJSON);
assertEquals(graphJSON1, graphJSON2);
assertEquals(((IntValue) graph.nodes.get("__ROOT__").getValues().get("age")).getInt(), 25);
assertTrue(graph.nodes.get("__ROOT__").getValues().get("address") instanceof NodeLinkValue);
} }
@Test @Test
void Test_sampleGraph2() { void Test_sampleGraph2() throws JsonProcessingException {
var objectMapper = new ObjectMapper(); var objectMapper = new ObjectMapper();
objectMapper.registerModule(new Jdk8Module()); objectMapper.registerModule(new Jdk8Module());
var graph = new GraphNodeBuilder() var graph = new NodeBuilder()
.add("a", new NodeArrayBuilder() .add("a", new ArrayBuilder()
.add(new GraphNodeBuilder() .add(new NodeBuilder()
.add("b", new GraphNodeBuilder() .add("b", new NodeBuilder()
.add("c", true))) .add("c", true)))
.add(0)) .add(0))
.build(); .build();
String graphJSON = null; String graphJSON = objectMapper.writeValueAsString(graph);
try { System.out.println(graphJSON);
graphJSON = objectMapper.writeValueAsString(graph);
} catch (JsonProcessingException e) { graph = objectMapper.readValue(graphJSON, MemoryGraph.class);
throw new RuntimeException(e); graphJSON = objectMapper.writeValueAsString(graph);
}
System.out.println(graphJSON); System.out.println(graphJSON);
} }
} }