This is an automated email from the ASF dual-hosted git repository.

paleolimbot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/sedona-db.git


The following commit(s) were added to refs/heads/main by this push:
     new faa3ed72 feat(rust/sedona-raster-functions): Add RS_Height (#302)
faa3ed72 is described below

commit faa3ed722d7505533cdaca323c3c20d2ff1d6606
Author: jp <[email protected]>
AuthorDate: Sat Nov 15 13:34:28 2025 -0800

    feat(rust/sedona-raster-functions): Add RS_Height (#302)
    
    Co-authored-by: Dewey Dunnington <[email protected]>
---
 Cargo.lock                                         |  2 +
 rust/sedona-raster-functions/Cargo.toml            |  1 +
 .../benches/native-raster-functions.rs             |  1 +
 rust/sedona-raster-functions/src/register.rs       |  3 +-
 rust/sedona-raster-functions/src/rs_size.rs        | 85 ++++++++++++++++++----
 rust/sedona/Cargo.toml                             |  1 +
 rust/sedona/src/context.rs                         |  3 +
 7 files changed, 80 insertions(+), 16 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index b6ad1c25..45e771cd 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4839,6 +4839,7 @@ dependencies = [
  "sedona-geoparquet",
  "sedona-geos",
  "sedona-proj",
+ "sedona-raster-functions",
  "sedona-s2geography",
  "sedona-schema",
  "sedona-spatial-join",
@@ -5164,6 +5165,7 @@ dependencies = [
  "criterion",
  "datafusion-common",
  "datafusion-expr",
+ "rstest",
  "sedona-common",
  "sedona-expr",
  "sedona-raster",
diff --git a/rust/sedona-raster-functions/Cargo.toml 
b/rust/sedona-raster-functions/Cargo.toml
index d0a2ea17..b674b136 100644
--- a/rust/sedona-raster-functions/Cargo.toml
+++ b/rust/sedona-raster-functions/Cargo.toml
@@ -41,6 +41,7 @@ sedona-schema = { path = "../sedona-schema" }
 [dev-dependencies]
 criterion = { workspace = true }
 sedona-testing = { path = "../sedona-testing", features = ["criterion"] }
+rstest = { workspace = true }
 
 [[bench]]
 harness = false
diff --git a/rust/sedona-raster-functions/benches/native-raster-functions.rs 
b/rust/sedona-raster-functions/benches/native-raster-functions.rs
index d729ccc5..3d1901f8 100644
--- a/rust/sedona-raster-functions/benches/native-raster-functions.rs
+++ b/rust/sedona-raster-functions/benches/native-raster-functions.rs
@@ -20,6 +20,7 @@ use sedona_testing::benchmark_util::{benchmark, 
BenchmarkArgSpec::*};
 fn criterion_benchmark(c: &mut Criterion) {
     let f = sedona_raster_functions::register::default_function_set();
 
+    benchmark::scalar(c, &f, "native", "rs_height", Raster(64, 64));
     benchmark::scalar(c, &f, "native", "rs_width", Raster(64, 64));
 }
 
diff --git a/rust/sedona-raster-functions/src/register.rs 
b/rust/sedona-raster-functions/src/register.rs
index 1945372d..fca2f862 100644
--- a/rust/sedona-raster-functions/src/register.rs
+++ b/rust/sedona-raster-functions/src/register.rs
@@ -38,8 +38,9 @@ pub fn default_function_set() -> FunctionSet {
 
     register_scalar_udfs!(
         function_set,
-        crate::rs_size::rs_width_udf,
         crate::rs_example::rs_example_udf,
+        crate::rs_size::rs_height_udf,
+        crate::rs_size::rs_width_udf,
     );
 
     register_aggregate_udfs!(function_set,);
diff --git a/rust/sedona-raster-functions/src/rs_size.rs 
b/rust/sedona-raster-functions/src/rs_size.rs
index 6b6d200f..ff16edc9 100644
--- a/rust/sedona-raster-functions/src/rs_size.rs
+++ b/rust/sedona-raster-functions/src/rs_size.rs
@@ -33,12 +33,28 @@ use sedona_schema::{datatypes::SedonaType, 
matchers::ArgMatcher};
 pub fn rs_width_udf() -> SedonaScalarUDF {
     SedonaScalarUDF::new(
         "rs_width",
-        vec![Arc::new(RsWidth {})],
+        vec![Arc::new(RsSize {
+            size_type: SizeType::Width,
+        })],
         Volatility::Immutable,
         Some(rs_width_doc()),
     )
 }
 
+/// RS_Height() scalar UDF documentation
+///
+/// Extract the height of the raster
+pub fn rs_height_udf() -> SedonaScalarUDF {
+    SedonaScalarUDF::new(
+        "rs_height",
+        vec![Arc::new(RsSize {
+            size_type: SizeType::Height,
+        })],
+        Volatility::Immutable,
+        Some(rs_height_doc()),
+    )
+}
+
 fn rs_width_doc() -> Documentation {
     Documentation::builder(
         DOC_SECTION_OTHER,
@@ -50,10 +66,29 @@ fn rs_width_doc() -> Documentation {
     .build()
 }
 
+fn rs_height_doc() -> Documentation {
+    Documentation::builder(
+        DOC_SECTION_OTHER,
+        "Return the height component of a raster".to_string(),
+        "RS_Height(raster: Raster)".to_string(),
+    )
+    .with_argument("raster", "Raster: Input raster")
+    .with_sql_example("SELECT RS_Height(raster)".to_string())
+    .build()
+}
+
+#[derive(Debug, Clone)]
+enum SizeType {
+    Width,
+    Height,
+}
+
 #[derive(Debug)]
-struct RsWidth {}
+struct RsSize {
+    size_type: SizeType,
+}
 
-impl SedonaScalarKernel for RsWidth {
+impl SedonaScalarKernel for RsSize {
     fn return_type(&self, args: &[SedonaType]) -> Result<Option<SedonaType>> {
         let matcher = ArgMatcher::new(
             vec![ArgMatcher::is_raster()],
@@ -74,10 +109,16 @@ impl SedonaScalarKernel for RsWidth {
         executor.execute_raster_void(|_i, raster_opt| {
             match raster_opt {
                 None => builder.append_null(),
-                Some(raster) => {
-                    let width = raster.metadata().width();
-                    builder.append_value(width);
-                }
+                Some(raster) => match self.size_type {
+                    SizeType::Width => {
+                        let width = raster.metadata().width();
+                        builder.append_value(width);
+                    }
+                    SizeType::Height => {
+                        let height = raster.metadata().height();
+                        builder.append_value(height);
+                    }
+                },
             }
             Ok(())
         })?;
@@ -91,6 +132,7 @@ mod tests {
     use super::*;
     use arrow_array::{Array, UInt64Array};
     use datafusion_expr::ScalarUDF;
+    use rstest::rstest;
     use sedona_schema::datatypes::RASTER;
     use sedona_testing::rasters::generate_test_rasters;
 
@@ -99,15 +141,21 @@ mod tests {
         let udf: ScalarUDF = rs_width_udf().into();
         assert_eq!(udf.name(), "rs_width");
         assert!(udf.documentation().is_some());
+
+        let udf: ScalarUDF = rs_height_udf().into();
+        assert_eq!(udf.name(), "rs_height");
+        assert!(udf.documentation().is_some());
     }
 
-    #[test]
-    fn udf_invoke() {
+    #[rstest]
+    fn udf_invoke(#[values(SizeType::Width, SizeType::Height)] st: SizeType) {
+        let kernel = RsSize {
+            size_type: st.clone(),
+        };
         // 3 rasters, second one is null
         let rasters = generate_test_rasters(3, Some(1)).unwrap();
 
         // Create the UDF and invoke it
-        let kernel = RsWidth {};
         let args = [ColumnarValue::Array(Arc::new(rasters))];
         let arg_types = vec![RASTER];
 
@@ -115,12 +163,19 @@ mod tests {
 
         // Check the result
         if let ColumnarValue::Array(result_array) = result {
-            let width_array = 
result_array.as_any().downcast_ref::<UInt64Array>().unwrap();
+            let size_array = 
result_array.as_any().downcast_ref::<UInt64Array>().unwrap();
+
+            assert_eq!(size_array.len(), 3);
 
-            assert_eq!(width_array.len(), 3);
-            assert_eq!(width_array.value(0), 1); // First raster width
-            assert!(width_array.is_null(1)); // Second raster is null
-            assert_eq!(width_array.value(2), 3); // Third raster width
+            match st.clone() {
+                SizeType::Width => assert_eq!(size_array.value(0), 1), // 
First raster width
+                SizeType::Height => assert_eq!(size_array.value(0), 2), // 
First raster height
+            }
+            assert!(size_array.is_null(1)); // Second raster is null
+            match st.clone() {
+                SizeType::Width => assert_eq!(size_array.value(2), 3), // 
Third raster width
+                SizeType::Height => assert_eq!(size_array.value(2), 4), // 
Third raster height
+            }
         } else {
             panic!("Expected array result");
         }
diff --git a/rust/sedona/Cargo.toml b/rust/sedona/Cargo.toml
index c7cb95a2..66f4324e 100644
--- a/rust/sedona/Cargo.toml
+++ b/rust/sedona/Cargo.toml
@@ -70,6 +70,7 @@ sedona-geometry = { path = "../sedona-geometry" }
 sedona-geoparquet = { path = "../sedona-geoparquet" }
 sedona-geos = { path = "../../c/sedona-geos", optional = true }
 sedona-proj = { path = "../../c/sedona-proj", default-features = false }
+sedona-raster-functions = { path = "../../rust/sedona-raster-functions" }
 sedona-schema = { path = "../sedona-schema" }
 sedona-spatial-join = { path = "../sedona-spatial-join", optional = true }
 sedona-s2geography = { path = "../../c/sedona-s2geography", optional = true }
diff --git a/rust/sedona/src/context.rs b/rust/sedona/src/context.rs
index bd503e5d..3903cfa9 100644
--- a/rust/sedona/src/context.rs
+++ b/rust/sedona/src/context.rs
@@ -153,6 +153,9 @@ impl SedonaContext {
         // is called).
         
out.register_scalar_kernels(sedona_proj::register::scalar_kernels().into_iter())?;
 
+        // Always register raster functions
+        
out.register_function_set(sedona_raster_functions::register::default_function_set());
+
         Ok(out)
     }
 

Reply via email to