Skip to content

Commit d376bba

Browse files
committed
feat(query): Support Geometry aggregate functions
1 parent 77517f8 commit d376bba

File tree

30 files changed

+4569
-3106
lines changed

30 files changed

+4569
-3106
lines changed

Cargo.lock

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ futures = "0.3.24"
267267
futures-async-stream = { version = "0.2.7" }
268268
futures-util = "0.3.24"
269269
geo = { version = "0.32.0", features = ["use-serde"] }
270-
geo-index = "0.3.2"
270+
geo-index = "0.3.4"
271271
geohash = "0.13.1"
272272
geozero = { version = "0.15.1", features = ["with-geo", "with-geojson", "with-wkb", "with-wkt"] }
273273
gimli = "0.31.0"
@@ -397,7 +397,7 @@ pprof = { git = "https://github.com/datafuse-extras/pprof-rs", rev = "edecd74",
397397
] }
398398
pretty_assertions = "1.3.0"
399399
procfs = { version = "0.17.0" }
400-
proj4rs = { version = "0.1.9", features = ["geo-types", "crs-definitions"] }
400+
proj4rs = { version = "0.1.10", features = ["geo-types", "crs-definitions"] }
401401
proptest = { version = "1", default-features = false, features = ["std"] }
402402
prost = { version = "0.13" }
403403
prost-build = { version = "0.13" }

src/common/io/src/geography.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,16 @@ use geozero::ToGeo;
2525
use geozero::ToWkb;
2626
use geozero::geojson::GeoJson;
2727
use geozero::wkb::Ewkb;
28+
use hex::encode_upper;
2829

2930
use crate::ewkb_to_geo;
31+
use crate::geometry::GeometryDataType;
3032
use crate::geometry::ewkt_str_to_geo;
33+
use crate::geometry::geo_to_ewkb;
34+
use crate::geometry::geo_to_ewkt;
35+
use crate::geometry::geo_to_json;
36+
use crate::geometry::geo_to_wkb;
37+
use crate::geometry::geo_to_wkt;
3138

3239
pub const LONGITUDE_MIN: f64 = -180.0;
3340
pub const LONGITUDE_MAX: f64 = 180.0;
@@ -69,6 +76,20 @@ pub fn geography_from_geojson(json_str: &str) -> Result<Vec<u8>> {
6976
.map_err(|e| ErrorCode::GeometryError(e.to_string()))
7077
}
7178

79+
pub fn geography_format(ewkb: &[u8], format_type: GeometryDataType) -> Result<String> {
80+
let geo = Ewkb(ewkb)
81+
.to_geo()
82+
.map_err(|e| ErrorCode::GeometryError(e.to_string()))?;
83+
84+
match format_type {
85+
GeometryDataType::WKB => geo_to_wkb(geo).map(encode_upper),
86+
GeometryDataType::EWKB => geo_to_ewkb(geo, Some(GEOGRAPHY_SRID)).map(encode_upper),
87+
GeometryDataType::WKT => geo_to_wkt(geo),
88+
GeometryDataType::EWKT => geo_to_ewkt(geo, Some(GEOGRAPHY_SRID)),
89+
GeometryDataType::GEOJSON => geo_to_json(geo),
90+
}
91+
}
92+
7293
pub fn check_srid(srid: Option<i32>) -> Result<()> {
7394
if let Some(srid) = srid
7495
&& srid != GEOGRAPHY_SRID

src/common/io/src/geometry.rs

Lines changed: 26 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ use databend_common_exception::ErrorCode;
1919
use databend_common_exception::Result;
2020
use geo::BoundingRect;
2121
use geo::Geometry;
22+
use geo::LineString;
2223
use geo::Point;
24+
use geo::Polygon;
25+
use geo::Rect;
2326
use geohash::encode;
2427
use geozero::CoordDimensions;
2528
use geozero::GeomProcessor;
@@ -31,6 +34,7 @@ use geozero::ToWkt;
3134
use geozero::geo_types::GeoWriter;
3235
use geozero::geojson::GeoJson;
3336
use geozero::wkb::Ewkb;
37+
use hex::encode_upper;
3438
use serde::Deserialize;
3539
use serde::Serialize;
3640
use wkt::TryFromWkt;
@@ -185,49 +189,18 @@ pub(crate) fn ewkt_str_to_geo(input: &str) -> Result<(Geometry, Option<i32>)> {
185189
}
186190
}
187191

188-
pub trait GeometryFormatOutput {
189-
fn format(self, data_type: GeometryDataType) -> Result<String>;
190-
}
191-
impl<B: AsRef<[u8]>> GeometryFormatOutput for Ewkb<B> {
192-
fn format(self, format_type: GeometryDataType) -> Result<String> {
193-
match format_type {
194-
GeometryDataType::WKB => self
195-
.to_wkb(CoordDimensions::xy())
196-
.map(|bytes| {
197-
bytes
198-
.iter()
199-
.map(|b| format!("{:02X}", b))
200-
.collect::<Vec<_>>()
201-
.join("")
202-
})
203-
.map_err(|e| ErrorCode::GeometryError(e.to_string())),
204-
GeometryDataType::EWKB => Ok(self
205-
.0
206-
.as_ref()
207-
.iter()
208-
.map(|b| format!("{:02X}", b))
209-
.collect::<Vec<_>>()
210-
.join("")),
211-
GeometryDataType::WKT => self
212-
.to_wkt()
213-
.map_err(|e| ErrorCode::GeometryError(e.to_string())),
214-
GeometryDataType::EWKT => self
215-
.to_ewkt(self.srid())
216-
.map_err(|e| ErrorCode::GeometryError(e.to_string())),
217-
GeometryDataType::GEOJSON => self
218-
.to_json()
219-
.map_err(|e| ErrorCode::GeometryError(e.to_string())),
220-
}
192+
pub fn geometry_format(ewkb: &[u8], format_type: GeometryDataType) -> Result<String> {
193+
let (geo, srid) = ewkb_to_geo(&mut Ewkb(ewkb))?;
194+
let srid = srid.unwrap_or(0);
195+
match format_type {
196+
GeometryDataType::WKB => geo_to_wkb(geo).map(encode_upper),
197+
GeometryDataType::EWKB => geo_to_ewkb(geo, Some(srid)).map(encode_upper),
198+
GeometryDataType::WKT => geo_to_wkt(geo),
199+
GeometryDataType::EWKT => geo_to_ewkt(geo, Some(srid)),
200+
GeometryDataType::GEOJSON => geo_to_json(geo),
221201
}
222202
}
223203

224-
pub fn geometry_format<T: GeometryFormatOutput>(
225-
geometry: T,
226-
format_type: GeometryDataType,
227-
) -> Result<String> {
228-
geometry.format(format_type)
229-
}
230-
231204
/// Convert Geometry object to GEOJSON format.
232205
pub fn geo_to_json(geo: Geometry) -> Result<String> {
233206
geo.to_json()
@@ -258,6 +231,19 @@ pub fn geo_to_ewkt(geo: Geometry, srid: Option<i32>) -> Result<String> {
258231
.map_err(|e| ErrorCode::GeometryError(e.to_string()))
259232
}
260233

234+
pub fn rect_to_polygon(rect: Rect<f64>) -> Polygon<f64> {
235+
let min = rect.min();
236+
let max = rect.max();
237+
let exterior = LineString::from(vec![
238+
(min.x, min.y),
239+
(max.x, min.y),
240+
(max.x, max.y),
241+
(min.x, max.y),
242+
(min.x, min.y),
243+
]);
244+
Polygon::new(exterior, vec![])
245+
}
246+
261247
/// Process EWKB input and return SRID.
262248
pub fn read_srid<B: AsRef<[u8]>>(ewkb: &mut Ewkb<B>) -> Option<i32> {
263249
let mut srid_processor = SridProcessor::new();

src/common/io/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub use decimal::display_decimal_256_trimmed;
6262
pub use escape::escape_string;
6363
pub use escape::escape_string_with_quote;
6464
pub use geography::GEOGRAPHY_SRID;
65+
pub use geography::geography_format;
6566
pub use geometry::Axis;
6667
pub use geometry::Extremum;
6768
pub use geometry::GeometryDataType;

src/query/expression/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ micromarshal = { workspace = true }
5252
num-bigint = { workspace = true }
5353
num-derive = { workspace = true }
5454
num-traits = { workspace = true }
55+
proj4rs = { workspace = true }
5556
rand = { workspace = true }
5657
rand_distr = { workspace = true }
5758
recursive = { workspace = true }

0 commit comments

Comments
 (0)