Skip to content

Commit ed035f6

Browse files
authored
Merge pull request #348 from CorvusYe/master
feat: Supporting geometry types.
2 parents 0f7809e + 7025041 commit ed035f6

File tree

8 files changed

+262
-3
lines changed

8 files changed

+262
-3
lines changed

CHANGELOG-CN.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@ This source code is licensed under Apache 2.0 License.
2222
2323
## 新特性
2424
25+
- 支持Geo类型
26+
27+
字段类型 | 属性类型
28+
---|---
29+
geo(point) | org.springframework.data.geo.Box
30+
geo(linestring) | org.springframework.data.geo.Point
31+
geo(polygon) | org.springframework.data.geo.Polygon
32+
geo | Object
33+
2534
- 支持节点的属性对象字段可以与实体对象直接映射
2635
2736
```java

CHANGELOG.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ This source code is licensed under Apache 2.0 License.
1818
- [ ] show metas
1919
- [ ] create | alter tag & edge type
2020
- [ ] index
21-
- [ ] ResultSetUtil more column types support
22-
- [ ] Geography
21+
- [x] ResultSetUtil more column types support
22+
- [x] Geography
2323
- [x] Duration
2424

2525
## Dependencies upgrade
@@ -43,6 +43,15 @@ This source code is licensed under Apache 2.0 License.
4343
4444
## Feature
4545
46+
- Supporting geometry types.
47+
48+
db type | java type
49+
---|---
50+
geo(point) | org.springframework.data.geo.Box
51+
geo(linestring) | org.springframework.data.geo.Point
52+
geo(polygon) | org.springframework.data.geo.Polygon
53+
geo | Object
54+
4655
- Supporting props can be directly mapped to entity objects.
4756
4857
```java
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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 javax.persistence.Id;
8+
import javax.persistence.Table;
9+
import org.nebula.contrib.ngbatis.annotations.Space;
10+
import org.springframework.data.geo.Box;
11+
import org.springframework.data.geo.Point;
12+
import org.springframework.data.geo.Polygon;
13+
14+
/**
15+
* @author yeweicheng
16+
* @since 2025-05-17 11:31
17+
* <br>Now is history!
18+
*/
19+
@Table(name = "test_geo")
20+
@Space(name = "test")
21+
public class TestGeo {
22+
23+
@Id
24+
private String id;
25+
26+
private Point geoPoint;
27+
28+
private Box geoLine;
29+
30+
private Polygon geoPolygon;
31+
32+
private Object geo;
33+
34+
public String getId() {
35+
return id;
36+
}
37+
38+
public void setId(String id) {
39+
this.id = id;
40+
}
41+
42+
public Point getGeoPoint() {
43+
return geoPoint;
44+
}
45+
46+
public void setGeoPoint(Point geoPoint) {
47+
this.geoPoint = geoPoint;
48+
}
49+
50+
public Box getGeoLine() {
51+
return geoLine;
52+
}
53+
54+
public void setGeoLine(Box geoLine) {
55+
this.geoLine = geoLine;
56+
}
57+
58+
public Polygon getGeoPolygon() {
59+
return geoPolygon;
60+
}
61+
62+
public void setGeoPolygon(Polygon geoPolygon) {
63+
this.geoPolygon = geoPolygon;
64+
}
65+
66+
public Object getGeo() {
67+
return geo;
68+
}
69+
70+
public void setGeo(Object geo) {
71+
this.geo = geo;
72+
}
73+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package ye.weicheng.ngbatis.demo.repository;
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 org.nebula.contrib.ngbatis.proxy.NebulaDaoBasic;
8+
import ye.weicheng.ngbatis.demo.pojo.TestGeo;
9+
10+
/**
11+
* @author yeweicheng
12+
* @since 2025-05-17 11:41
13+
* <br>Now is history!
14+
*/
15+
public interface TestGeoDao extends NebulaDaoBasic<TestGeo, String> {
16+
17+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<!--
2+
Copyright (c) 2025 All project authors. All rights reserved.
3+
4+
This source code is licensed under Apache 2.0 License.
5+
-->
6+
<mapper namespace="ye.weicheng.ngbatis.demo.repository.TestGeoDao">
7+
8+
</mapper>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package ye.weicheng.ngbatis.demo.repository;
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 com.alibaba.fastjson.JSON;
8+
import java.util.Date;
9+
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
10+
import org.junit.jupiter.api.Order;
11+
import org.junit.jupiter.api.Test;
12+
import org.junit.jupiter.api.TestMethodOrder;
13+
import org.springframework.beans.factory.annotation.Autowired;
14+
import org.springframework.boot.test.context.SpringBootTest;
15+
import org.springframework.data.geo.Point;
16+
import ye.weicheng.ngbatis.demo.pojo.TestGeo;
17+
18+
/**
19+
* @author yeweicheng
20+
* @since 2025-05-17 11:42
21+
* <br>Now is history!
22+
*/
23+
@SpringBootTest
24+
@TestMethodOrder(OrderAnnotation.class)
25+
public class TestGeoDaoTest {
26+
27+
static final int sec = new Date().getSeconds();
28+
29+
static final String caseId = "test-geo";
30+
31+
@Autowired private TestGeoDao dao;
32+
33+
@Test
34+
@Order(1)
35+
public void testInsert() {
36+
TestGeo geo = new TestGeo();
37+
geo.setId(caseId);
38+
geo.setGeoPoint(new Point(sec, sec + 0.1));
39+
geo.setGeoLine(new org.springframework.data.geo.Box(
40+
new Point(sec, sec + 0.1),
41+
new Point(sec + 0.1, sec)
42+
));
43+
geo.setGeoPolygon(new org.springframework.data.geo.Polygon(
44+
new Point(sec, sec + 0.1),
45+
new Point(sec + 0.1, sec),
46+
new Point(sec, sec)
47+
));
48+
dao.insert(geo);
49+
}
50+
51+
@Test
52+
@Order(2)
53+
public void testSelectById() {
54+
TestGeo testGeo = dao.selectById(caseId);
55+
System.out.println(JSON.toJSONString(testGeo));
56+
}
57+
}

src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/ValueFmtFn.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
import java.time.Duration;
1111
import java.util.Date;
1212
import org.apache.commons.text.StringEscapeUtils;
13+
import org.springframework.data.geo.Box;
14+
import org.springframework.data.geo.Point;
15+
import org.springframework.data.geo.Polygon;
1316

1417
/**
1518
* 对传递给数据库的值进行不同类型的格式化
@@ -81,6 +84,47 @@ public Object call(Object value, Boolean ifStringLike, Boolean escape) {
8184
: fn;
8285
return String.format("%s('%s')", fn, sdf.format(value));
8386
}
87+
88+
// ST_Point(longitude, latitude)
89+
if (value instanceof Point) {
90+
Point point = (Point) value;
91+
return String.format(
92+
"ST_Point(%s, %s)",
93+
point.getX(),
94+
point.getY()
95+
);
96+
}
97+
98+
// ST_GeogFromText("LINESTRING(3 8, 4.7 73.23)")
99+
if (value instanceof Box) {
100+
Box box = (Box) value;
101+
Point first = box.getFirst();
102+
Point second = box.getSecond();
103+
return String.format(
104+
"ST_GeogFromText(\"LINESTRING(%s %s, %s %s)\")",
105+
first.getX(),
106+
first.getY(),
107+
second.getX(),
108+
second.getY()
109+
);
110+
}
111+
112+
if (value instanceof Polygon) {
113+
Polygon polygon = (Polygon) value;
114+
StringBuilder sb = new StringBuilder("ST_GeogFromText(\"POLYGON((");
115+
for (Point point : polygon.getPoints()) {
116+
sb.append(String.format("%s %s,", point.getX(), point.getY()));
117+
}
118+
119+
// 追加起始点,形成闭环
120+
Point point = polygon.getPoints().get(0);
121+
sb.append(String.format("%s %s,", point.getX(), point.getY()));
122+
123+
sb.deleteCharAt(sb.length() - 1);
124+
sb.append("))\")");
125+
return sb.toString();
126+
}
127+
84128
return value;
85129
}
86130
}

src/main/java/org/nebula/contrib/ngbatis/utils/ResultSetUtil.java

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,13 @@
1313
import com.vesoft.nebula.DateTime;
1414
import com.vesoft.nebula.ErrorCode;
1515
import com.vesoft.nebula.Time;
16+
import com.vesoft.nebula.client.graph.data.CoordinateWrapper;
1617
import com.vesoft.nebula.client.graph.data.DateTimeWrapper;
1718
import com.vesoft.nebula.client.graph.data.DateWrapper;
1819
import com.vesoft.nebula.client.graph.data.DurationWrapper;
20+
import com.vesoft.nebula.client.graph.data.GeographyWrapper;
1921
import com.vesoft.nebula.client.graph.data.Node;
22+
import com.vesoft.nebula.client.graph.data.PointWrapper;
2023
import com.vesoft.nebula.client.graph.data.Relationship;
2124
import com.vesoft.nebula.client.graph.data.ResultSet;
2225
import com.vesoft.nebula.client.graph.data.TimeWrapper;
@@ -39,6 +42,9 @@
3942
import org.nebula.contrib.ngbatis.proxy.MapperProxy;
4043
import org.slf4j.Logger;
4144
import org.slf4j.LoggerFactory;
45+
import org.springframework.data.geo.Box;
46+
import org.springframework.data.geo.Point;
47+
import org.springframework.data.geo.Polygon;
4248

4349
/**
4450
* 结果集基础类型处理的工具类
@@ -96,7 +102,8 @@ public static <T> T getValue(ValueWrapper value, Class<T> resultType) {
96102
: value.isSet() ? transformSet(value.asSet())
97103
: value.isMap() ? transformMap(value.asMap())
98104
: value.isDuration() ? transformDuration(value.asDuration())
99-
: null;
105+
: value.isGeography() ? transformGeo(value.asGeography())
106+
: null;
100107
if (o instanceof Number) {
101108
o = castNumber((Number) o, resultType);
102109
}
@@ -147,6 +154,41 @@ private static Object transformTime(TimeWrapper time) {
147154
private static Object transformDuration(DurationWrapper du) {
148155
return java.time.Duration.ofNanos(du.getSeconds() * 1000000000);
149156
}
157+
158+
private static Object transformGeo(GeographyWrapper geo) {
159+
String geoStr = String.valueOf(geo);
160+
boolean isPoint = geoStr.startsWith("POINT");
161+
boolean isLineString = geoStr.startsWith("LINESTRING");
162+
boolean isPolygon = geoStr.startsWith("POLYGON");
163+
164+
if (isPoint) {
165+
CoordinateWrapper coordinate = geo.getPointWrapper().getCoordinate();
166+
return coordToPoint(coordinate);
167+
} else if (isLineString) {
168+
List<CoordinateWrapper> coordinateList = geo.getLineStringWrapper().getCoordinateList();
169+
Point first = coordToPoint(coordinateList.get(0));
170+
Point second = coordToPoint(coordinateList.get(1));
171+
return new Box(first, second);
172+
} else if (isPolygon) {
173+
List<List<CoordinateWrapper>> coordListList = geo.getPolygonWrapper().getCoordListList();
174+
List<Point> points = new ArrayList<>();
175+
List<CoordinateWrapper> coordList = coordListList.get(0);
176+
int size = coordList.size();
177+
for (int i = 0; i < size; i++) {
178+
if (i == size - 1) {
179+
break;
180+
}
181+
CoordinateWrapper coordinate = coordList.get(i);
182+
points.add(coordToPoint(coordinate));
183+
}
184+
return new Polygon(points);
185+
}
186+
return null;
187+
}
188+
189+
private static Point coordToPoint(CoordinateWrapper coordinate) {
190+
return new Point(coordinate.getX(), coordinate.getY());
191+
}
150192

151193
private static Object transformNode(Node node, Class<?> resultType) {
152194
List<String> tagNames = node.tagNames();

0 commit comments

Comments
 (0)