Skip to content

Commit 3a08ebe

Browse files
committed
fix: json serializer now is consistent with edges retrieved in different way
This issue fixes #2371 and #1590
1 parent 7fb650b commit 3a08ebe

File tree

7 files changed

+236
-97
lines changed

7 files changed

+236
-97
lines changed

engine/src/main/java/com/arcadedb/graph/GraphEngine.java

Lines changed: 86 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import com.arcadedb.database.Database;
2222
import com.arcadedb.database.DatabaseInternal;
23+
import com.arcadedb.database.Document;
2324
import com.arcadedb.database.Identifiable;
2425
import com.arcadedb.database.MutableDocument;
2526
import com.arcadedb.database.RID;
@@ -43,9 +44,34 @@
4344
* @author Luca Garulli ([email protected])
4445
*/
4546
public class GraphEngine {
46-
public static final String OUT_EDGES_SUFFIX = "_out_edges";
47-
public static final String IN_EDGES_SUFFIX = "_in_edges";
48-
private final DatabaseInternal database;
47+
public static final String OUT_EDGES_SUFFIX = "_out_edges";
48+
public static final String IN_EDGES_SUFFIX = "_in_edges";
49+
50+
public static final IterableGraph<Vertex> EMPTY_VERTEX_LIST = new IterableGraph<>() {
51+
@Override
52+
public Iterator<Vertex> iterator() {
53+
return Collections.emptyIterator();
54+
}
55+
56+
@Override
57+
public Class<? extends Document> getEntryType() {
58+
return Vertex.class;
59+
}
60+
};
61+
62+
public static final IterableGraph<Edge> EMPTY_EDGE_LIST = new IterableGraph<>() {
63+
@Override
64+
public Iterator<Edge> iterator() {
65+
return Collections.emptyIterator();
66+
}
67+
68+
@Override
69+
public Class<? extends Document> getEntryType() {
70+
return Edge.class;
71+
}
72+
};
73+
74+
private final DatabaseInternal database;
4975

5076
public GraphEngine(final DatabaseInternal database) {
5177
this.database = database;
@@ -86,7 +112,8 @@ public void dropVertexType(final VertexType type) {
86112
}
87113
}
88114

89-
public ImmutableLightEdge newLightEdge(final VertexInternal fromVertex, final String edgeTypeName, final Identifiable toVertex) {
115+
public ImmutableLightEdge newLightEdge(final VertexInternal fromVertex, final String edgeTypeName,
116+
final Identifiable toVertex) {
90117
if (toVertex == null)
91118
throw new IllegalArgumentException("Destination vertex is null");
92119

@@ -257,7 +284,8 @@ public EdgeSegment createOutEdgeChunk(final MutableVertex fromVertex) {
257284
outChunk = (EdgeSegment) database.lookupByRID(outEdgesHeadChunk, true);
258285
} catch (final RecordNotFoundException e) {
259286
LogManager.instance()
260-
.log(this, Level.SEVERE, "Record %s (outEdgesHeadChunk) not found on vertex %s. Creating a new one", outEdgesHeadChunk,
287+
.log(this, Level.SEVERE, "Record %s (outEdgesHeadChunk) not found on vertex %s. Creating a new one",
288+
outEdgesHeadChunk,
261289
fromVertex.getIdentity());
262290
outEdgesHeadChunk = null;
263291
}
@@ -473,20 +501,42 @@ public IterableGraph<Edge> getEdges(final VertexInternal vertex, final Vertex.DI
473501

474502
case OUT:
475503
final EdgeLinkedList outEdges = getEdgeHeadChunk(vertex, Vertex.DIRECTION.OUT);
476-
if (outEdges != null)
477-
return () -> outEdges.edgeIterator(edgeTypes);
504+
if (outEdges != null) {
505+
return new IterableGraph<>() {
506+
@Override
507+
public Iterator<Edge> iterator() {
508+
return outEdges.edgeIterator(edgeTypes);
509+
}
510+
511+
@Override
512+
public Class<? extends Document> getEntryType() {
513+
return Edge.class;
514+
}
515+
};
516+
}
478517
break;
479518

480519
case IN:
481520
final EdgeLinkedList inEdges = getEdgeHeadChunk(vertex, Vertex.DIRECTION.IN);
482521
if (inEdges != null)
483-
return () -> inEdges.edgeIterator(edgeTypes);
522+
return new IterableGraph<>() {
523+
@Override
524+
public Iterator<Edge> iterator() {
525+
return inEdges.edgeIterator(edgeTypes);
526+
}
527+
528+
@Override
529+
public Class<? extends Document> getEntryType() {
530+
return Edge.class;
531+
}
532+
};
484533
break;
485534

486535
default:
487536
throw new IllegalArgumentException("Invalid direction " + direction);
488537
}
489-
return IterableGraph.emptyList();
538+
539+
return EMPTY_EDGE_LIST;
490540
}
491541

492542
/**
@@ -516,7 +566,8 @@ public IterableGraph<Vertex> getVertices(final VertexInternal vertex) {
516566
*
517567
* @return An iterator of PVertex instances
518568
*/
519-
public IterableGraph<Vertex> getVertices(final VertexInternal vertex, final Vertex.DIRECTION direction, final String... edgeTypes) {
569+
public IterableGraph<Vertex> getVertices(final VertexInternal vertex, final Vertex.DIRECTION direction,
570+
final String... edgeTypes) {
520571
if (direction == null)
521572
throw new IllegalArgumentException("Direction is null");
522573

@@ -536,20 +587,41 @@ public IterableGraph<Vertex> getVertices(final VertexInternal vertex, final Vert
536587

537588
case OUT:
538589
final EdgeLinkedList outEdges = getEdgeHeadChunk(vertex, Vertex.DIRECTION.OUT);
539-
if (outEdges != null)
540-
return () -> outEdges.vertexIterator(edgeTypes);
590+
if (outEdges != null) {
591+
return new IterableGraph<>() {
592+
@Override
593+
public Iterator<Vertex> iterator() {
594+
return outEdges.vertexIterator(edgeTypes);
595+
}
596+
597+
@Override
598+
public Class<? extends Document> getEntryType() {
599+
return Vertex.class;
600+
}
601+
};
602+
}
541603
break;
542604

543605
case IN:
544606
final EdgeLinkedList inEdges = getEdgeHeadChunk(vertex, Vertex.DIRECTION.IN);
545607
if (inEdges != null)
546-
return () -> inEdges.vertexIterator(edgeTypes);
608+
return new IterableGraph<>() {
609+
@Override
610+
public Iterator<Vertex> iterator() {
611+
return inEdges.vertexIterator(edgeTypes);
612+
}
613+
614+
@Override
615+
public Class<? extends Document> getEntryType() {
616+
return Vertex.class;
617+
}
618+
};
547619
break;
548620

549621
default:
550622
throw new IllegalArgumentException("Invalid direction " + direction);
551623
}
552-
return IterableGraph.emptyList();
624+
return EMPTY_VERTEX_LIST;
553625
}
554626

555627
public boolean isVertexConnectedTo(final VertexInternal vertex, final Identifiable toVertex) {

engine/src/main/java/com/arcadedb/graph/IterableGraph.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919
package com.arcadedb.graph;
2020

21+
import com.arcadedb.database.Document;
2122
import com.arcadedb.utility.MultiIterator;
2223

2324
import java.util.*;
@@ -28,9 +29,7 @@
2829
* @author Luca Garulli ([email protected])
2930
*/
3031
public interface IterableGraph<T> extends Iterable<T> {
31-
static <T> IterableGraph<T> emptyList() {
32-
return () -> Collections.emptyIterator();
33-
}
32+
Class<? extends Document> getEntryType();
3433

3534
default T getFirstOrNull() {
3635
if (this instanceof List<?> list)

engine/src/main/java/com/arcadedb/query/sql/method/collection/SQLMethodSize.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,18 @@ public Object execute(final Object value, final Identifiable currentRecord, fina
4343

4444
final int size;
4545
if (value != null) {
46-
if (value instanceof Result result)
47-
size = result.getRecord().isPresent() ? result.getRecord().get().size() : -1;
48-
else if (value instanceof Identifiable rid) {
46+
switch (value) {
47+
case Result result -> size = result.getRecord().isPresent() ? result.getRecord().get().size() : -1;
48+
case Identifiable rid -> {
4949
final Record record = rid.getRecord(true);
5050
if (record != null)
5151
size = record.size();
5252
else
5353
size = 0;
54-
} else if (value instanceof String)
55-
size = value.toString().length();
56-
else
57-
size = MultiValue.getSize(value);
54+
}
55+
case String s -> size = s.length();
56+
default -> size = MultiValue.getSize(value);
57+
}
5858

5959
} else {
6060
size = 0;

engine/src/main/java/com/arcadedb/serializer/JsonSerializer.java

Lines changed: 54 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.arcadedb.database.DetachedDocument;
2323
import com.arcadedb.database.Document;
2424
import com.arcadedb.graph.Edge;
25+
import com.arcadedb.graph.IterableGraph;
2526
import com.arcadedb.graph.Vertex;
2627
import com.arcadedb.query.sql.executor.Result;
2728
import com.arcadedb.query.sql.executor.ResultSet;
@@ -55,8 +56,7 @@ public static JsonSerializer createJsonSerializer() {
5556

5657
public JSONObject serializeDocument(final Document document) {
5758
final Database database = document.getDatabase();
58-
final JSONObject object = new JSONObject()
59-
.setDateFormat(database.getSchema().getDateTimeFormat())
59+
final JSONObject object = new JSONObject().setDateFormat(database.getSchema().getDateTimeFormat())
6060
.setDateTimeFormat(database.getSchema().getDateTimeFormat());
6161

6262
if (document.getIdentity() != null)
@@ -71,7 +71,7 @@ public JSONObject serializeDocument(final Document document) {
7171
switch (value) {
7272
case null -> value = JSONObject.NULL;
7373
case Document document1 -> value = serializeDocument(document1);
74-
case Collection<?> collection -> serializeCollection(database, collection);
74+
case Collection<?> collection -> serializeCollection(database, collection, null);
7575
case Map map -> value = serializeMap(database, (Map<Object, Object>) map);
7676
default -> {
7777
}
@@ -88,8 +88,7 @@ public JSONObject serializeDocument(final Document document) {
8888
}
8989

9090
public JSONObject serializeResult(final Database database, final Result result) {
91-
final JSONObject object = new JSONObject()
92-
.setDateFormat(database.getSchema().getDateFormat())
91+
final JSONObject object = new JSONObject().setDateFormat(database.getSchema().getDateFormat())
9392
.setDateTimeFormat(database.getSchema().getDateTimeFormat());
9493

9594
DocumentType type = null;
@@ -118,61 +117,47 @@ else if (value != null)
118117
propertyType = null;
119118

120119
if (propertyType != null) {
121-
if (propertyTypes.length() > 0)
120+
if (!propertyTypes.isEmpty())
122121
propertyTypes.append(",");
123122
propertyTypes.append(propertyName).append(":").append(propertyType.getId());
124123
}
125124

126-
if (value == null)
127-
value = JSONObject.NULL;
128-
else if (value instanceof Document document)
129-
value = serializeDocument(document);
130-
else if (value instanceof Result res)
131-
value = serializeResult(database, res);
132-
else if (value instanceof Collection<?> coll)
133-
value = serializeCollection(database, coll);
134-
else if (value instanceof Map)
135-
value = serializeMap(database, (Map<Object, Object>) value);
136-
else if (value.getClass().isArray())
137-
value = serializeCollection(database, List.of((Object[]) value));
138-
139-
value = convertNonNumbers(value);
125+
value = serializeObject(database, value);
140126

141127
object.put(propertyName, value);
142128
}
143129

144130
return object;
145131
}
146132

147-
private Object serializeCollection(final Database database, final Collection<?> value) {
133+
private Object serializeCollection(final Database database, final Collection<?> value, Class<? extends Document> entryType) {
148134
Object result = value;
149-
if (!value.isEmpty()) {
150-
if (useCollectionSizeForEdges && value.iterator().next() instanceof Edge)
151-
result = value.size();
152-
else if (useCollectionSize) {
135+
if (useCollectionSize) {
136+
result = value.size();
137+
} else {
138+
if (useCollectionSizeForEdges && //
139+
((entryType != null && entryType.isAssignableFrom(Edge.class)) || //
140+
value.iterator().next() instanceof Edge))
153141
result = value.size();
154-
} else {
142+
else {
155143
final JSONArray list = new JSONArray();
156-
for (Object o : value) {
157-
if (o instanceof Document document)
158-
o = serializeDocument(document);
159-
else if (o instanceof Result result1)
160-
o = serializeResult(database, result1);
161-
else if (o instanceof ResultSet set)
162-
o = serializeResultSet(database, set);
163-
else if (o instanceof Collection<?> collection)
164-
o = serializeCollection(database, collection);
165-
else if (o instanceof Map)
166-
o = serializeMap(database, (Map<Object, Object>) o);
167-
168-
list.put(o);
169-
}
144+
for (Object o : value)
145+
list.put(serializeObject(database, o));
146+
170147
result = list;
171148
}
172149
}
173150
return result;
174151
}
175152

153+
private Object serializeIterator(final Database database, final Iterator<?> value, final Class<? extends Document> entryType) {
154+
final List<Object> list = new ArrayList<>();
155+
while (value.hasNext())
156+
list.add(value.next());
157+
158+
return serializeCollection(database, list, entryType);
159+
}
160+
176161
private Object serializeResultSet(final Database database, final ResultSet resultSet) {
177162
final JSONArray array = new JSONArray();
178163
while (resultSet.hasNext()) {
@@ -187,21 +172,10 @@ private Object serializeMap(final Database database, final Map<Object, Object> v
187172
if (useCollectionSize) {
188173
result = value.size();
189174
} else {
190-
final JSONObject map = new JSONObject()
191-
.setDateFormat(database.getSchema().getDateFormat())
175+
final JSONObject map = new JSONObject().setDateFormat(database.getSchema().getDateFormat())
192176
.setDateTimeFormat(database.getSchema().getDateTimeFormat());
193177
for (final Map.Entry<Object, Object> entry : value.entrySet()) {
194-
Object o = entry.getValue();
195-
if (o instanceof Document document)
196-
o = serializeDocument(document);
197-
else if (o instanceof ResultSet set)
198-
o = serializeResultSet(database, set);
199-
else if (o instanceof Result result1)
200-
o = serializeResult(database, result1);
201-
else if (o instanceof Collection<?> collection)
202-
o = serializeCollection(database, collection);
203-
else if (o instanceof Map)
204-
o = serializeMap(database, (Map<Object, Object>) o);
178+
final Object o = serializeObject(database, entry.getValue());
205179
map.put(entry.getKey().toString(), o);
206180
}
207181
result = map;
@@ -299,4 +273,31 @@ else if (value.equals(Double.NEGATIVE_INFINITY) || value.equals(Float.NEGATIVE_I
299273
value = "NegInfinity";
300274
return value;
301275
}
276+
277+
private Object serializeObject(final Database database, Object value) {
278+
if (value == null)
279+
value = JSONObject.NULL;
280+
else if (value instanceof Document document)
281+
value = serializeDocument(document);
282+
else if (value instanceof Result res)
283+
value = serializeResult(database, res);
284+
else if (value instanceof ResultSet res)
285+
value = serializeResultSet(database, res);
286+
else if (value instanceof Collection<?> coll)
287+
value = serializeCollection(database, coll, null);
288+
else if (value instanceof IterableGraph<?> iter)
289+
value = serializeIterator(database, iter.iterator(), iter.getEntryType());
290+
else if (value instanceof Iterable<?> iter)
291+
value = serializeIterator(database, iter.iterator(), null);
292+
else if (value instanceof Iterator<?> iter)
293+
value = serializeIterator(database, iter, null);
294+
else if (value instanceof Map)
295+
value = serializeMap(database, (Map<Object, Object>) value);
296+
else if (value.getClass().isArray())
297+
value = serializeCollection(database, List.of((Object[]) value), null);
298+
299+
value = convertNonNumbers(value);
300+
301+
return value;
302+
}
302303
}

0 commit comments

Comments
 (0)