Skip to content

Commit 1518a2e

Browse files
author
DvirDukhan
authored
added path support (#52)
* added path support * added path builder * added example to readme.md
1 parent 9ec317b commit 1518a2e

File tree

9 files changed

+364
-13
lines changed

9 files changed

+364
-13
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ package com.redislabs.redisgraph;
9090

9191
import com.redislabs.redisgraph.graph_entities.Edge;
9292
import com.redislabs.redisgraph.graph_entities.Node;
93+
import com.redislabs.redisgraph.graph_entities.Path;
9394
import com.redislabs.redisgraph.impl.api.RedisGraph;
9495

9596
import java.util.List;
@@ -115,6 +116,15 @@ public class RedisGraphExample {
115116
System.out.println(record.toString());
116117
}
117118

119+
resultSet = graph.query("social", "MATCH p = (:person)-[:knows]->(:person) RETURN p");
120+
while(resultSet.hasNext()) {
121+
Record record = resultSet.next();
122+
Path p = record.getValue("p");
123+
124+
// More path API at Javadoc.
125+
System.out.println(p.nodeCount());
126+
}
127+
118128
// delete graph
119129
graph.deleteGraph("social");
120130

pom.xml

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,25 @@
7575
<version>1.6.6</version>
7676
<scope>test</scope>
7777
</dependency>
78-
</dependencies>
78+
<dependency>
79+
<groupId>org.junit.jupiter</groupId>
80+
<artifactId>junit-jupiter</artifactId>
81+
<version>RELEASE</version>
82+
<scope>test</scope>
83+
</dependency>
84+
<dependency>
85+
<groupId>org.junit.jupiter</groupId>
86+
<artifactId>junit-jupiter</artifactId>
87+
<version>RELEASE</version>
88+
<scope>test</scope>
89+
</dependency>
90+
<dependency>
91+
<groupId>nl.jqno.equalsverifier</groupId>
92+
<artifactId>equalsverifier</artifactId>
93+
<version>3.1.10</version>
94+
<scope>test</scope>
95+
</dependency>
96+
</dependencies>
7997
<properties>
8098
<maven.compiler.source>8</maven.compiler.source>
8199
<maven.compiler.target>8</maven.compiler.target>
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package com.redislabs.redisgraph.graph_entities;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import java.util.Objects;
6+
7+
/**
8+
* This class represents a path in the graph.
9+
*/
10+
public final class Path {
11+
12+
private final List<Node> nodes;
13+
private final List<Edge> edges;
14+
15+
16+
/**
17+
* Parametrized constructor
18+
* @param nodes - List of nodes.
19+
* @param edges - List of edges.
20+
*/
21+
public Path(List<Node> nodes, List<Edge> edges) {
22+
this.nodes = nodes;
23+
this.edges = edges;
24+
}
25+
26+
/**
27+
* Returns the nodes of the path.
28+
* @return List of nodes.
29+
*/
30+
public List<Node> getNodes() {
31+
return nodes;
32+
}
33+
34+
/**
35+
* Returns the edges of the path.
36+
* @return List of edges.
37+
*/
38+
public List<Edge> getEdges() {
39+
return edges;
40+
}
41+
42+
/**
43+
* Returns the length of the path - number of edges.
44+
* @return Number of edges.
45+
*/
46+
public int length() {
47+
return edges.size();
48+
}
49+
50+
/**
51+
* Return the number of nodes in the path.
52+
* @return Number of nodes.
53+
*/
54+
public int nodeCount(){
55+
return nodes.size();
56+
}
57+
58+
/**
59+
* Returns the first node in the path.
60+
* @return First nodes in the path.
61+
* @throws IndexOutOfBoundsException if the path is empty.
62+
*/
63+
public Node firstNode(){
64+
return nodes.get(0);
65+
}
66+
67+
/**
68+
* Returns the last node in the path.
69+
* @return Last nodes in the path.
70+
* @throws IndexOutOfBoundsException if the path is empty.
71+
*/
72+
public Node lastNode(){
73+
return nodes.get(nodes.size() - 1);
74+
}
75+
76+
/**
77+
* Returns a node with specified index in the path.
78+
* @return Node.
79+
* @throws IndexOutOfBoundsException if the index is out of range
80+
* ({@code index < 0 || index >= nodesCount()})
81+
*/
82+
public Node getNode(int index){
83+
return nodes.get(index);
84+
}
85+
86+
/**
87+
* Returns an edge with specified index in the path.
88+
* @return Edge.
89+
* @throws IndexOutOfBoundsException if the index is out of range
90+
* ({@code index < 0 || index >= length()})
91+
*/
92+
public Edge getEdge(int index){
93+
return edges.get(index);
94+
}
95+
96+
@Override
97+
public boolean equals(Object o) {
98+
if (this == o) return true;
99+
if (o == null || getClass() != o.getClass()) return false;
100+
Path path = (Path) o;
101+
return Objects.equals(nodes, path.nodes) &&
102+
Objects.equals(edges, path.edges);
103+
}
104+
105+
@Override
106+
public int hashCode() {
107+
return Objects.hash(nodes, edges);
108+
}
109+
110+
@Override
111+
public String toString() {
112+
final StringBuilder sb = new StringBuilder("Path{");
113+
sb.append("nodes=").append(nodes);
114+
sb.append(", edges=").append(edges);
115+
sb.append('}');
116+
return sb.toString();
117+
}
118+
}

src/main/java/com/redislabs/redisgraph/impl/resultset/ResultSetImpl.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@
66
import com.redislabs.redisgraph.ResultSet;
77
import com.redislabs.redisgraph.Statistics;
88
import com.redislabs.redisgraph.exceptions.JRedisGraphRunTimeException;
9-
import com.redislabs.redisgraph.graph_entities.Edge;
10-
import com.redislabs.redisgraph.graph_entities.GraphEntity;
11-
import com.redislabs.redisgraph.graph_entities.Node;
12-
import com.redislabs.redisgraph.graph_entities.Property;
9+
import com.redislabs.redisgraph.graph_entities.*;
1310
import com.redislabs.redisgraph.impl.graph_cache.GraphCache;
1411
import redis.clients.jedis.util.SafeEncoder;
1512
import redis.clients.jedis.exceptions.JedisDataException;
@@ -245,12 +242,21 @@ private Object deserializeScalar(List<Object> rawScalarData) {
245242
return deserializeNode((List<Object>) obj);
246243
case VALUE_EDGE:
247244
return deserializeEdge((List<Object>) obj);
245+
case VALUE_PATH:
246+
return deserializePath(obj);
248247
case VALUE_UNKNOWN:
249248
default:
250249
return obj;
251250
}
252251
}
253252

253+
private Path deserializePath(Object rawScalarData) {
254+
List<List<Object>> array = (List<List<Object>>) rawScalarData;
255+
List<Node> nodes = (List<Node>) deserializeScalar(array.get(0));
256+
List<Edge> edges = (List<Edge>) deserializeScalar(array.get(1));
257+
return new Path(nodes, edges);
258+
}
259+
254260
private List<Object> deserializeArray(Object rawScalarData) {
255261
List<List<Object>> array = (List<List<Object>>) rawScalarData;
256262
List<Object> res = new ArrayList<>(array.size());

src/main/java/com/redislabs/redisgraph/impl/resultset/ResultSetScalarTypes.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ enum ResultSetScalarTypes {
1111
VALUE_DOUBLE,
1212
VALUE_ARRAY,
1313
VALUE_EDGE,
14-
VALUE_NODE;
14+
VALUE_NODE,
15+
VALUE_PATH;
1516

1617

1718
static ResultSetScalarTypes[] values = values();

src/test/java/com/redislabs/redisgraph/RedisGraphAPITest.java

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,26 @@
11
package com.redislabs.redisgraph;
22

33

4-
import java.util.Arrays;
5-
import java.util.List;
6-
import java.util.NoSuchElementException;
4+
import java.util.*;
75
import java.util.stream.Collectors;
86
import java.util.stream.IntStream;
97

108
import com.redislabs.redisgraph.graph_entities.Edge;
119
import com.redislabs.redisgraph.graph_entities.Node;
10+
import com.redislabs.redisgraph.graph_entities.Path;
1211
import com.redislabs.redisgraph.graph_entities.Property;
1312
import com.redislabs.redisgraph.impl.api.RedisGraph;
1413
import com.redislabs.redisgraph.impl.resultset.ResultSetImpl;
15-
import org.junit.After;
16-
import org.junit.Assert;
17-
import org.junit.Before;
18-
import org.junit.Test;
14+
import com.redislabs.redisgraph.test.utils.PathBuilder;
15+
import org.junit.*;
1916

2017
import com.redislabs.redisgraph.Statistics.Label;
18+
import org.junit.rules.ExpectedException;
2119

2220
import static com.redislabs.redisgraph.Header.ResultSetColumnTypes.*;
2321

2422
public class RedisGraphAPITest {
23+
2524
private RedisGraphContextGenerator api;
2625

2726
public RedisGraphAPITest() {
@@ -878,4 +877,47 @@ record = resultSet.next();
878877

879878
}
880879

880+
@Test
881+
public void testPath(){
882+
List<Node> nodes = new ArrayList<>(3);
883+
for(int i =0; i < 3; i++){
884+
Node node = new Node();
885+
node.setId(i);
886+
node.addLabel("L1");
887+
nodes.add(node);
888+
}
889+
890+
List<Edge> edges = new ArrayList<>(2);
891+
for(int i =0; i <2; i++){
892+
Edge edge = new Edge();
893+
edge.setId(i);
894+
edge.setRelationshipType("R1");
895+
edge.setSource(i);
896+
edge.setDestination(i + 1);
897+
edges.add(edge);
898+
}
899+
900+
Set<Path> expectedPaths = new HashSet<>();
901+
902+
Path path01 = new PathBuilder(2).append(nodes.get(0)).append(edges.get(0)).append(nodes.get(1)).build();
903+
Path path12 = new PathBuilder(2).append(nodes.get(1)).append(edges.get(1)).append(nodes.get(2)).build();
904+
Path path02 = new PathBuilder(3).append(nodes.get(0)).append(edges.get(0)).append(nodes.get(1)).append(edges.get(1)).append(nodes.get(2)).build();
905+
906+
expectedPaths.add(path01);
907+
expectedPaths.add(path12);
908+
expectedPaths.add(path02);
909+
910+
api.query("social", "CREATE (:L1)-[:R1]->(:L1)-[:R1]->(:L1)");
911+
912+
ResultSet resultSet = api.query("social", "MATCH p = (:L1)-[:R1*]->(:L1) RETURN p");
913+
914+
Assert.assertEquals(expectedPaths.size(), resultSet.size());
915+
for(int i =0; i < resultSet.size(); i++){
916+
Path p = resultSet.next().getValue("p");
917+
Assert.assertTrue(expectedPaths.contains(p));
918+
expectedPaths.remove(p);
919+
}
920+
921+
}
922+
881923
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.redislabs.redisgraph.graph_entities;
2+
3+
import nl.jqno.equalsverifier.EqualsVerifier;
4+
import org.junit.Test;
5+
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
import java.util.concurrent.ThreadLocalRandom;
9+
import java.util.stream.Collectors;
10+
import java.util.stream.IntStream;
11+
12+
import static org.junit.jupiter.api.Assertions.*;
13+
14+
public class PathTest {
15+
16+
private Node buildNode(int id){
17+
Node n = new Node();
18+
n.setId(0);
19+
return n;
20+
}
21+
22+
private Edge buildEdge(int id, int src, int dst){
23+
Edge e = new Edge();
24+
e.setId(id);
25+
e.setSource(src);
26+
e.setDestination(dst);
27+
return e;
28+
}
29+
30+
private List<Node> buildNodeArray(int size) {
31+
List<Node> nodes = new ArrayList<>();
32+
return IntStream.range(0, size).mapToObj(i -> buildNode(i)).collect(Collectors.toList());
33+
}
34+
35+
private List<Edge> buildEdgeArray(int size){
36+
List<Node> nodes = new ArrayList<>();
37+
return IntStream.range(0, size).mapToObj(i -> buildEdge(i, i, i+1)).collect(Collectors.toList());
38+
}
39+
40+
private Path buildPath(int nodeCount){
41+
return new Path(buildNodeArray(nodeCount), buildEdgeArray(nodeCount-1));
42+
}
43+
44+
@Test
45+
public void testEmptyPath(){
46+
Path path = buildPath(0);
47+
assertEquals(0, path.length());
48+
assertEquals(0, path.nodeCount());
49+
assertThrows(IndexOutOfBoundsException.class, ()->path.getNode(0));
50+
assertThrows(IndexOutOfBoundsException.class, ()->path.getEdge(0));
51+
}
52+
53+
@Test
54+
public void testSingleNodePath(){
55+
Path path = buildPath(1);
56+
assertEquals(0, path.length());
57+
assertEquals(1, path.nodeCount());
58+
Node n = new Node();
59+
n.setId(0);
60+
assertEquals(n, path.firstNode());
61+
assertEquals(n, path.lastNode());
62+
assertEquals(n, path.getNode(0));
63+
}
64+
65+
@Test
66+
public void testRandomLengthPath(){
67+
int nodeCount = ThreadLocalRandom.current().nextInt(2, 100 + 1);
68+
Path path = buildPath(nodeCount);
69+
assertEquals(buildNodeArray(nodeCount), path.getNodes());
70+
assertEquals(buildEdgeArray(nodeCount-1), path.getEdges());
71+
assertDoesNotThrow(()->path.getEdge(0));
72+
}
73+
74+
@Test
75+
public void hashCodeEqualTest(){
76+
EqualsVerifier.forClass(Path.class).verify();
77+
}
78+
}

0 commit comments

Comments
 (0)