Skip to content

Commit b91c314

Browse files
authored
Merge pull request #362 from CorvusYe/master
feat: automatic conversion from Node/Relationship to NgVertex/NgEdge.
2 parents 0e5b3f2 + 239f77a commit b91c314

File tree

10 files changed

+245
-28
lines changed

10 files changed

+245
-28
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package ye.weicheng.ngbatis.demo.pojo;
2+
3+
// Copyright (c) 2025 All project authors. All rights reserved.
4+
//
5+
// This source code is licensed under Apache 2.0 License.
6+
7+
import java.util.List;
8+
import org.nebula.contrib.ngbatis.models.data.NgEdge;
9+
import org.nebula.contrib.ngbatis.models.data.NgVertex;
10+
11+
/**
12+
* @author yeweicheng
13+
* @since 2025-07-01 13:00
14+
* <br>Now is history!
15+
*/
16+
public class TripletStep<T> {
17+
18+
private NgVertex<T> src;
19+
private NgVertex<T> dst;
20+
private List<NgEdge<T>> edges;
21+
22+
23+
public NgVertex<T> getSrc() {
24+
return src;
25+
}
26+
27+
public void setSrc(NgVertex<T> src) {
28+
this.src = src;
29+
}
30+
31+
public NgVertex<T> getDst() {
32+
return dst;
33+
}
34+
35+
public void setDst(NgVertex<T> dst) {
36+
this.dst = dst;
37+
}
38+
39+
public List<NgEdge<T>> getEdges() {
40+
return edges;
41+
}
42+
43+
public void setEdges(List<NgEdge<T>> edges) {
44+
this.edges = edges;
45+
}
46+
47+
}

ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/TestRepository.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.springframework.data.repository.query.Param;
1919
import ye.weicheng.ngbatis.demo.pojo.Person;
2020
import ye.weicheng.ngbatis.demo.pojo.PersonLikePerson;
21+
import ye.weicheng.ngbatis.demo.pojo.TripletStep;
2122

2223
/**
2324
* 数据访问层 样例。
@@ -91,6 +92,8 @@ public interface TestRepository extends NebulaDaoBasic<Person, String> {
9192

9293
String testValueFmtWhenNull(@Param("value") String nullValue);
9394

95+
List<TripletStep> selectTripletStep();
96+
9497

9598
class DynamicNode {
9699
@Id

ngbatis-demo/src/main/resources/mapper/TestRepository.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,12 @@
179179
<select id="testValueFmtWhenNull">
180180
RETURN ${ ng.valueFmt(value) ! "null" }
181181
</select>
182+
183+
<select id="selectTripletStep" resultType="ye.weicheng.ngbatis.demo.pojo.TripletStep">
184+
MATCH (n)-[r*..2]->(n2)
185+
RETURN n as `src`, r as `edges`, n2 as `dst`
186+
LIMIT 10
187+
</select>
182188

183189
</mapper>
184190

ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NgbatisDemoApplicationTests.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.springframework.boot.test.context.SpringBootTest;
2424
import ye.weicheng.ngbatis.demo.pojo.Person;
2525
import ye.weicheng.ngbatis.demo.pojo.PersonLikePerson;
26+
import ye.weicheng.ngbatis.demo.pojo.TripletStep;
2627
import ye.weicheng.ngbatis.demo.repository.TestRepository;
2728
import ye.weicheng.ngbatis.demo.repository.TestRepository.DynamicNode;
2829

@@ -285,4 +286,9 @@ public void testResultContainingSet() {
285286
System.out.println(JSON.toJSONString(rs));
286287
}
287288

289+
@Test
290+
public void selectTripletStep() {
291+
List<TripletStep> tripletSteps = repository.selectTripletStep();
292+
System.out.println(JSON.toJSONString(tripletSteps));
293+
}
288294
}

src/main/java/org/nebula/contrib/ngbatis/handler/AbstractResultHandler.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
*/
3838
public abstract class AbstractResultHandler<T, Z> implements ResultHandler<T, Z> {
3939

40-
private Logger log = LoggerFactory.getLogger(AbstractResultHandler.class);
40+
private Logger log = LoggerFactory.getLogger(getClass());
4141

4242
/**
4343
* 不同数据类型的结果处理类创建时,需要将自身所处理的类型注册到全局变量中。
@@ -134,10 +134,10 @@ protected T newInstance(Class<T> returnType, Class resultType) {
134134
* @return 返回接口类型默认使用的实现
135135
*/
136136
protected T defaultInstance(Class<?> returnType) {
137-
Object o = returnType == List.class ? new ArrayList<>()
138-
: returnType == Set.class ? new HashSet<>()
139-
: returnType == Queue.class ? new ConcurrentLinkedQueue<>()
140-
: returnType == Map.class ? new LinkedHashMap<>()
137+
Object o = List.class.isAssignableFrom(returnType) ? new ArrayList<>()
138+
: Set.class.isAssignableFrom(returnType) ? new HashSet<>()
139+
: Queue.class.isAssignableFrom(returnType) ? new ConcurrentLinkedQueue<>()
140+
: Map.class.isAssignableFrom(returnType) ? new LinkedHashMap<>()
141141
: null;
142142
return (T) o;
143143
}

src/main/java/org/nebula/contrib/ngbatis/handler/CollectionObjectResultHandler.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,17 @@
44
//
55
// This source code is licensed under Apache 2.0 License.
66

7+
import com.vesoft.nebula.client.graph.data.Node;
8+
import com.vesoft.nebula.client.graph.data.Relationship;
79
import com.vesoft.nebula.client.graph.data.ResultSet;
10+
import java.io.UnsupportedEncodingException;
11+
import java.util.Arrays;
812
import java.util.Collection;
13+
import java.util.HashMap;
914
import java.util.List;
15+
import java.util.Map;
16+
import org.nebula.contrib.ngbatis.models.data.NgEdge;
17+
import org.nebula.contrib.ngbatis.models.data.NgVertex;
1018
import org.springframework.beans.factory.annotation.Autowired;
1119
import org.springframework.stereotype.Component;
1220

@@ -37,4 +45,37 @@ public Collection handle(Collection newResult, ResultSet result, Class resultTyp
3745
return newResult;
3846
}
3947

40-
}
48+
49+
List<Class<?>> collectionInnerType = Arrays.asList(NgEdge.class, NgVertex.class);
50+
51+
boolean isCollectionInnerType(Class<?> resultType) {
52+
for (Class<?> innerType : collectionInnerType) {
53+
boolean assignableFrom = innerType.isAssignableFrom(resultType);
54+
if (assignableFrom) return true;
55+
}
56+
return false;
57+
}
58+
59+
public Collection<Object> handle(Collection<Object> nestedCollection, Class<?> resultType) {
60+
if (isCollectionInnerType(resultType)) {
61+
try {
62+
Collection<Object> nestedCollect = defaultInstance(nestedCollection.getClass());
63+
for (Object o : nestedCollection) {
64+
if (NgEdge.class.isAssignableFrom(resultType) && o instanceof Relationship) {
65+
o = objectResultHandler.toEdge((Relationship) o);
66+
}
67+
if (NgVertex.class.isAssignableFrom(resultType) && o instanceof Node) {
68+
o = objectResultHandler.toVertex((Node) o);
69+
}
70+
nestedCollect.add(o);
71+
}
72+
return nestedCollect;
73+
} catch (UnsupportedEncodingException e) {
74+
// 在前置判断中,已经规避了异常发生的可能性
75+
throw new RuntimeException(e);
76+
}
77+
}
78+
return nestedCollection;
79+
}
80+
81+
}

src/main/java/org/nebula/contrib/ngbatis/handler/NgEdgeResultHandler.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,20 +40,25 @@ public NgEdge<?> handle(NgEdge<?> newResult, Record row) {
4040
public NgEdge<?> handle(NgEdge<?> newResult, ValueWrapper relationshipValueWrapper) {
4141
try {
4242
Relationship relationship = relationshipValueWrapper.asRelationship();
43-
44-
newResult.setEdgeName(relationship.edgeName());
45-
46-
long ranking = relationship.ranking();
47-
newResult.setRank(ranking);
48-
49-
newResult.setSrcID(getValue(relationship.srcId()));
50-
newResult.setDstID(getValue(relationship.dstId()));
51-
52-
newResult.setProperties(edgePropsToMap(relationship));
53-
return newResult;
43+
return handle(newResult, relationship);
5444
} catch (UnsupportedEncodingException e) {
5545
throw new ResultHandleException(
5646
String.format("%s : %s", e.getClass().toString(), e.getMessage()));
5747
}
5848
}
49+
50+
public NgEdge<?> handle(NgEdge<?> newResult, Relationship relationship)
51+
throws UnsupportedEncodingException {
52+
newResult.setEdgeName(relationship.edgeName());
53+
54+
long ranking = relationship.ranking();
55+
newResult.setRank(ranking);
56+
57+
newResult.setSrcID(getValue(relationship.srcId()));
58+
newResult.setDstID(getValue(relationship.dstId()));
59+
60+
newResult.setProperties(edgePropsToMap(relationship));
61+
return newResult;
62+
}
63+
5964
}

src/main/java/org/nebula/contrib/ngbatis/handler/ObjectResultHandler.java

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//
55
// This source code is licensed under Apache 2.0 License.
66

7+
import static org.nebula.contrib.ngbatis.utils.ReflectUtil.getCollectionE;
78
import static org.nebula.contrib.ngbatis.utils.ReflectUtil.isCurrentTypeOrParentType;
89
import static org.nebula.contrib.ngbatis.utils.ResultSetUtil.nodeToResultType;
910
import static org.nebula.contrib.ngbatis.utils.ResultSetUtil.relationshipToResultType;
@@ -12,8 +13,11 @@
1213
import com.vesoft.nebula.client.graph.data.Relationship;
1314
import com.vesoft.nebula.client.graph.data.ResultSet;
1415
import com.vesoft.nebula.client.graph.data.ValueWrapper;
16+
import java.io.UnsupportedEncodingException;
1517
import java.lang.reflect.Field;
18+
import java.util.ArrayList;
1619
import java.util.Arrays;
20+
import java.util.Collection;
1721
import java.util.HashMap;
1822
import java.util.HashSet;
1923
import java.util.List;
@@ -22,8 +26,12 @@
2226
import java.util.stream.Collectors;
2327
import org.nebula.contrib.ngbatis.config.NgbatisConfig;
2428
import org.nebula.contrib.ngbatis.models.MapperContext;
29+
import org.nebula.contrib.ngbatis.models.data.NgEdge;
30+
import org.nebula.contrib.ngbatis.models.data.NgVertex;
2531
import org.nebula.contrib.ngbatis.utils.ReflectUtil;
2632
import org.nebula.contrib.ngbatis.utils.ResultSetUtil;
33+
import org.springframework.beans.factory.annotation.Autowired;
34+
import org.springframework.context.annotation.Lazy;
2735
import org.springframework.stereotype.Component;
2836

2937
/**
@@ -42,6 +50,10 @@ public class ObjectResultHandler extends AbstractResultHandler<Object, Object> {
4250
private final Map<Class<?>, Set<?>> classColumnNamesMap = new HashMap<>();
4351
private final Map<Class<?>, Set<?>> classAllColumnNamesMap = new HashMap<>();
4452

53+
@Autowired private NgEdgeResultHandler edgeResultHandler;
54+
@Autowired private NgVertexResultHandler vertexResultHandler;
55+
@Lazy @Autowired private CollectionObjectResultHandler collectionObjectResultHandler;
56+
4557
@Override
4658
public Object handle(Object newResult, ResultSet result, Class resultType)
4759
throws NoSuchFieldException, IllegalAccessException {
@@ -110,6 +122,11 @@ private Object fillResult(Object v, Object newResult, List<String> columnNames,
110122
Object prop = props.get(k);
111123
ReflectUtil.setValue(newResult, k, prop);
112124
}
125+
} else if (v instanceof Collection) {
126+
Class<?> genericType = getCollectionE(newResult, columnName);
127+
Collection<?> innerCollectionResult =
128+
collectionObjectResultHandler.handle((Collection) v, genericType);
129+
ReflectUtil.setValue(newResult, columnName, innerCollectionResult);
113130
} else {
114131
ReflectUtil.setValue(newResult, columnName, v);
115132
}
@@ -168,20 +185,64 @@ private Object fillResultByNode(
168185
if (columnNames.size() == 1) {
169186
newResult = nodeToResultType(node, resultType);
170187
} else {
171-
nodeToResultType(newResult, columnName, node);
188+
nodeToNgResultType(node, newResult, columnName);
172189
}
173190
return newResult;
174191
}
175192

193+
private void nodeToNgResultType(Node node, Object newResult, String columnName) {
194+
Class<?> fieldType = ReflectUtil.fieldType(newResult, columnName);
195+
if (fieldType == NgVertex.class) {
196+
try {
197+
NgVertex<?> ngVertex = toVertex(node);
198+
ReflectUtil.setValue(newResult, columnName, ngVertex);
199+
} catch (Exception e) {
200+
// 在前置判断中,已经规避了异常发生的可能性
201+
throw new RuntimeException(e);
202+
}
203+
} else {
204+
nodeToResultType(newResult, columnName, node);
205+
}
206+
}
207+
176208
private Object fillResultByRelationship(
177209
Relationship relationship, Object newResult,
178210
List<String> columnNames, Class resultType, String columnName) {
179211

180212
if (columnNames.size() == 1) {
181213
newResult = relationshipToResultType(relationship, resultType);
182214
} else {
183-
relationshipToResultType(newResult, columnName, relationship);
215+
relationshipToNgResultType(relationship, newResult, columnName);
184216
}
185217
return newResult;
186218
}
219+
220+
private void relationshipToNgResultType(
221+
Relationship relationship, Object newResult, String columnName) {
222+
223+
Class<?> fieldType = ReflectUtil.fieldType(newResult, columnName);
224+
if (fieldType == NgEdge.class) {
225+
try {
226+
NgEdge<?> ngEdge = toEdge(relationship);
227+
ReflectUtil.setValue(newResult, columnName, ngEdge);
228+
} catch (Exception e) {
229+
// 在前置判断中,已经规避了异常发生的可能性
230+
throw new RuntimeException(e);
231+
}
232+
} else {
233+
relationshipToResultType(newResult, columnName, relationship);
234+
}
235+
}
236+
237+
public NgVertex<?> toVertex(Node node) {
238+
NgVertex<?> ngVertex = new NgVertex<>();
239+
vertexResultHandler.handle(ngVertex, node);
240+
return ngVertex;
241+
}
242+
243+
public NgEdge<?> toEdge(Relationship relationship) throws UnsupportedEncodingException {
244+
NgEdge<?> ngEdge = new NgEdge<>();
245+
edgeResultHandler.handle(ngEdge, relationship);
246+
return ngEdge;
247+
}
187248
}

src/main/java/org/nebula/contrib/ngbatis/session/IntervalCheckSessionDispatcher.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,12 +277,13 @@ public ResultSet executeWithParameter(
277277
gql = qlAndSpace[1];
278278
String autoSwitch = qlAndSpace[0] == null ? "" : qlAndSpace[0];
279279
session = localSession.getSession();
280+
String oldSessionSpace = localSession.getCurrentSpace();
280281
result = session.executeWithParameter(gql, params);
281282

282283
localSession.setCurrentSpace(getSpace(result));
283284
handleSession(localSession, result);
284285
if (log.isDebugEnabled()) {
285-
extraReturn.put("localSessionSpace", space);
286+
extraReturn.put("localSessionSpace", oldSessionSpace);
286287
String currentSpace = localSession.getCurrentSpace();
287288
if (nullSafeEquals(currentSpace, autoSwitch)) {
288289
extraReturn.put("autoSwitch", autoSwitch);

0 commit comments

Comments
 (0)