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 2de9e8e7 refactor(rust/sedona-functions): Remove stub functions (#638)
2de9e8e7 is described below

commit 2de9e8e78b59ea744c0081b14f74988916c8097e
Author: Dewey Dunnington <[email protected]>
AuthorDate: Sat Feb 21 20:15:57 2026 -0600

    refactor(rust/sedona-functions): Remove stub functions (#638)
---
 docs/reference/sql/_render_meta.py                 |  11 +++
 rust/sedona-expr/src/aggregate_udf.rs              |  85 +---------------
 rust/sedona-expr/src/function_set.rs               |  36 +++----
 rust/sedona-expr/src/scalar_udf.rs                 |  48 ++-------
 rust/sedona-functions/src/distance.rs              |  57 -----------
 rust/sedona-functions/src/lib.rs                   |  27 ++----
 rust/sedona-functions/src/overlay.rs               |  66 -------------
 rust/sedona-functions/src/predicates.rs            | 108 ---------------------
 rust/sedona-functions/src/referencing.rs           |  63 ------------
 rust/sedona-functions/src/register.rs              |  50 +---------
 rust/sedona-functions/src/st_analyze_agg.rs        |  25 +++--
 rust/sedona-functions/src/st_area.rs               |  47 ---------
 rust/sedona-functions/src/st_asgeojson.rs          |  47 ---------
 rust/sedona-functions/src/st_buffer.rs             |  47 ---------
 rust/sedona-functions/src/st_centroid.rs           |  43 --------
 rust/sedona-functions/src/st_concavehull.rs        |  46 ---------
 rust/sedona-functions/src/st_intersection_agg.rs   |  51 ----------
 rust/sedona-functions/src/st_isempty.rs            |   4 -
 .../src/{st_dwithin.rs => st_knn.rs}               |  28 ++++--
 rust/sedona-functions/src/st_length.rs             |  47 ---------
 rust/sedona-functions/src/st_line_merge.rs         |  43 --------
 rust/sedona-functions/src/st_perimeter.rs          |  51 ----------
 rust/sedona-functions/src/st_polygonize_agg.rs     |  45 ---------
 rust/sedona-functions/src/st_transform.rs          |  55 -----------
 rust/sedona-functions/src/st_union_agg.rs          |  51 ----------
 rust/sedona-geo/src/st_area.rs                     |   5 +-
 rust/sedona-geo/src/st_centroid.rs                 |   8 +-
 rust/sedona-geo/src/st_intersection_agg.rs         |  14 +--
 rust/sedona-geo/src/st_intersects.rs               |  11 +--
 rust/sedona-geo/src/st_length.rs                   |   5 +-
 rust/sedona-geo/src/st_line_interpolate_point.rs   |   5 +-
 rust/sedona-geo/src/st_perimeter.rs                |   8 +-
 rust/sedona-geo/src/st_union_agg.rs                |  14 +--
 .../tests/spatial_join_integration.rs              |  16 ++-
 34 files changed, 117 insertions(+), 1150 deletions(-)

diff --git a/docs/reference/sql/_render_meta.py 
b/docs/reference/sql/_render_meta.py
index ff41c5e8..949273da 100644
--- a/docs/reference/sql/_render_meta.py
+++ b/docs/reference/sql/_render_meta.py
@@ -187,6 +187,17 @@ def to_str(v):
             return " "
         elif v["t"] == "Para":
             return "".join(to_str(item) for item in v["c"])
+        if v["t"] == "Quoted":
+            quote_type = v["c"][0]["t"]
+            if quote_type == "SingleQuote":
+                quote_char = "'"
+            elif quote_type == "DoubleQuote":
+                quote_char = '"'
+            else:
+                raise ValueError(f"Unhandled quote type in ast {v}")
+
+            content = "".join(to_str(item) for item in v["c"][1])
+            return f"{quote_char}{content}{quote_char}"
         else:
             raise ValueError(f"Unhandled type in Pandoc ast convert: {v}")
     else:
diff --git a/rust/sedona-expr/src/aggregate_udf.rs 
b/rust/sedona-expr/src/aggregate_udf.rs
index 6d2b655b..e2d6c076 100644
--- a/rust/sedona-expr/src/aggregate_udf.rs
+++ b/rust/sedona-expr/src/aggregate_udf.rs
@@ -25,8 +25,6 @@ use datafusion_expr::{
 use sedona_common::sedona_internal_err;
 use sedona_schema::datatypes::SedonaType;
 
-use sedona_schema::matchers::ArgMatcher;
-
 /// Shorthand for a [SedonaAccumulator] reference
 pub type SedonaAccumulatorRef = Arc<dyn SedonaAccumulator>;
 
@@ -101,16 +99,9 @@ impl SedonaAggregateUDF {
         }
     }
 
-    /// Create a new stub aggregate function
-    ///
-    /// Creates a new aggregate function that calculates a return type but 
fails when
-    /// invoked with arguments. This is useful to create stub functions when 
it is
-    /// expected that the actual functionality will be registered from one or 
more
-    /// independent crates (e.g., ST_Union_Agg(), which may be implemented in
-    /// sedona-geo or sedona-geography).
-    pub fn new_stub(name: &str, arg_matcher: ArgMatcher, volatility: 
Volatility) -> Self {
-        let stub_kernel = StubAccumulator::new(name.to_string(), arg_matcher);
-        Self::new(name, stub_kernel, volatility)
+    /// Create a new immutable SedonaAggregateUDF
+    pub fn from_impl(name: &str, kernels: impl IntoSedonaAccumulatorRefs) -> 
Self {
+        Self::new(name, kernels, Volatility::Immutable)
     }
 
     /// Add a new kernel to an Aggregate UDF
@@ -261,43 +252,8 @@ pub trait SedonaAccumulator: Debug + Send + Sync {
     fn state_fields(&self, args: &[SedonaType]) -> Result<Vec<FieldRef>>;
 }
 
-#[derive(Debug)]
-struct StubAccumulator {
-    name: String,
-    matcher: ArgMatcher,
-}
-
-impl StubAccumulator {
-    fn new(name: String, matcher: ArgMatcher) -> Self {
-        Self { name, matcher }
-    }
-}
-
-impl SedonaAccumulator for StubAccumulator {
-    fn return_type(&self, args: &[SedonaType]) -> Result<Option<SedonaType>> {
-        self.matcher.match_args(args)
-    }
-
-    fn accumulator(
-        &self,
-        args: &[SedonaType],
-        _output_type: &SedonaType,
-    ) -> Result<Box<dyn Accumulator>> {
-        not_impl_err!(
-            "Implementation for {}({args:?}) was not registered",
-            self.name
-        )
-    }
-
-    fn state_fields(&self, _args: &[SedonaType]) -> Result<Vec<FieldRef>> {
-        Ok(vec![])
-    }
-}
-
 #[cfg(test)]
 mod test {
-    use sedona_testing::testers::AggregateUdfTester;
-
     use crate::aggregate_udf::SedonaAggregateUDF;
 
     use super::*;
@@ -324,39 +280,4 @@ mod test {
 
         Ok(())
     }
-
-    #[test]
-    fn stub() {
-        let stub = SedonaAggregateUDF::new_stub(
-            "stubby",
-            ArgMatcher::new(vec![], SedonaType::Arrow(DataType::Boolean)),
-            Volatility::Immutable,
-        );
-
-        // We registered the stub with zero arguments, so when we call it
-        // with zero arguments it should calculate a return type but
-        // produce our stub error message when used.
-        let tester = AggregateUdfTester::new(stub.clone().into(), vec![]);
-        assert_eq!(
-            tester.return_type().unwrap(),
-            SedonaType::Arrow(DataType::Boolean)
-        );
-
-        let err = tester.aggregate(&vec![]).unwrap_err();
-        assert_eq!(
-            err.message(),
-            "Implementation for stubby([]) was not registered"
-        );
-
-        // If we call with anything else, we shouldn't be able to do anything
-        let tester = AggregateUdfTester::new(
-            stub.clone().into(),
-            vec![SedonaType::Arrow(DataType::Binary)],
-        );
-        let err = tester.return_type().unwrap_err();
-        assert_eq!(
-            err.message(),
-            "stubby([Arrow(Binary)]): No kernel matching arguments"
-        );
-    }
 }
diff --git a/rust/sedona-expr/src/function_set.rs 
b/rust/sedona-expr/src/function_set.rs
index 3332d8da..3d862085 100644
--- a/rust/sedona-expr/src/function_set.rs
+++ b/rust/sedona-expr/src/function_set.rs
@@ -20,7 +20,6 @@ use crate::{
 };
 use datafusion_common::error::Result;
 use datafusion_expr::{AggregateUDFImpl, ScalarUDFImpl};
-use sedona_common::sedona_internal_err;
 use std::collections::HashMap;
 
 /// Helper for managing groups of functions
@@ -96,9 +95,8 @@ impl FunctionSet {
 
     /// Add a kernel to a function in this set
     ///
-    /// This adds a scalar UDF with immutable output and no documentation if a
-    /// function of that name does not exist in this set. A reference to the
-    /// matching function is returned.
+    /// This adds a scalar UDF with immutable output if a function of that 
name does not
+    /// exist in this set. A reference to the matching or inserted function is 
returned.
     pub fn add_scalar_udf_impl(
         &mut self,
         name: &str,
@@ -116,8 +114,8 @@ impl FunctionSet {
 
     /// Add an aggregate kernel to a function in this set
     ///
-    /// This errors if a function of that name does not exist in this set. A 
reference
-    /// to the matching function is returned.
+    /// This adds an aggregate UDF with immutable output if a function of that 
name does not
+    /// exist in this set. A reference to the matching or inserted function is 
returned.
     pub fn add_aggregate_udf_kernel(
         &mut self,
         name: &str,
@@ -125,10 +123,12 @@ impl FunctionSet {
     ) -> Result<&SedonaAggregateUDF> {
         if let Some(function) = self.aggregate_udf_mut(name) {
             function.add_kernel(kernel);
-            Ok(self.aggregate_udf(name).unwrap())
         } else {
-            sedona_internal_err!("Can't register aggregate kernel for function 
'{}'", name)
+            let function = SedonaAggregateUDF::from_impl(name, kernel);
+            self.insert_aggregate_udf(function);
         }
+
+        Ok(self.aggregate_udf(name).unwrap())
     }
 }
 
@@ -261,12 +261,10 @@ mod tests {
                 .name(),
             "simple_udaf"
         );
-        let err = functions
-            .add_aggregate_udf_kernel("function that does not exist", 
kernel.clone())
-            .unwrap_err();
-        assert!(err.message().lines().next().unwrap().contains(
-            "Can't register aggregate kernel for function 'function that does 
not exist'."
-        ));
+        let added_func = functions
+            .add_aggregate_udf_kernel("function that does not exist yet", 
kernel.clone())
+            .unwrap();
+        assert_eq!(added_func.name(), "function that does not exist yet");
 
         let udaf2 = SedonaAggregateUDF::new(
             "simple_udaf2",
@@ -281,9 +279,13 @@ mod tests {
                 .aggregate_udfs()
                 .map(|s| s.name())
                 .collect::<HashSet<_>>(),
-            vec!["simple_udaf", "simple_udaf2"]
-                .into_iter()
-                .collect::<HashSet<_>>()
+            vec![
+                "simple_udaf",
+                "simple_udaf2",
+                "function that does not exist yet"
+            ]
+            .into_iter()
+            .collect::<HashSet<_>>()
         );
     }
 }
diff --git a/rust/sedona-expr/src/scalar_udf.rs 
b/rust/sedona-expr/src/scalar_udf.rs
index 02d89f35..37c6cff0 100644
--- a/rust/sedona-expr/src/scalar_udf.rs
+++ b/rust/sedona-expr/src/scalar_udf.rs
@@ -204,24 +204,6 @@ impl SedonaScalarUDF {
         }
     }
 
-    /// Create a new stub function
-    ///
-    /// Creates a new function that calculates a return type but fails when 
invoked with
-    /// arguments. This is useful to create stub functions when it is expected 
that the
-    /// actual functionality will be registered from one or more independent 
crates
-    /// (e.g., ST_Intersects(), which may be implemented in sedona-geo or 
sedona-geography).
-    pub fn new_stub(name: &str, arg_matcher: ArgMatcher, volatility: 
Volatility) -> Self {
-        let name_string = name.to_string();
-        let stub_kernel = SimpleSedonaScalarKernel::new_ref(
-            arg_matcher,
-            Arc::new(move |arg_types, _| {
-                not_impl_err!("Implementation for {name_string}({arg_types:?}) 
was not registered")
-            }),
-        );
-
-        Self::new(name, vec![stub_kernel], volatility)
-    }
-
     /// Create a SedonaScalarUDF from a single kernel
     ///
     /// This constructor creates a [Volatility::Immutable] function with no 
documentation
@@ -331,6 +313,7 @@ impl ScalarUDFImpl for SedonaScalarUDF {
 
 #[cfg(test)]
 mod tests {
+
     use datafusion_common::{scalar::ScalarValue, DFSchema};
     use sedona_testing::testers::ScalarUdfTester;
 
@@ -426,34 +409,17 @@ mod tests {
         tester.assert_return_type(DataType::Utf8);
     }
 
-    #[test]
-    fn stub() {
-        let stub = SedonaScalarUDF::new_stub(
-            "stubby",
-            ArgMatcher::new(vec![], SedonaType::Arrow(DataType::Boolean)),
-            Volatility::Immutable,
-        );
-        let tester = ScalarUdfTester::new(stub.into(), vec![]);
-        tester.assert_return_type(DataType::Boolean);
-
-        let err = tester.invoke_arrays(vec![]).unwrap_err();
-        assert_eq!(
-            err.message(),
-            "Implementation for stubby([]) was not registered"
-        );
-    }
-
     #[test]
     fn crs_propagation() {
         let geom_lnglat = SedonaType::Wkb(Edges::Planar, lnglat());
-        let predicate_stub = SedonaScalarUDF::new_stub(
-            "stubby",
+        let predicate_stub_impl = SimpleSedonaScalarKernel::new_ref(
             ArgMatcher::new(
                 vec![ArgMatcher::is_geometry(), ArgMatcher::is_geometry()],
                 SedonaType::Arrow(DataType::Boolean),
             ),
-            Volatility::Immutable,
+            Arc::new(|_arg_types, _args| unreachable!("Should not be 
executed")),
         );
+        let predicate_stub = SedonaScalarUDF::from_impl("foofy", 
predicate_stub_impl);
 
         // None CRS to None CRS is OK
         let tester = ScalarUdfTester::new(
@@ -478,14 +444,14 @@ mod tests {
         assert!(err.message().starts_with("Mismatched CRS arguments"));
 
         // When geometry is output, it should match the crses of the inputs
-        let geom_out_stub = SedonaScalarUDF::new_stub(
-            "stubby",
+        let geom_out_impl = SimpleSedonaScalarKernel::new_ref(
             ArgMatcher::new(
                 vec![ArgMatcher::is_geometry(), ArgMatcher::is_geometry()],
                 WKB_GEOMETRY,
             ),
-            Volatility::Immutable,
+            Arc::new(|_arg_types, args| Ok(args[0].clone())),
         );
+        let geom_out_stub = SedonaScalarUDF::from_impl("foofy", geom_out_impl);
 
         let tester = ScalarUdfTester::new(
             geom_out_stub.clone().into(),
diff --git a/rust/sedona-functions/src/distance.rs 
b/rust/sedona-functions/src/distance.rs
deleted file mode 100644
index 5924b235..00000000
--- a/rust/sedona-functions/src/distance.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use arrow_schema::DataType;
-use datafusion_expr::Volatility;
-use sedona_expr::scalar_udf::SedonaScalarUDF;
-use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher};
-
-/// ST_Distance() scalar UDF stub
-pub fn st_distance_udf() -> SedonaScalarUDF {
-    distance_stub_udf("ST_Distance")
-}
-
-/// ST_MaxDistance() scalar UDF stub
-pub fn st_max_distance_udf() -> SedonaScalarUDF {
-    distance_stub_udf("ST_MaxDistance")
-}
-
-pub fn distance_stub_udf(name: &str) -> SedonaScalarUDF {
-    SedonaScalarUDF::new_stub(
-        &name.to_lowercase(),
-        ArgMatcher::new(
-            vec![
-                ArgMatcher::is_geometry_or_geography(),
-                ArgMatcher::is_geometry_or_geography(),
-            ],
-            SedonaType::Arrow(DataType::Float64),
-        ),
-        Volatility::Immutable,
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use datafusion_expr::ScalarUDF;
-
-    use super::*;
-
-    #[test]
-    fn udf_metadata() {
-        let udf: ScalarUDF = st_distance_udf().into();
-        assert_eq!(udf.name(), "st_distance");
-    }
-}
diff --git a/rust/sedona-functions/src/lib.rs b/rust/sedona-functions/src/lib.rs
index 57acef7d..2c9ad0e1 100644
--- a/rust/sedona-functions/src/lib.rs
+++ b/rust/sedona-functions/src/lib.rs
@@ -14,33 +14,24 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-mod distance;
+
 pub mod executor;
-mod overlay;
-mod predicates;
-mod referencing;
 pub mod register;
 mod sd_format;
 pub mod sd_order;
 mod st_affine;
 mod st_affine_helpers;
 pub mod st_analyze_agg;
-mod st_area;
 mod st_asbinary;
 mod st_asewkb;
-mod st_asgeojson;
 mod st_astext;
 mod st_azimuth;
-mod st_buffer;
-mod st_centroid;
 mod st_collect_agg;
-mod st_concavehull;
 mod st_dimension;
 mod st_dump;
-mod st_dwithin;
 pub mod st_envelope;
-pub mod st_envelope_agg;
-pub mod st_flipcoordinates;
+mod st_envelope_agg;
+mod st_flipcoordinates;
 mod st_force_dim;
 mod st_geometryn;
 mod st_geometrytype;
@@ -49,29 +40,23 @@ mod st_geomfromwkb;
 mod st_geomfromwkt;
 mod st_haszm;
 mod st_interiorringn;
-pub mod st_intersection_agg;
-pub mod st_isclosed;
+mod st_isclosed;
 mod st_iscollection;
-pub mod st_isempty;
-mod st_length;
-mod st_line_merge;
+mod st_isempty;
+mod st_knn;
 mod st_makeline;
 mod st_numgeometries;
-mod st_perimeter;
 mod st_point;
 mod st_pointn;
 mod st_points;
 mod st_pointzm;
-mod st_polygonize_agg;
 mod st_reverse;
 mod st_rotate;
 mod st_scale;
 mod st_setsrid;
 mod st_srid;
 mod st_start_point;
-mod st_transform;
 mod st_translate;
-pub mod st_union_agg;
 mod st_xyzm;
 mod st_xyzm_minmax;
 mod st_zmflag;
diff --git a/rust/sedona-functions/src/overlay.rs 
b/rust/sedona-functions/src/overlay.rs
deleted file mode 100644
index 49557fad..00000000
--- a/rust/sedona-functions/src/overlay.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use datafusion_expr::Volatility;
-use sedona_expr::scalar_udf::SedonaScalarUDF;
-use sedona_schema::{datatypes::WKB_GEOMETRY, matchers::ArgMatcher};
-
-/// ST_Intersection() scalar UDF stub
-pub fn st_intersection_udf() -> SedonaScalarUDF {
-    overlay_stub_udf("ST_Intersection")
-}
-
-/// ST_Union() scalar UDF stub
-pub fn st_union_udf() -> SedonaScalarUDF {
-    overlay_stub_udf("ST_Union")
-}
-
-/// ST_Difference() scalar UDF stub
-pub fn st_difference_udf() -> SedonaScalarUDF {
-    overlay_stub_udf("ST_Difference")
-}
-
-/// ST_SymDifference() scalar UDF stub
-pub fn st_sym_difference_udf() -> SedonaScalarUDF {
-    overlay_stub_udf("ST_SymDifference")
-}
-
-pub fn overlay_stub_udf(name: &str) -> SedonaScalarUDF {
-    SedonaScalarUDF::new_stub(
-        &name.to_lowercase(),
-        ArgMatcher::new(
-            vec![
-                ArgMatcher::is_geometry_or_geography(),
-                ArgMatcher::is_geometry_or_geography(),
-            ],
-            WKB_GEOMETRY,
-        ),
-        Volatility::Immutable,
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use datafusion_expr::ScalarUDF;
-
-    use super::*;
-
-    #[test]
-    fn udf_metadata() {
-        let udf: ScalarUDF = st_intersection_udf().into();
-        assert_eq!(udf.name(), "st_intersection");
-    }
-}
diff --git a/rust/sedona-functions/src/predicates.rs 
b/rust/sedona-functions/src/predicates.rs
deleted file mode 100644
index f4d5233f..00000000
--- a/rust/sedona-functions/src/predicates.rs
+++ /dev/null
@@ -1,108 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use arrow_schema::DataType;
-use datafusion_expr::Volatility;
-use sedona_expr::scalar_udf::SedonaScalarUDF;
-use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher};
-
-/// ST_Equals() scalar UDF stub
-pub fn st_equals_udf() -> SedonaScalarUDF {
-    predicate_stub_udf("ST_Equals")
-}
-
-/// ST_Intersects() scalar UDF stub
-pub fn st_intersects_udf() -> SedonaScalarUDF {
-    predicate_stub_udf("ST_Intersects")
-}
-
-/// ST_Disjoint() scalar UDF stub
-pub fn st_disjoint_udf() -> SedonaScalarUDF {
-    predicate_stub_udf("ST_Disjoint")
-}
-
-/// ST_Contains() scalar UDF stub
-pub fn st_contains_udf() -> SedonaScalarUDF {
-    predicate_stub_udf("ST_Contains")
-}
-
-/// ST_Within() scalar UDF stub
-pub fn st_within_udf() -> SedonaScalarUDF {
-    predicate_stub_udf("ST_Within")
-}
-
-/// ST_Covers() scalar UDF stub
-pub fn st_covers_udf() -> SedonaScalarUDF {
-    predicate_stub_udf("ST_Covers")
-}
-
-/// ST_CoveredBy() scalar UDF stub
-pub fn st_covered_by_udf() -> SedonaScalarUDF {
-    predicate_stub_udf("ST_CoveredBy")
-}
-
-/// ST_Touches() scalar UDF stub
-pub fn st_touches_udf() -> SedonaScalarUDF {
-    predicate_stub_udf("ST_Touches")
-}
-
-/// ST_KNN() scalar UDF stub
-///
-/// This is a stub function that defines the signature and documentation for 
ST_KNN
-/// but does not contain an actual implementation. The real k-nearest 
neighbors logic
-/// is handled by the spatial join execution engine.
-pub fn st_knn_udf() -> SedonaScalarUDF {
-    SedonaScalarUDF::new_stub(
-        "st_knn",
-        ArgMatcher::new(
-            vec![
-                ArgMatcher::is_geometry_or_geography(),
-                ArgMatcher::is_geometry_or_geography(),
-                ArgMatcher::is_numeric(),
-                ArgMatcher::is_boolean(),
-            ],
-            SedonaType::Arrow(DataType::Boolean),
-        ),
-        Volatility::Immutable,
-    )
-}
-
-pub fn predicate_stub_udf(name: &str) -> SedonaScalarUDF {
-    SedonaScalarUDF::new_stub(
-        &name.to_lowercase(),
-        ArgMatcher::new(
-            vec![
-                ArgMatcher::is_geometry_or_geography(),
-                ArgMatcher::is_geometry_or_geography(),
-            ],
-            SedonaType::Arrow(DataType::Boolean),
-        ),
-        Volatility::Immutable,
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use datafusion_expr::ScalarUDF;
-
-    use super::*;
-
-    #[test]
-    fn udf_metadata() {
-        let udf: ScalarUDF = st_intersects_udf().into();
-        assert_eq!(udf.name(), "st_intersects");
-    }
-}
diff --git a/rust/sedona-functions/src/referencing.rs 
b/rust/sedona-functions/src/referencing.rs
deleted file mode 100644
index d83c704a..00000000
--- a/rust/sedona-functions/src/referencing.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use arrow_schema::DataType;
-use datafusion_expr::Volatility;
-use sedona_expr::scalar_udf::SedonaScalarUDF;
-use sedona_schema::{
-    datatypes::{SedonaType, WKB_GEOMETRY},
-    matchers::ArgMatcher,
-};
-
-/// ST_LineLocatePoint() scalar UDF implementation
-pub fn st_line_locate_point_udf() -> SedonaScalarUDF {
-    SedonaScalarUDF::new_stub(
-        "st_linelocatepoint",
-        ArgMatcher::new(
-            vec![ArgMatcher::is_geometry(), ArgMatcher::is_geometry()],
-            SedonaType::Arrow(DataType::Float64),
-        ),
-        Volatility::Immutable,
-    )
-}
-
-/// ST_LineInterpolatePoint() scalar UDF implementation
-pub fn st_line_interpolate_point_udf() -> SedonaScalarUDF {
-    SedonaScalarUDF::new_stub(
-        "st_lineinterpolatepoint",
-        ArgMatcher::new(
-            vec![ArgMatcher::is_geometry(), ArgMatcher::is_numeric()],
-            WKB_GEOMETRY,
-        ),
-        Volatility::Immutable,
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use datafusion_expr::ScalarUDF;
-
-    use super::*;
-
-    #[test]
-    fn udf_metadata() {
-        let udf: ScalarUDF = st_line_interpolate_point_udf().into();
-        assert_eq!(udf.name(), "st_lineinterpolatepoint");
-
-        let udf: ScalarUDF = st_line_locate_point_udf().into();
-        assert_eq!(udf.name(), "st_linelocatepoint");
-    }
-}
diff --git a/rust/sedona-functions/src/register.rs 
b/rust/sedona-functions/src/register.rs
index b50079e7..7fdb1cb3 100644
--- a/rust/sedona-functions/src/register.rs
+++ b/rust/sedona-functions/src/register.rs
@@ -38,38 +38,15 @@ pub fn default_function_set() -> FunctionSet {
 
     register_scalar_udfs!(
         function_set,
-        crate::distance::st_distance_udf,
-        crate::distance::st_max_distance_udf,
-        crate::overlay::st_difference_udf,
-        crate::overlay::st_intersection_udf,
-        crate::overlay::st_sym_difference_udf,
-        crate::overlay::st_union_udf,
-        crate::predicates::st_contains_udf,
-        crate::predicates::st_covered_by_udf,
-        crate::predicates::st_covers_udf,
-        crate::predicates::st_disjoint_udf,
-        crate::predicates::st_equals_udf,
-        crate::predicates::st_intersects_udf,
-        crate::predicates::st_knn_udf,
-        crate::predicates::st_touches_udf,
-        crate::predicates::st_within_udf,
-        crate::referencing::st_line_interpolate_point_udf,
-        crate::referencing::st_line_locate_point_udf,
         crate::sd_format::sd_format_udf,
         crate::sd_order::sd_order_udf,
         crate::st_affine::st_affine_udf,
-        crate::st_area::st_area_udf,
         crate::st_asbinary::st_asbinary_udf,
         crate::st_asewkb::st_asewkb_udf,
-        crate::st_asgeojson::st_asgeojson_udf,
         crate::st_astext::st_astext_udf,
         crate::st_azimuth::st_azimuth_udf,
-        crate::st_buffer::st_buffer_udf,
-        crate::st_centroid::st_centroid_udf,
-        crate::st_concavehull::st_concavehull_udf,
         crate::st_dimension::st_dimension_udf,
         crate::st_dump::st_dump_udf,
-        crate::st_dwithin::st_dwithin_udf,
         crate::st_envelope::st_envelope_udf,
         crate::st_flipcoordinates::st_flipcoordinates_udf,
         crate::st_geometryn::st_geometryn_udf,
@@ -87,11 +64,9 @@ pub fn default_function_set() -> FunctionSet {
         crate::st_isclosed::st_isclosed_udf,
         crate::st_iscollection::st_iscollection_udf,
         crate::st_isempty::st_isempty_udf,
-        crate::st_length::st_length_udf,
-        crate::st_line_merge::st_line_merge_udf,
+        crate::st_knn::st_knn_udf,
         crate::st_makeline::st_makeline_udf,
         crate::st_numgeometries::st_numgeometries_udf,
-        crate::st_perimeter::st_perimeter_udf,
         crate::st_point::st_geogpoint_udf,
         crate::st_point::st_point_udf,
         crate::st_pointn::st_pointn_udf,
@@ -111,7 +86,6 @@ pub fn default_function_set() -> FunctionSet {
         crate::st_srid::st_srid_udf,
         crate::st_start_point::st_end_point_udf,
         crate::st_start_point::st_start_point_udf,
-        crate::st_transform::st_transform_udf,
         crate::st_translate::st_translate_udf,
         crate::st_force_dim::st_force2d_udf,
         crate::st_force_dim::st_force3d_udf,
@@ -137,29 +111,7 @@ pub fn default_function_set() -> FunctionSet {
         crate::st_analyze_agg::st_analyze_agg_udf,
         crate::st_collect_agg::st_collect_agg_udf,
         crate::st_envelope_agg::st_envelope_agg_udf,
-        crate::st_intersection_agg::st_intersection_agg_udf,
-        crate::st_polygonize_agg::st_polygonize_agg_udf,
-        crate::st_union_agg::st_union_agg_udf,
     );
 
     function_set
 }
-
-/// Functions whose implementations are registered independently
-///
-/// These functions are included in the default function set; however,
-/// it is useful to expose them individually for testing in crates that
-/// implement them.
-pub mod stubs {
-    pub use crate::overlay::*;
-    pub use crate::predicates::*;
-    pub use crate::referencing::*;
-    pub use crate::st_area::st_area_udf;
-    pub use crate::st_azimuth::st_azimuth_udf;
-    pub use crate::st_centroid::st_centroid_udf;
-    pub use crate::st_length::st_length_udf;
-    pub use crate::st_perimeter::st_perimeter_udf;
-    pub use crate::st_setsrid::st_set_crs_with_engine_udf;
-    pub use crate::st_setsrid::st_set_srid_with_engine_udf;
-    pub use crate::st_transform::st_transform_udf;
-}
diff --git a/rust/sedona-functions/src/st_analyze_agg.rs 
b/rust/sedona-functions/src/st_analyze_agg.rs
index 3c9016e2..fdd127d6 100644
--- a/rust/sedona-functions/src/st_analyze_agg.rs
+++ b/rust/sedona-functions/src/st_analyze_agg.rs
@@ -31,8 +31,7 @@ use datafusion_common::{
 use datafusion_expr::Volatility;
 use datafusion_expr::{Accumulator, ColumnarValue};
 use sedona_common::{sedona_internal_datafusion_err, sedona_internal_err};
-use sedona_expr::aggregate_udf::SedonaAccumulatorRef;
-use sedona_expr::aggregate_udf::SedonaAggregateUDF;
+use sedona_expr::aggregate_udf::{SedonaAccumulatorRef, SedonaAggregateUDF};
 use sedona_expr::item_crs::ItemCrsSedonaAccumulator;
 use sedona_expr::{aggregate_udf::SedonaAccumulator, statistics::GeoStatistics};
 use sedona_geometry::analyze::GeometrySummary;
@@ -43,7 +42,7 @@ use wkb::reader::Wkb;
 
 use crate::executor::WkbExecutor;
 
-/// ST_Analyze_Agg() aggregate UDF implementation
+/// ST_Analyze_Agg() aggregate UDF
 ///
 /// This function computes comprehensive statistics for a collection of 
geometries.
 /// It returns a struct containing various metrics such as count, min/max 
coordinates,
@@ -51,11 +50,14 @@ use crate::executor::WkbExecutor;
 pub fn st_analyze_agg_udf() -> SedonaAggregateUDF {
     SedonaAggregateUDF::new(
         "st_analyze_agg",
-        ItemCrsSedonaAccumulator::wrap_impl(STAnalyzeAgg {}),
+        ItemCrsSedonaAccumulator::wrap_impl(st_analyze_agg_impl()),
         Volatility::Immutable,
     )
 }
+
 /// ST_Analyze_Agg() implementation
+///
+/// This wrapper is exposed because it is used by the spatial join 
implementation.
 pub fn st_analyze_agg_impl() -> SedonaAccumulatorRef {
     Arc::new(STAnalyzeAgg {})
 }
@@ -486,8 +488,7 @@ mod test {
 
     #[rstest]
     fn basic_analyze_cases(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] 
sedona_type: SedonaType) {
-        let mut udaf = st_analyze_agg_udf();
-        udaf.add_kernel(st_analyze_agg_impl());
+        let udaf = st_analyze_agg_udf();
 
         let tester = AggregateUdfTester::new(udaf.into(), 
vec![sedona_type.clone()]);
 
@@ -529,8 +530,7 @@ mod test {
         #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY, 
WKB_GEOMETRY_ITEM_CRS.clone())]
         sedona_type: SedonaType,
     ) {
-        let mut udaf = st_analyze_agg_udf();
-        udaf.add_kernel(st_analyze_agg_impl());
+        let udaf = st_analyze_agg_udf();
 
         let tester = AggregateUdfTester::new(udaf.into(), 
vec![sedona_type.clone()]);
 
@@ -569,8 +569,7 @@ mod test {
 
     #[rstest]
     fn analyze_polygon(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: 
SedonaType) {
-        let mut udaf = st_analyze_agg_udf();
-        udaf.add_kernel(st_analyze_agg_impl());
+        let udaf = st_analyze_agg_udf();
 
         let tester = AggregateUdfTester::new(udaf.into(), 
vec![sedona_type.clone()]);
 
@@ -611,8 +610,7 @@ mod test {
     fn analyze_mixed_geometries(
         #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType,
     ) {
-        let mut udaf = st_analyze_agg_udf();
-        udaf.add_kernel(st_analyze_agg_impl());
+        let udaf = st_analyze_agg_udf();
 
         let tester = AggregateUdfTester::new(udaf.into(), 
vec![sedona_type.clone()]);
 
@@ -653,8 +651,7 @@ mod test {
 
     #[rstest]
     fn analyze_empty_input(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] 
sedona_type: SedonaType) {
-        let mut udaf = st_analyze_agg_udf();
-        udaf.add_kernel(st_analyze_agg_impl());
+        let udaf = st_analyze_agg_udf();
 
         let tester = AggregateUdfTester::new(udaf.into(), 
vec![sedona_type.clone()]);
 
diff --git a/rust/sedona-functions/src/st_area.rs 
b/rust/sedona-functions/src/st_area.rs
deleted file mode 100644
index 7d480f3d..00000000
--- a/rust/sedona-functions/src/st_area.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use arrow_schema::DataType;
-use datafusion_expr::Volatility;
-use sedona_expr::scalar_udf::SedonaScalarUDF;
-use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher};
-
-/// ST_Area() scalar UDF implementation
-///
-/// Stub function for area calculation.
-pub fn st_area_udf() -> SedonaScalarUDF {
-    SedonaScalarUDF::new_stub(
-        "st_area",
-        ArgMatcher::new(
-            vec![ArgMatcher::is_geometry_or_geography()],
-            SedonaType::Arrow(DataType::Float64),
-        ),
-        Volatility::Immutable,
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use datafusion_expr::ScalarUDF;
-
-    use super::*;
-
-    #[test]
-    fn udf_metadata() {
-        let udf: ScalarUDF = st_area_udf().into();
-        assert_eq!(udf.name(), "st_area");
-    }
-}
diff --git a/rust/sedona-functions/src/st_asgeojson.rs 
b/rust/sedona-functions/src/st_asgeojson.rs
deleted file mode 100644
index d34adba1..00000000
--- a/rust/sedona-functions/src/st_asgeojson.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use arrow_schema::DataType;
-use datafusion_expr::Volatility;
-use sedona_expr::scalar_udf::SedonaScalarUDF;
-use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher};
-
-/// ST_AsGeoJSON() scalar UDF implementation
-///
-/// Stub function for GeoJSON conversion.
-pub fn st_asgeojson_udf() -> SedonaScalarUDF {
-    SedonaScalarUDF::new_stub(
-        "st_asgeojson",
-        ArgMatcher::new(
-            vec![ArgMatcher::is_geometry_or_geography()],
-            SedonaType::Arrow(DataType::Utf8),
-        ),
-        Volatility::Immutable,
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use datafusion_expr::ScalarUDF;
-
-    use super::*;
-
-    #[test]
-    fn udf_metadata() {
-        let udf: ScalarUDF = st_asgeojson_udf().into();
-        assert_eq!(udf.name(), "st_asgeojson");
-    }
-}
diff --git a/rust/sedona-functions/src/st_buffer.rs 
b/rust/sedona-functions/src/st_buffer.rs
deleted file mode 100644
index 41a0c654..00000000
--- a/rust/sedona-functions/src/st_buffer.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use datafusion_expr::Volatility;
-use sedona_expr::scalar_udf::SedonaScalarUDF;
-use sedona_schema::{datatypes::WKB_GEOMETRY, matchers::ArgMatcher};
-
-/// ST_Buffer() scalar UDF stub
-pub fn st_buffer_udf() -> SedonaScalarUDF {
-    SedonaScalarUDF::new_stub(
-        "st_buffer",
-        ArgMatcher::new(
-            vec![
-                ArgMatcher::is_geometry_or_geography(),
-                ArgMatcher::is_numeric(),
-            ],
-            WKB_GEOMETRY,
-        ),
-        Volatility::Immutable,
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use datafusion_expr::ScalarUDF;
-
-    use super::*;
-
-    #[test]
-    fn udf_metadata() {
-        let udf: ScalarUDF = st_buffer_udf().into();
-        assert_eq!(udf.name(), "st_buffer");
-    }
-}
diff --git a/rust/sedona-functions/src/st_centroid.rs 
b/rust/sedona-functions/src/st_centroid.rs
deleted file mode 100644
index 0e1ac329..00000000
--- a/rust/sedona-functions/src/st_centroid.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use datafusion_expr::Volatility;
-use sedona_expr::scalar_udf::SedonaScalarUDF;
-use sedona_schema::{datatypes::WKB_GEOMETRY, matchers::ArgMatcher};
-
-/// ST_Centroid() scalar UDF stub
-///
-/// Stub function for centroid calculation.
-pub fn st_centroid_udf() -> SedonaScalarUDF {
-    SedonaScalarUDF::new_stub(
-        "st_centroid",
-        ArgMatcher::new(vec![ArgMatcher::is_geometry()], WKB_GEOMETRY),
-        Volatility::Immutable,
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use datafusion_expr::ScalarUDF;
-
-    use super::*;
-
-    #[test]
-    fn udf_metadata() {
-        let udf: ScalarUDF = st_centroid_udf().into();
-        assert_eq!(udf.name(), "st_centroid");
-    }
-}
diff --git a/rust/sedona-functions/src/st_concavehull.rs 
b/rust/sedona-functions/src/st_concavehull.rs
deleted file mode 100644
index 37a2ef6a..00000000
--- a/rust/sedona-functions/src/st_concavehull.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use datafusion_expr::Volatility;
-use sedona_expr::scalar_udf::SedonaScalarUDF;
-use sedona_schema::{datatypes::WKB_GEOMETRY, matchers::ArgMatcher};
-
-/// ST_ConcaveHull stub function
-///
-/// Stub function for concave hull calculation
-pub fn st_concavehull_udf() -> SedonaScalarUDF {
-    SedonaScalarUDF::new_stub(
-        "st_concavehull",
-        ArgMatcher::new(
-            vec![ArgMatcher::is_geometry(), ArgMatcher::is_numeric()],
-            WKB_GEOMETRY,
-        ),
-        Volatility::Immutable,
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use datafusion_expr::ScalarUDF;
-
-    use super::*;
-
-    #[test]
-    fn udf_metadata() {
-        let udf: ScalarUDF = st_concavehull_udf().into();
-        assert_eq!(udf.name(), "st_concavehull");
-    }
-}
diff --git a/rust/sedona-functions/src/st_intersection_agg.rs 
b/rust/sedona-functions/src/st_intersection_agg.rs
deleted file mode 100644
index 6c8d8419..00000000
--- a/rust/sedona-functions/src/st_intersection_agg.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use std::vec;
-
-use datafusion_expr::Volatility;
-use sedona_expr::aggregate_udf::SedonaAggregateUDF;
-use sedona_schema::{
-    datatypes::{Edges, SedonaType},
-    matchers::ArgMatcher,
-};
-
-/// ST_Intersection_Agg() aggregate UDF implementation
-///
-/// An implementation of intersection calculation.
-pub fn st_intersection_agg_udf() -> SedonaAggregateUDF {
-    SedonaAggregateUDF::new_stub(
-        "st_intersection_agg",
-        ArgMatcher::new(
-            vec![ArgMatcher::is_geometry_or_geography()],
-            SedonaType::Wkb(Edges::Planar, None),
-        ),
-        Volatility::Immutable,
-    )
-}
-
-#[cfg(test)]
-mod test {
-    use datafusion_expr::AggregateUDF;
-
-    use super::*;
-
-    #[test]
-    fn udf_metadata() {
-        let udf: AggregateUDF = st_intersection_agg_udf().into();
-        assert_eq!(udf.name(), "st_intersection_agg");
-    }
-}
diff --git a/rust/sedona-functions/src/st_isempty.rs 
b/rust/sedona-functions/src/st_isempty.rs
index 0d6041c6..6ca4aff5 100644
--- a/rust/sedona-functions/src/st_isempty.rs
+++ b/rust/sedona-functions/src/st_isempty.rs
@@ -72,10 +72,6 @@ impl SedonaScalarKernel for STIsEmpty {
     }
 }
 
-pub fn is_wkb_empty(item: &Wkb) -> Result<bool> {
-    invoke_scalar(item)
-}
-
 fn invoke_scalar(item: &Wkb) -> Result<bool> {
     is_geometry_empty(item).map_err(|e| {
         datafusion_common::error::DataFusionError::Execution(format!(
diff --git a/rust/sedona-functions/src/st_dwithin.rs 
b/rust/sedona-functions/src/st_knn.rs
similarity index 62%
rename from rust/sedona-functions/src/st_dwithin.rs
rename to rust/sedona-functions/src/st_knn.rs
index ab352629..6ca3563b 100644
--- a/rust/sedona-functions/src/st_dwithin.rs
+++ b/rust/sedona-functions/src/st_knn.rs
@@ -14,25 +14,33 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
+
+use std::sync::Arc;
+
 use arrow_schema::DataType;
-use datafusion_expr::Volatility;
-use sedona_expr::scalar_udf::SedonaScalarUDF;
+use datafusion_common::plan_err;
+use sedona_expr::scalar_udf::{SedonaScalarUDF, SimpleSedonaScalarKernel};
 use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher};
 
-/// ST_DWithin() scalar UDF stub
-pub fn st_dwithin_udf() -> SedonaScalarUDF {
-    SedonaScalarUDF::new_stub(
-        "st_dwithin",
+/// ST_KNN() scalar UDF stub
+///
+/// This is a stub function that defines the signature and documentation for 
ST_KNN
+/// but does not contain an actual implementation. The real k-nearest 
neighbors logic
+/// is handled by the spatial join execution engine.
+pub fn st_knn_udf() -> SedonaScalarUDF {
+    let stub_impl = SimpleSedonaScalarKernel::new_ref(
         ArgMatcher::new(
             vec![
                 ArgMatcher::is_geometry_or_geography(),
                 ArgMatcher::is_geometry_or_geography(),
                 ArgMatcher::is_numeric(),
+                ArgMatcher::is_boolean(),
             ],
             SedonaType::Arrow(DataType::Boolean),
         ),
-        Volatility::Immutable,
-    )
+        Arc::new(|_arg_types, _args| plan_err!("Can't execute ST_KNN() outside 
a spatial join")),
+    );
+    SedonaScalarUDF::from_impl("st_knn", stub_impl)
 }
 
 #[cfg(test)]
@@ -43,7 +51,7 @@ mod tests {
 
     #[test]
     fn udf_metadata() {
-        let udf: ScalarUDF = st_dwithin_udf().into();
-        assert_eq!(udf.name(), "st_dwithin");
+        let udf: ScalarUDF = st_knn_udf().into();
+        assert_eq!(udf.name(), "st_knn");
     }
 }
diff --git a/rust/sedona-functions/src/st_length.rs 
b/rust/sedona-functions/src/st_length.rs
deleted file mode 100644
index b68a1be8..00000000
--- a/rust/sedona-functions/src/st_length.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use arrow_schema::DataType;
-use datafusion_expr::Volatility;
-use sedona_expr::scalar_udf::SedonaScalarUDF;
-use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher};
-
-/// ST_Length() scalar UDF implementation
-///
-/// Stub function for length calculation.
-pub fn st_length_udf() -> SedonaScalarUDF {
-    SedonaScalarUDF::new_stub(
-        "st_length",
-        ArgMatcher::new(
-            vec![ArgMatcher::is_geometry_or_geography()],
-            SedonaType::Arrow(DataType::Float64),
-        ),
-        Volatility::Immutable,
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use datafusion_expr::ScalarUDF;
-
-    use super::*;
-
-    #[test]
-    fn udf_metadata() {
-        let udf: ScalarUDF = st_length_udf().into();
-        assert_eq!(udf.name(), "st_length");
-    }
-}
diff --git a/rust/sedona-functions/src/st_line_merge.rs 
b/rust/sedona-functions/src/st_line_merge.rs
deleted file mode 100644
index 0069903b..00000000
--- a/rust/sedona-functions/src/st_line_merge.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use datafusion_expr::Volatility;
-use sedona_expr::scalar_udf::SedonaScalarUDF;
-use sedona_schema::{datatypes::WKB_GEOMETRY, matchers::ArgMatcher};
-
-/// ST_LineMerge() scalar UDF implementation
-///
-/// Stub function for line merging.
-pub fn st_line_merge_udf() -> SedonaScalarUDF {
-    SedonaScalarUDF::new_stub(
-        "st_linemerge",
-        ArgMatcher::new(vec![ArgMatcher::is_geometry()], WKB_GEOMETRY),
-        Volatility::Immutable,
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use datafusion_expr::ScalarUDF;
-
-    use super::*;
-
-    #[test]
-    fn udf_metadata() {
-        let udf: ScalarUDF = st_line_merge_udf().into();
-        assert_eq!(udf.name(), "st_linemerge");
-    }
-}
diff --git a/rust/sedona-functions/src/st_perimeter.rs 
b/rust/sedona-functions/src/st_perimeter.rs
deleted file mode 100644
index 596518ae..00000000
--- a/rust/sedona-functions/src/st_perimeter.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use arrow_schema::DataType;
-use datafusion_expr::Volatility;
-use sedona_expr::scalar_udf::SedonaScalarUDF;
-use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher};
-
-/// ST_Perimeter() scalar UDF implementation
-///
-/// Stub function for perimeter calculation.
-pub fn st_perimeter_udf() -> SedonaScalarUDF {
-    SedonaScalarUDF::new_stub(
-        "st_perimeter",
-        ArgMatcher::new(
-            vec![
-                ArgMatcher::is_geometry_or_geography(),
-                ArgMatcher::optional(ArgMatcher::is_boolean()),
-                ArgMatcher::optional(ArgMatcher::is_boolean()),
-            ],
-            SedonaType::Arrow(DataType::Float64),
-        ),
-        Volatility::Immutable,
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use datafusion_expr::ScalarUDF;
-
-    use super::*;
-
-    #[test]
-    fn udf_metadata() {
-        let udf: ScalarUDF = st_perimeter_udf().into();
-        assert_eq!(udf.name(), "st_perimeter");
-    }
-}
diff --git a/rust/sedona-functions/src/st_polygonize_agg.rs 
b/rust/sedona-functions/src/st_polygonize_agg.rs
deleted file mode 100644
index c1f01033..00000000
--- a/rust/sedona-functions/src/st_polygonize_agg.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use std::vec;
-
-use datafusion_expr::Volatility;
-use sedona_expr::aggregate_udf::SedonaAggregateUDF;
-use sedona_schema::{datatypes::WKB_GEOMETRY, matchers::ArgMatcher};
-
-/// ST_Polygonize_Agg() aggregate UDF implementation
-///
-/// Creates polygons from a set of linework that forms closed rings.
-pub fn st_polygonize_agg_udf() -> SedonaAggregateUDF {
-    SedonaAggregateUDF::new_stub(
-        "st_polygonize_agg",
-        ArgMatcher::new(vec![ArgMatcher::is_geometry()], WKB_GEOMETRY),
-        Volatility::Immutable,
-    )
-}
-
-#[cfg(test)]
-mod test {
-    use datafusion_expr::AggregateUDF;
-
-    use super::*;
-
-    #[test]
-    fn udf_metadata() {
-        let udf: AggregateUDF = st_polygonize_agg_udf().into();
-        assert_eq!(udf.name(), "st_polygonize_agg");
-    }
-}
diff --git a/rust/sedona-functions/src/st_transform.rs 
b/rust/sedona-functions/src/st_transform.rs
deleted file mode 100644
index 372358d1..00000000
--- a/rust/sedona-functions/src/st_transform.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use std::vec;
-
-use datafusion_expr::Volatility;
-use sedona_expr::scalar_udf::SedonaScalarUDF;
-use sedona_schema::{datatypes::WKB_GEOMETRY, matchers::ArgMatcher};
-
-/// St_Transform() UDF implementation
-///
-/// An implementation of intersection calculation.
-pub fn st_transform_udf() -> SedonaScalarUDF {
-    SedonaScalarUDF::new_stub(
-        "st_transform",
-        ArgMatcher::new(
-            vec![
-                ArgMatcher::is_geometry(),
-                ArgMatcher::or(vec![ArgMatcher::is_string(), 
ArgMatcher::is_numeric()]),
-                ArgMatcher::optional(ArgMatcher::or(vec![
-                    ArgMatcher::is_string(),
-                    ArgMatcher::is_numeric(),
-                ])),
-                ArgMatcher::optional(ArgMatcher::is_boolean()),
-            ],
-            WKB_GEOMETRY,
-        ),
-        Volatility::Immutable,
-    )
-}
-
-#[cfg(test)]
-mod test {
-    use super::*;
-    use datafusion_expr::ScalarUDFImpl;
-
-    #[test]
-    fn udf_metadata() {
-        let udf: SedonaScalarUDF = st_transform_udf();
-        assert_eq!(udf.name(), "st_transform");
-    }
-}
diff --git a/rust/sedona-functions/src/st_union_agg.rs 
b/rust/sedona-functions/src/st_union_agg.rs
deleted file mode 100644
index 6cb994f7..00000000
--- a/rust/sedona-functions/src/st_union_agg.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use std::vec;
-
-use datafusion_expr::Volatility;
-use sedona_expr::aggregate_udf::SedonaAggregateUDF;
-use sedona_schema::{
-    datatypes::{Edges, SedonaType},
-    matchers::ArgMatcher,
-};
-
-/// ST_Union_Agg() aggregate UDF implementation
-///
-/// An implementation of union calculation.
-pub fn st_union_agg_udf() -> SedonaAggregateUDF {
-    SedonaAggregateUDF::new_stub(
-        "st_union_agg",
-        ArgMatcher::new(
-            vec![ArgMatcher::is_geometry_or_geography()],
-            SedonaType::Wkb(Edges::Planar, None),
-        ),
-        Volatility::Immutable,
-    )
-}
-
-#[cfg(test)]
-mod test {
-    use datafusion_expr::AggregateUDF;
-
-    use super::*;
-
-    #[test]
-    fn udf_metadata() {
-        let udf: AggregateUDF = st_union_agg_udf().into();
-        assert_eq!(udf.name(), "st_union_agg");
-    }
-}
diff --git a/rust/sedona-geo/src/st_area.rs b/rust/sedona-geo/src/st_area.rs
index f60599a7..2b2b7d4c 100644
--- a/rust/sedona-geo/src/st_area.rs
+++ b/rust/sedona-geo/src/st_area.rs
@@ -78,7 +78,7 @@ mod tests {
     use arrow_array::{create_array, ArrayRef};
     use datafusion_common::scalar::ScalarValue;
     use rstest::rstest;
-    use sedona_functions::register::stubs::st_area_udf;
+    use sedona_expr::scalar_udf::SedonaScalarUDF;
     use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, 
WKB_VIEW_GEOMETRY};
     use sedona_testing::testers::ScalarUdfTester;
 
@@ -89,8 +89,7 @@ mod tests {
         #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY, 
WKB_GEOMETRY_ITEM_CRS.clone())]
         sedona_type: SedonaType,
     ) {
-        let mut udf = st_area_udf();
-        udf.add_kernels(st_area_impl());
+        let udf = SedonaScalarUDF::from_impl("st_area", st_area_impl());
         let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type]);
 
         assert_eq!(
diff --git a/rust/sedona-geo/src/st_centroid.rs 
b/rust/sedona-geo/src/st_centroid.rs
index 9f5a6a7c..bd97f691 100644
--- a/rust/sedona-geo/src/st_centroid.rs
+++ b/rust/sedona-geo/src/st_centroid.rs
@@ -107,7 +107,7 @@ fn invoke_scalar(wkb: &Wkb) -> Result<Vec<u8>> {
 #[cfg(test)]
 mod tests {
     use rstest::rstest;
-    use sedona_functions::register::stubs::st_centroid_udf;
+    use sedona_expr::scalar_udf::SedonaScalarUDF;
     use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, 
WKB_VIEW_GEOMETRY};
     use sedona_testing::compare::assert_array_equal;
     use sedona_testing::create::create_array;
@@ -117,8 +117,7 @@ mod tests {
 
     #[rstest]
     fn udf(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType) 
{
-        let mut udf = st_centroid_udf();
-        udf.add_kernels(st_centroid_impl());
+        let udf = SedonaScalarUDF::from_impl("st_centroid", 
st_centroid_impl());
         let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type]);
 
         assert_eq!(tester.return_type().unwrap(), WKB_GEOMETRY);
@@ -147,8 +146,7 @@ mod tests {
 
     #[rstest]
     fn udf_invoke_item_crs(#[values(WKB_GEOMETRY_ITEM_CRS.clone())] 
sedona_type: SedonaType) {
-        let mut udf = st_centroid_udf();
-        udf.add_kernels(st_centroid_impl());
+        let udf = SedonaScalarUDF::from_impl("st_centroid", 
st_centroid_impl());
         let tester = ScalarUdfTester::new(udf.into(), 
vec![sedona_type.clone()]);
         tester.assert_return_type(sedona_type);
 
diff --git a/rust/sedona-geo/src/st_intersection_agg.rs 
b/rust/sedona-geo/src/st_intersection_agg.rs
index 1ef1958a..c8c4cb7f 100644
--- a/rust/sedona-geo/src/st_intersection_agg.rs
+++ b/rust/sedona-geo/src/st_intersection_agg.rs
@@ -222,7 +222,7 @@ impl Accumulator for IntersectionAccumulator {
 mod test {
     use super::*;
     use rstest::rstest;
-    use sedona_functions::st_intersection_agg::st_intersection_agg_udf;
+    use sedona_expr::aggregate_udf::SedonaAggregateUDF;
     use sedona_schema::datatypes::{WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY};
     use sedona_testing::{
         compare::{assert_scalar_equal, 
assert_scalar_equal_wkb_geometry_topologically},
@@ -232,8 +232,7 @@ mod test {
 
     #[rstest]
     fn polygon_polygon_cases(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] 
sedona_type: SedonaType) {
-        let mut udaf = st_intersection_agg_udf();
-        udaf.add_kernel(st_intersection_agg_impl());
+        let udaf = SedonaAggregateUDF::from_impl("st_intersection_agg", 
st_intersection_agg_impl());
 
         let tester = AggregateUdfTester::new(udaf.into(), 
vec![sedona_type.clone()]);
         assert_eq!(tester.return_type().unwrap(), WKB_GEOMETRY);
@@ -297,8 +296,7 @@ mod test {
     fn polygon_multipolygon_cases(
         #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType,
     ) {
-        let mut udaf = st_intersection_agg_udf();
-        udaf.add_kernel(st_intersection_agg_impl());
+        let udaf = SedonaAggregateUDF::from_impl("st_union", 
st_intersection_agg_impl());
 
         let tester = AggregateUdfTester::new(udaf.into(), 
vec![sedona_type.clone()]);
 
@@ -345,8 +343,7 @@ mod test {
     fn multipolygon_multipolygon_cases(
         #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType,
     ) {
-        let mut udaf = st_intersection_agg_udf();
-        udaf.add_kernel(st_intersection_agg_impl());
+        let udaf = SedonaAggregateUDF::from_impl("st_union", 
st_intersection_agg_impl());
 
         let tester = AggregateUdfTester::new(udaf.into(), 
vec![sedona_type.clone()]);
 
@@ -400,8 +397,7 @@ mod test {
     fn udf_invoke_item_crs() {
         let sedona_type = WKB_GEOMETRY_ITEM_CRS.clone();
 
-        let mut udaf = st_intersection_agg_udf();
-        udaf.add_kernel(st_intersection_agg_impl());
+        let udaf = SedonaAggregateUDF::from_impl("st_union", 
st_intersection_agg_impl());
         let tester = AggregateUdfTester::new(udaf.into(), 
vec![sedona_type.clone()]);
         assert_eq!(tester.return_type().unwrap(), sedona_type.clone());
 
diff --git a/rust/sedona-geo/src/st_intersects.rs 
b/rust/sedona-geo/src/st_intersects.rs
index 405ebce3..8a0db4be 100644
--- a/rust/sedona-geo/src/st_intersects.rs
+++ b/rust/sedona-geo/src/st_intersects.rs
@@ -77,7 +77,7 @@ fn invoke_scalar(item_a: &Wkb, geom_b: &Wkb) -> Result<bool> {
 mod tests {
     use arrow_array::{create_array, ArrayRef};
     use datafusion_common::scalar::ScalarValue;
-    use sedona_functions::register::stubs::st_intersects_udf;
+    use sedona_expr::scalar_udf::SedonaScalarUDF;
     use sedona_schema::datatypes::WKB_GEOMETRY;
     use sedona_testing::{
         create::{create_array, create_scalar},
@@ -88,8 +88,7 @@ mod tests {
 
     #[test]
     fn scalar_scalar() {
-        let mut udf = st_intersects_udf();
-        udf.add_kernels(st_intersects_impl());
+        let udf = SedonaScalarUDF::from_impl("st_intersects", 
st_intersects_impl());
         let tester = ScalarUdfTester::new(udf.into(), vec![WKB_GEOMETRY, 
WKB_GEOMETRY]);
 
         let point = create_scalar(Some("POINT (0.25 0.25)"), &WKB_GEOMETRY);
@@ -149,8 +148,7 @@ mod tests {
 
     #[test]
     fn scalar_array() {
-        let mut udf = st_intersects_udf();
-        udf.add_kernels(st_intersects_impl());
+        let udf = SedonaScalarUDF::from_impl("st_intersects", 
st_intersects_impl());
         let tester = ScalarUdfTester::new(udf.into(), vec![WKB_GEOMETRY, 
WKB_GEOMETRY]);
 
         let point_array = create_array(
@@ -179,8 +177,7 @@ mod tests {
 
     #[test]
     fn array_array() {
-        let mut udf = st_intersects_udf();
-        udf.add_kernels(st_intersects_impl());
+        let udf = SedonaScalarUDF::from_impl("st_intersects", 
st_intersects_impl());
         let tester = ScalarUdfTester::new(udf.into(), vec![WKB_GEOMETRY, 
WKB_GEOMETRY]);
 
         let point_array = create_array(
diff --git a/rust/sedona-geo/src/st_length.rs b/rust/sedona-geo/src/st_length.rs
index eb4eff65..b17befe8 100644
--- a/rust/sedona-geo/src/st_length.rs
+++ b/rust/sedona-geo/src/st_length.rs
@@ -79,7 +79,7 @@ mod tests {
     use arrow_array::{create_array, ArrayRef};
     use datafusion_common::scalar::ScalarValue;
     use rstest::rstest;
-    use sedona_functions::register::stubs::st_length_udf;
+    use sedona_expr::scalar_udf::SedonaScalarUDF;
     use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, 
WKB_VIEW_GEOMETRY};
     use sedona_testing::testers::ScalarUdfTester;
 
@@ -90,8 +90,7 @@ mod tests {
         #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY, 
WKB_GEOMETRY_ITEM_CRS.clone())]
         sedona_type: SedonaType,
     ) {
-        let mut udf = st_length_udf();
-        udf.add_kernels(st_length_impl());
+        let udf = SedonaScalarUDF::from_impl("st_length", st_length_impl());
         let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type]);
 
         assert_eq!(
diff --git a/rust/sedona-geo/src/st_line_interpolate_point.rs 
b/rust/sedona-geo/src/st_line_interpolate_point.rs
index 473cb05d..1a66280c 100644
--- a/rust/sedona-geo/src/st_line_interpolate_point.rs
+++ b/rust/sedona-geo/src/st_line_interpolate_point.rs
@@ -108,7 +108,6 @@ fn invoke_scalar(geom: &geo_types::Geometry<f64>, ratio: 
f64) -> Result<(f64, f6
 mod tests {
     use rstest::rstest;
     use sedona_expr::scalar_udf::SedonaScalarUDF;
-    use sedona_functions::register::stubs::st_area_udf;
     use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, 
WKB_VIEW_GEOMETRY};
     use sedona_testing::{compare::assert_scalar_equal_wkb_geometry, 
testers::ScalarUdfTester};
 
@@ -116,8 +115,8 @@ mod tests {
 
     #[rstest]
     fn udf(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType) 
{
-        let mut udf = st_area_udf();
-        udf.add_kernels(st_line_interpolate_point_impl());
+        let udf =
+            SedonaScalarUDF::from_impl("st_lineinterpolatepoint", 
st_line_interpolate_point_impl());
         let tester = ScalarUdfTester::new(
             udf.into(),
             vec![sedona_type, SedonaType::Arrow(DataType::Float64)],
diff --git a/rust/sedona-geo/src/st_perimeter.rs 
b/rust/sedona-geo/src/st_perimeter.rs
index bdce596d..c5c14cd8 100644
--- a/rust/sedona-geo/src/st_perimeter.rs
+++ b/rust/sedona-geo/src/st_perimeter.rs
@@ -79,7 +79,7 @@ mod tests {
     use arrow_array::{create_array, ArrayRef};
     use datafusion_common::scalar::ScalarValue;
     use rstest::rstest;
-    use sedona_functions::register::stubs::st_perimeter_udf;
+    use sedona_expr::scalar_udf::SedonaScalarUDF;
     use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, 
WKB_VIEW_GEOMETRY};
     use sedona_testing::testers::ScalarUdfTester;
 
@@ -90,8 +90,7 @@ mod tests {
         #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY, 
WKB_GEOMETRY_ITEM_CRS.clone())]
         sedona_type: SedonaType,
     ) {
-        let mut udf = st_perimeter_udf();
-        udf.add_kernels(st_perimeter_impl());
+        let udf = SedonaScalarUDF::from_impl("st_perimeter", 
st_perimeter_impl());
         let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type]);
 
         assert_eq!(
@@ -131,8 +130,7 @@ mod tests {
 
     #[test]
     fn test_polygon_with_hole() {
-        let mut udf = st_perimeter_udf();
-        udf.add_kernels(st_perimeter_impl());
+        let udf = SedonaScalarUDF::from_impl("st_perimeter", 
st_perimeter_impl());
         let tester = ScalarUdfTester::new(udf.into(), vec![WKB_GEOMETRY]);
 
         // Polygon with a hole: outer ring 40, inner ring 24
diff --git a/rust/sedona-geo/src/st_union_agg.rs 
b/rust/sedona-geo/src/st_union_agg.rs
index e9d7e003..a091be8c 100644
--- a/rust/sedona-geo/src/st_union_agg.rs
+++ b/rust/sedona-geo/src/st_union_agg.rs
@@ -216,7 +216,7 @@ impl Accumulator for UnionAccumulator {
 mod test {
     use super::*;
     use rstest::rstest;
-    use sedona_functions::st_union_agg::st_union_agg_udf;
+    use sedona_expr::aggregate_udf::SedonaAggregateUDF;
     use sedona_schema::datatypes::{WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY};
     use sedona_testing::{
         compare::{assert_scalar_equal, 
assert_scalar_equal_wkb_geometry_topologically},
@@ -226,8 +226,7 @@ mod test {
 
     #[rstest]
     fn polygon_polygon_cases(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] 
sedona_type: SedonaType) {
-        let mut udaf = st_union_agg_udf();
-        udaf.add_kernel(st_union_agg_impl());
+        let udaf = SedonaAggregateUDF::from_impl("st_union_agg", 
st_union_agg_impl());
 
         let tester = AggregateUdfTester::new(udaf.into(), 
vec![sedona_type.clone()]);
         assert_eq!(tester.return_type().unwrap(), WKB_GEOMETRY);
@@ -289,8 +288,7 @@ mod test {
     fn polygon_multipolygon_cases(
         #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType,
     ) {
-        let mut udaf = st_union_agg_udf();
-        udaf.add_kernel(st_union_agg_impl());
+        let udaf = SedonaAggregateUDF::from_impl("st_union", 
st_union_agg_impl());
 
         let tester = AggregateUdfTester::new(udaf.into(), 
vec![sedona_type.clone()]);
 
@@ -337,8 +335,7 @@ mod test {
     fn multipolygon_multipolygon_cases(
         #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType,
     ) {
-        let mut udaf = st_union_agg_udf();
-        udaf.add_kernel(st_union_agg_impl());
+        let udaf = SedonaAggregateUDF::from_impl("st_union", 
st_union_agg_impl());
 
         let tester = AggregateUdfTester::new(udaf.into(), 
vec![sedona_type.clone()]);
 
@@ -385,8 +382,7 @@ mod test {
     #[rstest]
     fn udf_invoke_item_crs() {
         let sedona_type = WKB_GEOMETRY_ITEM_CRS.clone();
-        let mut udaf = st_union_agg_udf();
-        udaf.add_kernel(st_union_agg_impl());
+        let udaf = SedonaAggregateUDF::from_impl("st_union", 
st_union_agg_impl());
         let tester = AggregateUdfTester::new(udaf.into(), 
vec![sedona_type.clone()]);
         assert_eq!(tester.return_type().unwrap(), sedona_type.clone());
 
diff --git a/rust/sedona-spatial-join/tests/spatial_join_integration.rs 
b/rust/sedona-spatial-join/tests/spatial_join_integration.rs
index b0c8f5e0..00047255 100644
--- a/rust/sedona-spatial-join/tests/spatial_join_integration.rs
+++ b/rust/sedona-spatial-join/tests/spatial_join_integration.rs
@@ -35,9 +35,13 @@ use geo::{Distance, Euclidean};
 use geo_types::{Coord, Rect};
 use rstest::rstest;
 use sedona_common::SedonaOptions;
+use sedona_expr::scalar_udf::{SedonaScalarUDF, SimpleSedonaScalarKernel};
 use sedona_geo::to_geo::GeoTypesExecutor;
 use sedona_geometry::types::GeometryTypeId;
-use sedona_schema::datatypes::{SedonaType, WKB_GEOGRAPHY, WKB_GEOMETRY};
+use sedona_schema::{
+    datatypes::{SedonaType, WKB_GEOGRAPHY, WKB_GEOMETRY},
+    matchers::ArgMatcher,
+};
 use sedona_spatial_join::{
     register_planner, spatial_predicate::RelationPredicate, SpatialJoinExec, 
SpatialPredicate,
 };
@@ -514,6 +518,16 @@ async fn test_geography_join_is_not_optimized() -> 
Result<()> {
     let options = SpatialJoinOptions::default();
     let ctx = setup_context(Some(options), 10)?;
 
+    let stub_impl = SimpleSedonaScalarKernel::new_ref(
+        ArgMatcher::new(
+            vec![ArgMatcher::is_geography(), ArgMatcher::is_geography()],
+            SedonaType::Arrow(DataType::Boolean),
+        ),
+        Arc::new(|_arg_types, _args| unreachable!("Should not be executed")),
+    );
+    let st_intersects_udf = SedonaScalarUDF::from_impl("st_intersects", 
stub_impl);
+    ctx.register_udf(st_intersects_udf.into());
+
     // Prepare geography tables
     let ((left_schema, left_partitions), (right_schema, right_partitions)) =
         create_test_data_with_size_range((0.1, 10.0), WKB_GEOGRAPHY)?;

Reply via email to