Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rust/sedona-functions/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ wkb = { workspace = true }
wkt = { workspace = true }
serde_json = { workspace = true }
glam = { workspace = true }
geos = { workspace = true, features = ["geo"] }

[[bench]]
harness = false
Expand Down
1 change: 1 addition & 0 deletions rust/sedona-functions/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,4 @@ mod st_translate;
mod st_xyzm;
mod st_xyzm_minmax;
mod st_zmflag;
mod st_relate;
74 changes: 74 additions & 0 deletions rust/sedona-functions/src/st_relate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use arrow_array::builder::StringBuilder;
use arrow_schema::DataType;
use datafusion_common::{error::Result, DataFusionError};
use datafusion_expr::{ColumnarValue, Volatility};

use geos::{Geom, Geometry as GeosGeometry};

use sedona_expr::{
item_crs::ItemCrsKernel,
scalar_udf::{SedonaScalarKernel, SedonaScalarUDF},
};
use sedona_schema::{
datatypes::{SedonaType, WKB_GEOMETRY},
matchers::ArgMatcher,
};
use std::sync::Arc;
use crate::executor::WkbExecutor;

/// ST_Relate() scalar UDF
///
/// Returns a 9-character text string representing the DE-9IM relationship matrix
pub fn st_relate_udf() -> SedonaScalarUDF {
SedonaScalarUDF::new(
"st_relate",
ItemCrsKernel::wrap_impl(vec![Arc::new(STRelate)]),
Volatility::Immutable,
)
}

#[derive(Debug)]
struct STRelate;

impl SedonaScalarKernel for STRelate {
fn return_type(&self, args: &[SedonaType]) -> Result<Option<SedonaType>> {
let matcher = ArgMatcher::new(
vec![ArgMatcher::is_geometry(), ArgMatcher::is_geometry()],
SedonaType::Arrow(DataType::Utf8),
);
matcher.match_args(args)
}

fn invoke_batch(
&self,
arg_types: &[SedonaType],
args: &[ColumnarValue],
) -> Result<ColumnarValue> {
let mut executor = WkbExecutor::new(arg_types, args);
let mut builder = StringBuilder::with_capacity(
executor.num_iterations(),
9 * executor.num_iterations(),
);

executor.execute(|args| {
match (args[0], args[1]) {
(Some(wkb1), Some(wkb2)) => {
// Convert Sedona WKB to GEOS Geometry
let g1 = GeosGeometry::try_from(wkb1)
.map_err(|e| DataFusionError::Execution(format!("GEOS conversion error: {}", e)))?;
let g2 = GeosGeometry::try_from(wkb2)
.map_err(|e| DataFusionError::Execution(format!("GEOS conversion error: {}", e)))?;

let matrix = g1.relate(&g2)
.map_err(|e| DataFusionError::Execution(format!("ST_Relate error: {}", e)))?;

builder.append_value(matrix);
}
_ => builder.append_null(),
}
Ok(())
})?;

executor.finish(Arc::new(builder.finish()))
}
}
Loading