Skip to content

Commit 31997c0

Browse files
author
DvirDukhan
committed
Modified ResultSet implementation to handle new compact query answer,
as well as new interface modifications
1 parent 630c5d8 commit 31997c0

File tree

1 file changed

+261
-70
lines changed

1 file changed

+261
-70
lines changed

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

Lines changed: 261 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -3,78 +3,269 @@
33
import java.util.ArrayList;
44
import java.util.List;
55
import java.util.NoSuchElementException;
6-
import java.util.stream.Collectors;
6+
import java.util.Objects;
77

8-
import com.redislabs.redisgraph.Record;
9-
import com.redislabs.redisgraph.ResultSet;
10-
import com.redislabs.redisgraph.Statistics;
8+
import com.redislabs.redisgraph.*;
119

1210
import redis.clients.jedis.util.SafeEncoder;
1311

14-
public class ResultSetImpl implements ResultSet{
15-
16-
private final int totalResults;
17-
private final List<String> header;
18-
private final List<Record> results;
19-
private final Statistics statistics;
20-
private int position = 0;
21-
22-
public ResultSetImpl(List<Object> resp) {
23-
24-
this.statistics = new StatisticsImpl((List<byte[]>)resp.get(1));
25-
26-
ArrayList<ArrayList<?>> result = (ArrayList<ArrayList<?>>) resp.get(0);
27-
28-
// Empty result set
29-
if(result == null || result.isEmpty()) {
30-
header = new ArrayList<>(0);
31-
totalResults = 0;
32-
results = new ArrayList<>(0);
33-
} else {
34-
ArrayList<byte[]> headers = (ArrayList<byte[]>)result.get(0);
35-
header = headers.stream().map( String::new).collect(Collectors.toList());
36-
37-
// First row is a header row
38-
totalResults = result.size()-1;
39-
results = new ArrayList<>(totalResults);
40-
// Skips last row (runtime info)
41-
for (int i = 1; i <= totalResults; i++) {
42-
ArrayList<?> row = result.get(i);
43-
Record record = new RecordImpl(header, row.stream().map( obj -> {
44-
if(obj instanceof byte[]) {
45-
return SafeEncoder.encode((byte[])obj);
46-
}
47-
return obj;
48-
}).collect(Collectors.toList()));
49-
results.add(record);
50-
}
51-
}
52-
}
53-
54-
@Override
55-
public List<String> getHeader(){
56-
return header;
57-
}
58-
59-
@Override
60-
public boolean hasNext() {
61-
return position < results.size();
62-
}
63-
64-
@Override
65-
public Record next() {
66-
if (!hasNext())
67-
throw new NoSuchElementException();
68-
return results.get(position++);
69-
}
70-
71-
@Override
72-
public Statistics getStatistics() {
73-
return statistics;
74-
}
75-
76-
@Override
77-
public String toString() {
78-
return this.header + "\n" + this.results + "\n" + this.statistics;
79-
}
12+
public class ResultSetImpl implements ResultSet {
13+
14+
Header header = new HeaderImpl(new ArrayList<>());
15+
Statistics statistics = new StatisticsImpl(new ArrayList<>());
16+
17+
private final List<Record> results = new ArrayList<>();
18+
19+
private int position = 0;
20+
21+
/**
22+
*
23+
* @param rawResponse the raw representation of response is at most 3 lists of objects.
24+
* The last list is the statistics list.
25+
*/
26+
public ResultSetImpl(List<Object> rawResponse){
27+
28+
if(rawResponse.size() != 3){
29+
30+
parseStatistics(rawResponse.get(rawResponse.size()-1));
31+
32+
}
33+
else{
34+
35+
parseHeader((List<List<Object>>)rawResponse.get(0));
36+
parseResult((List<List<Object>>)rawResponse.get(1));
37+
parseStatistics((List<Object>)rawResponse.get(2));
38+
}
39+
}
40+
41+
42+
/**
43+
*
44+
* @param rawResultSet - raw result set representation
45+
*/
46+
private void parseResult(List<List<Object>> rawResultSet) {
47+
if (rawResultSet == null || rawResultSet.isEmpty()) {
48+
return;
49+
} else {
50+
//go over each raw result
51+
for (List<Object> row : rawResultSet) {
52+
53+
List<Object> parsedRow = new ArrayList<>();
54+
//go over each object in the result
55+
for (int i = 0; i < row.size(); i++) {
56+
//get raw representation of the object
57+
List<Object> obj = (List<Object>) row.get(i);
58+
//get object type
59+
Header.ResultSetColumnTypes objType = header.getSchemaTypes().get(i);
60+
//deserialize according to type and
61+
switch (objType) {
62+
case COLUMN_NODE:
63+
parsedRow.add(deserializeNode(obj));
64+
break;
65+
case COLUMN_RELATION:
66+
parsedRow.add(deserializeEdge(obj));
67+
break;
68+
case COLUMN_SCALAR: {
69+
parsedRow.add(deserializeScalar(obj));
70+
71+
}
72+
}
73+
74+
}
75+
//create new record from deserialized objects
76+
Record record = new RecordImpl(header.getSchemaNames(), parsedRow);
77+
results.add(record);
78+
79+
80+
}
81+
82+
}
83+
84+
}
85+
86+
/**
87+
*
88+
* @param rawStatistics raw statistics representation
89+
*/
90+
private void parseStatistics(Object rawStatistics){
91+
statistics = new StatisticsImpl((List<byte[]>)rawStatistics);
92+
}
93+
94+
95+
/**
96+
*
97+
* @param rawHeader raw header representation
98+
*/
99+
private void parseHeader(List<List<Object>> rawHeader){
100+
header = new HeaderImpl(rawHeader);
101+
}
102+
103+
@Override
104+
public Statistics getStatistics() {
105+
return statistics;
106+
}
107+
108+
@Override
109+
public Header getHeader(){
110+
return header;
111+
}
112+
113+
114+
/**
115+
* @param rawNodeData - raw node object in the form of list of object
116+
* rawNodeData.get(0) - id (long)
117+
* rawNodeData.get(1) - a list y which contains the labels of this node. Each entry is a label id from the type of long
118+
* rawNodeData.get(2) - a list which contains the properties of the node.
119+
* @return Node object
120+
*/
121+
private Node deserializeNode(List<Object> rawNodeData) {
122+
Node node = new Node();
123+
deserializeGraphEntityId(node, rawNodeData.get(0));
124+
List<Long> labelsIndices = (List<Long>) rawNodeData.get(1);
125+
for (long labelIndex : labelsIndices) {
126+
String label = RedisGraphAPI.getInstance().getLabel((int) labelIndex);
127+
node.addLabel(label);
128+
}
129+
deserializeGraphEntityProperties(node, (List<List<Object>>) rawNodeData.get(2));
130+
131+
return node;
132+
133+
}
134+
135+
/**
136+
* @param graphEntity graph entity
137+
* @param rawEntityId raw representation of entity id to be set to the graph entity
138+
*/
139+
private void deserializeGraphEntityId(GraphEntity graphEntity, Object rawEntityId) {
140+
int id = (int) (long) rawEntityId;
141+
graphEntity.setId(id);
142+
}
143+
144+
145+
/**
146+
* @param rawEdgeData - a list of objects
147+
* rawEdgeData[0] - edge id
148+
* rawEdgeData[1] - edge relationship type
149+
* rawEdgeData[2] - edge source
150+
* rawEdgeData[3] - edge destination
151+
* rawEdgeData[4] - edge properties
152+
* @return Edge object
153+
*/
154+
private Edge deserializeEdge(List<Object> rawEdgeData) {
155+
Edge edge = new Edge();
156+
deserializeGraphEntityId(edge, rawEdgeData.get(0));
157+
158+
String relationshipType = RedisGraphAPI.getInstance().getRelationshipType((int) (long) rawEdgeData.get(1));
159+
edge.setRelationshipType(relationshipType);
160+
161+
edge.setSource((int) (long) rawEdgeData.get(2));
162+
edge.setDestination((int) (long) rawEdgeData.get(3));
163+
164+
deserializeGraphEntityProperties(edge, (List<List<Object>>) rawEdgeData.get(4));
165+
166+
return edge;
167+
}
168+
169+
/**
170+
* @param entity graph entity for adding the properties to
171+
* @param rawProperties raw representation of a list of graph entity properties. Each entry is a list (rawProperty)
172+
* is a raw representation of property, as follows:
173+
* rawProperty.get(0) - property key
174+
* rawProperty.get(1) - property type
175+
* rawProperty.get(2) - property value
176+
*/
177+
void deserializeGraphEntityProperties(GraphEntity entity, List<List<Object>> rawProperties) {
178+
179+
180+
for (List<Object> rawProperty : rawProperties) {
181+
Property property = new Property();
182+
property.setName(RedisGraphAPI.getInstance().getPropertyName((int) (long) rawProperty.get(0)));
183+
184+
//trimmed for getting to value using deserializeScalar
185+
List<Object> propertyScalar = rawProperty.subList(1, rawProperty.size());
186+
property.setType(getScalarTypeFromObject(propertyScalar.get(0)));
187+
property.setValue(deserializeScalar(propertyScalar));
188+
189+
entity.addProperty(property);
190+
191+
}
192+
193+
}
194+
195+
/**
196+
* @param rawScalarData - a list of object. list[0] is the scalar type, list[1] is the scalar value
197+
* @return value of the specific scalar type
198+
*/
199+
private Object deserializeScalar(List<Object> rawScalarData) {
200+
ResultSetScalarTypes type = getScalarTypeFromObject(rawScalarData.get(0));
201+
Object obj = rawScalarData.get(1);
202+
switch (type) {
203+
case PROPERTY_NULL:
204+
return null;
205+
case PROPERTY_BOOLEAN:
206+
return Boolean.parseBoolean(SafeEncoder.encode((byte[])obj));
207+
case PROPERTY_DOUBLE:
208+
return Double.parseDouble(SafeEncoder.encode((byte[])obj));
209+
case PROPERTY_INTEGER:
210+
return (Integer) ((Long) obj).intValue();
211+
case PROPERTY_STRING:
212+
return SafeEncoder.encode((byte[]) obj);
213+
case PROPERTY_UNKNOWN:
214+
default:
215+
return obj;
216+
}
217+
}
218+
219+
/**
220+
* Auxiliary function to retrieve scalar types
221+
*
222+
* @param rawScalarType
223+
* @return scalar type
224+
*/
225+
private ResultSetScalarTypes getScalarTypeFromObject(Object rawScalarType) {
226+
return ResultSetScalarTypes.values()[(int) (long) rawScalarType];
227+
}
228+
229+
@Override
230+
public boolean hasNext() {
231+
return position < results.size();
232+
}
233+
234+
@Override
235+
public Record next() {
236+
if (!hasNext())
237+
throw new NoSuchElementException();
238+
return results.get(position++);
239+
}
240+
241+
242+
@Override
243+
public int size() {
244+
return results.size();
245+
}
246+
247+
@Override
248+
public boolean equals(Object o) {
249+
if (this == o) return true;
250+
if (!(o instanceof ResultSetImpl)) return false;
251+
ResultSetImpl resultSet = (ResultSetImpl) o;
252+
return Objects.equals(getHeader(), resultSet.getHeader()) &&
253+
Objects.equals(getStatistics(), resultSet.getStatistics()) &&
254+
Objects.equals(results, resultSet.results);
255+
}
256+
257+
@Override
258+
public int hashCode() {
259+
return Objects.hash(getHeader(), getStatistics(), results);
260+
}
261+
262+
@Override
263+
public String toString() {
264+
final StringBuilder sb = new StringBuilder("ResultSetImpl{");
265+
sb.append("header=").append(header);
266+
sb.append(", statistics=").append(statistics);
267+
sb.append(", results=").append(results);
268+
sb.append('}');
269+
return sb.toString();
270+
}
80271
}

0 commit comments

Comments
 (0)