diff --git a/c/sedona-geos/src/register.rs b/c/sedona-geos/src/register.rs index 82553bc29..39f80676d 100644 --- a/c/sedona-geos/src/register.rs +++ b/c/sedona-geos/src/register.rs @@ -15,97 +15,77 @@ // specific language governing permissions and limitations // under the License. use sedona_expr::aggregate_udf::SedonaAccumulatorRef; -use sedona_expr::scalar_udf::ScalarKernelRef; +use sedona_expr::scalar_udf::{IntoScalarKernelRefs, ScalarKernelRef}; -use crate::{ - distance::st_distance_impl, - st_area::st_area_impl, - st_boundary::st_boundary_impl, - st_buffer::{st_buffer_impl, st_buffer_style_impl}, - st_centroid::st_centroid_impl, - st_concavehull::{st_concave_hull_allow_holes_impl, st_concave_hull_impl}, - st_convexhull::st_convex_hull_impl, - st_dwithin::st_dwithin_impl, - st_isring::st_is_ring_impl, - st_issimple::st_is_simple_impl, - st_isvalid::st_is_valid_impl, - st_isvalidreason::st_is_valid_reason_impl, - st_length::st_length_impl, - st_line_merge::st_line_merge_impl, - st_makevalid::st_make_valid_impl, - st_minimumclearance::st_minimum_clearance_impl, - st_minimumclearance_line::st_minimum_clearance_line_impl, - st_nrings::st_nrings_impl, - st_numinteriorrings::st_num_interior_rings_impl, - st_numpoints::st_num_points_impl, - st_perimeter::st_perimeter_impl, - st_polygonize::st_polygonize_impl, - st_polygonize_agg::st_polygonize_agg_impl, - st_simplify::st_simplify_impl, - st_simplifypreservetopology::st_simplify_preserve_topology_impl, - st_snap::st_snap_impl, - st_unaryunion::st_unary_union_impl, -}; - -use crate::binary_predicates::{ - st_contains_impl, st_covered_by_impl, st_covers_impl, st_crosses_impl, st_disjoint_impl, - st_equals_impl, st_intersects_impl, st_overlaps_impl, st_touches_impl, st_within_impl, -}; +macro_rules! define_scalar_kernels { + ($($name:expr => $impl:expr),* $(,)?) => { + vec![ + $( + ($name, $impl().into_scalar_kernel_refs()), + )* + ] + }; +} -use crate::overlay::{ - st_difference_impl, st_intersection_impl, st_sym_difference_impl, st_union_impl, -}; +macro_rules! define_aggregate_kernels { + ($($name:expr => $impl:expr),* $(,)?) => { + vec![ + $( + ($name, $impl()), + )* + ] + }; +} -pub fn scalar_kernels() -> Vec<(&'static str, ScalarKernelRef)> { - vec![ - ("st_area", st_area_impl()), - ("st_boundary", st_boundary_impl()), - ("st_buffer", st_buffer_impl()), - ("st_buffer", st_buffer_style_impl()), - ("st_centroid", st_centroid_impl()), - ("st_concavehull", st_concave_hull_allow_holes_impl()), - ("st_concavehull", st_concave_hull_impl()), - ("st_contains", st_contains_impl()), - ("st_convexhull", st_convex_hull_impl()), - ("st_coveredby", st_covered_by_impl()), - ("st_covers", st_covers_impl()), - ("st_crosses", st_crosses_impl()), - ("st_difference", st_difference_impl()), - ("st_disjoint", st_disjoint_impl()), - ("st_distance", st_distance_impl()), - ("st_dwithin", st_dwithin_impl()), - ("st_equals", st_equals_impl()), - ("st_intersection", st_intersection_impl()), - ("st_intersects", st_intersects_impl()), - ("st_isring", st_is_ring_impl()), - ("st_issimple", st_is_simple_impl()), - ("st_isvalid", st_is_valid_impl()), - ("st_isvalidreason", st_is_valid_reason_impl()), - ("st_length", st_length_impl()), - ("st_linemerge", st_line_merge_impl()), - ("st_numinteriorrings", st_num_interior_rings_impl()), - ("st_numpoints", st_num_points_impl()), - ("st_nrings", st_nrings_impl()), - ("st_makevalid", st_make_valid_impl()), - ("st_minimumclearance", st_minimum_clearance_impl()), - ("st_minimumclearanceline", st_minimum_clearance_line_impl()), - ("st_overlaps", st_overlaps_impl()), - ("st_perimeter", st_perimeter_impl()), - ("st_polygonize", st_polygonize_impl()), - ("st_simplify", st_simplify_impl()), - ( - "st_simplifypreservetopology", - st_simplify_preserve_topology_impl(), - ), - ("st_snap", st_snap_impl()), - ("st_symdifference", st_sym_difference_impl()), - ("st_touches", st_touches_impl()), - ("st_unaryunion", st_unary_union_impl()), - ("st_union", st_union_impl()), - ("st_within", st_within_impl()), - ] +pub fn scalar_kernels() -> Vec<(&'static str, Vec)> { + define_scalar_kernels!( + "st_area" => crate::st_area::st_area_impl, + "st_boundary" => crate::st_boundary::st_boundary_impl, + "st_buffer" => crate::st_buffer::st_buffer_impl, + "st_buffer" => crate::st_buffer::st_buffer_style_impl, + "st_centroid" => crate::st_centroid::st_centroid_impl, + "st_concavehull" => crate::st_concavehull::st_concave_hull_allow_holes_impl, + "st_concavehull" => crate::st_concavehull::st_concave_hull_impl, + "st_contains" => crate::binary_predicates::st_contains_impl, + "st_convexhull" => crate::st_convexhull::st_convex_hull_impl, + "st_coveredby" => crate::binary_predicates::st_covered_by_impl, + "st_covers" => crate::binary_predicates::st_covers_impl, + "st_crosses" => crate::binary_predicates::st_crosses_impl, + "st_difference" => crate::overlay::st_difference_impl, + "st_disjoint" => crate::binary_predicates::st_disjoint_impl, + "st_distance" => crate::distance::st_distance_impl, + "st_dwithin" => crate::st_dwithin::st_dwithin_impl, + "st_equals" => crate::binary_predicates::st_equals_impl, + "st_intersection" => crate::overlay::st_intersection_impl, + "st_intersects" => crate::binary_predicates::st_intersects_impl, + "st_isring" => crate::st_isring::st_is_ring_impl, + "st_issimple" => crate::st_issimple::st_is_simple_impl, + "st_isvalid" => crate::st_isvalid::st_is_valid_impl, + "st_isvalidreason" => crate::st_isvalidreason::st_is_valid_reason_impl, + "st_length" => crate::st_length::st_length_impl, + "st_linemerge" => crate::st_line_merge::st_line_merge_impl, + "st_makevalid" => crate::st_makevalid::st_make_valid_impl, + "st_minimumclearance" => crate::st_minimumclearance::st_minimum_clearance_impl, + "st_minimumclearanceline" => crate::st_minimumclearance_line::st_minimum_clearance_line_impl, + "st_nrings" => crate::st_nrings::st_nrings_impl, + "st_numinteriorrings" => crate::st_numinteriorrings::st_num_interior_rings_impl, + "st_numpoints" => crate::st_numpoints::st_num_points_impl, + "st_overlaps" => crate::binary_predicates::st_overlaps_impl, + "st_perimeter" => crate::st_perimeter::st_perimeter_impl, + "st_polygonize" => crate::st_polygonize::st_polygonize_impl, + "st_simplify" => crate::st_simplify::st_simplify_impl, + "st_simplifypreservetopology" => crate::st_simplifypreservetopology::st_simplify_preserve_topology_impl, + "st_snap" => crate::st_snap::st_snap_impl, + "st_symdifference" => crate::overlay::st_sym_difference_impl, + "st_touches" => crate::binary_predicates::st_touches_impl, + "st_unaryunion" => crate::st_unaryunion::st_unary_union_impl, + "st_union" => crate::overlay::st_union_impl, + "st_within" => crate::binary_predicates::st_within_impl, + ) } pub fn aggregate_kernels() -> Vec<(&'static str, SedonaAccumulatorRef)> { - vec![("st_polygonize_agg", st_polygonize_agg_impl())] + define_aggregate_kernels!( + "st_polygonize_agg" => crate::st_polygonize_agg::st_polygonize_agg_impl, + ) } diff --git a/c/sedona-geos/src/st_area.rs b/c/sedona-geos/src/st_area.rs index 7c9bead7d..7cd7bf828 100644 --- a/c/sedona-geos/src/st_area.rs +++ b/c/sedona-geos/src/st_area.rs @@ -21,14 +21,17 @@ use arrow_schema::DataType; use datafusion_common::{error::Result, DataFusionError}; use datafusion_expr::ColumnarValue; use geos::Geom; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher}; use crate::executor::GeosExecutor; /// ST_Area() implementation using the geos crate -pub fn st_area_impl() -> ScalarKernelRef { - Arc::new(STArea {}) +pub fn st_area_impl() -> Vec { + ItemCrsKernel::wrap_impl(STArea {}) } #[derive(Debug)] @@ -78,13 +81,16 @@ mod tests { use datafusion_common::ScalarValue; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY}; use sedona_testing::testers::ScalarUdfTester; use super::*; #[rstest] - fn udf(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType) { + fn udf( + #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY, WKB_GEOMETRY_ITEM_CRS.clone())] + sedona_type: SedonaType, + ) { let udf = SedonaScalarUDF::from_impl("st_area", st_area_impl()); let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type]); tester.assert_return_type(DataType::Float64); diff --git a/c/sedona-geos/src/st_boundary.rs b/c/sedona-geos/src/st_boundary.rs index f2dbc7442..e1f72b6b0 100644 --- a/c/sedona-geos/src/st_boundary.rs +++ b/c/sedona-geos/src/st_boundary.rs @@ -21,7 +21,10 @@ use arrow_array::builder::BinaryBuilder; use datafusion_common::{error::Result, DataFusionError}; use datafusion_expr::ColumnarValue; use geos::{Geom, Geometry, GeometryTypes}; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_geometry::wkb_factory::WKB_MIN_PROBABLE_BYTES; use sedona_schema::{ datatypes::{SedonaType, WKB_GEOMETRY}, @@ -32,8 +35,8 @@ use crate::executor::GeosExecutor; use crate::geos_to_wkb::write_geos_geometry; /// ST_Boundary() implementation using the geos crate -pub fn st_boundary_impl() -> ScalarKernelRef { - Arc::new(STBoundary {}) +pub fn st_boundary_impl() -> Vec { + ItemCrsKernel::wrap_impl(STBoundary {}) } #[derive(Debug)] @@ -284,7 +287,7 @@ fn collect_boundary_components( mod tests { use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY}; use sedona_testing::testers::ScalarUdfTester; use super::*; @@ -367,4 +370,14 @@ mod tests { let result = tester.invoke_scalar("GEOMETRYCOLLECTION EMPTY").unwrap(); tester.assert_scalar_result_equals(result, "GEOMETRYCOLLECTION EMPTY"); } + + #[rstest] + fn udf_invoke_item_crs(#[values(WKB_GEOMETRY_ITEM_CRS.clone())] sedona_type: SedonaType) { + let udf = SedonaScalarUDF::from_impl("st_boundary", st_boundary_impl()); + let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type.clone()]); + tester.assert_return_type(sedona_type); + + let result = tester.invoke_scalar("POINT (1 3)").unwrap(); + tester.assert_scalar_result_equals(result, "GEOMETRYCOLLECTION EMPTY"); + } } diff --git a/c/sedona-geos/src/st_buffer.rs b/c/sedona-geos/src/st_buffer.rs index 0c98da351..29718a72f 100644 --- a/c/sedona-geos/src/st_buffer.rs +++ b/c/sedona-geos/src/st_buffer.rs @@ -23,7 +23,10 @@ use datafusion_common::error::Result; use datafusion_common::{DataFusionError, ScalarValue}; use datafusion_expr::ColumnarValue; use geos::{BufferParams, CapStyle, Geom, JoinStyle}; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_geometry::wkb_factory::WKB_MIN_PROBABLE_BYTES; use sedona_schema::{ datatypes::{SedonaType, WKB_GEOMETRY}, @@ -46,8 +49,8 @@ use crate::geos_to_wkb::write_geos_geometry; /// - side: both, left, right /// - mitre_limit/miter_limit: numeric value /// - quad_segs/quadrant_segments: integer value -pub fn st_buffer_impl() -> ScalarKernelRef { - Arc::new(STBuffer {}) +pub fn st_buffer_impl() -> Vec { + ItemCrsKernel::wrap_impl(STBuffer {}) } #[derive(Debug)] @@ -72,8 +75,8 @@ impl SedonaScalarKernel for STBuffer { } } -pub fn st_buffer_style_impl() -> ScalarKernelRef { - Arc::new(STBufferStyle {}) +pub fn st_buffer_style_impl() -> Vec { + ItemCrsKernel::wrap_impl(STBufferStyle {}) } #[derive(Debug)] struct STBufferStyle {} @@ -296,7 +299,7 @@ mod tests { use datafusion_common::ScalarValue; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + 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; use sedona_testing::testers::ScalarUdfTester; @@ -728,4 +731,17 @@ mod tests { "Should handle complex string with both sides." ); } + + #[rstest] + fn udf_invoke_item_crs(#[values(WKB_GEOMETRY_ITEM_CRS.clone())] sedona_type: SedonaType) { + let udf = SedonaScalarUDF::from_impl("st_buffer", st_buffer_impl()); + let tester = ScalarUdfTester::new( + udf.into(), + vec![sedona_type.clone(), SedonaType::Arrow(DataType::Float64)], + ); + tester.assert_return_type(sedona_type); + + let result = tester.invoke_scalar_scalar("POINT (0 0)", 1.0).unwrap(); + assert!(!result.is_null()); + } } diff --git a/c/sedona-geos/src/st_centroid.rs b/c/sedona-geos/src/st_centroid.rs index 6750a2c7b..793b0215b 100644 --- a/c/sedona-geos/src/st_centroid.rs +++ b/c/sedona-geos/src/st_centroid.rs @@ -20,7 +20,10 @@ use arrow_array::builder::BinaryBuilder; use datafusion_common::{error::Result, DataFusionError}; use datafusion_expr::ColumnarValue; use geos::Geom; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_geometry::wkb_factory::WKB_MIN_PROBABLE_BYTES; use sedona_schema::{ datatypes::{SedonaType, WKB_GEOMETRY}, @@ -31,8 +34,8 @@ use crate::executor::GeosExecutor; use crate::geos_to_wkb::write_geos_geometry; /// ST_Centroid() implementation using the geos crate -pub fn st_centroid_impl() -> ScalarKernelRef { - Arc::new(STCentroid {}) +pub fn st_centroid_impl() -> Vec { + ItemCrsKernel::wrap_impl(STCentroid {}) } #[derive(Debug)] @@ -85,7 +88,7 @@ mod tests { use datafusion_common::ScalarValue; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + 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; use sedona_testing::testers::ScalarUdfTester; @@ -118,4 +121,16 @@ mod tests { ); assert_array_equal(&tester.invoke_wkb_array(input_wkt).unwrap(), &expected); } + + #[rstest] + fn udf_invoke_item_crs(#[values(WKB_GEOMETRY_ITEM_CRS.clone())] sedona_type: SedonaType) { + 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); + + let result = tester + .invoke_scalar("POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))") + .unwrap(); + tester.assert_scalar_result_equals(result, "POINT (0.5 0.5)"); + } } diff --git a/c/sedona-geos/src/st_concavehull.rs b/c/sedona-geos/src/st_concavehull.rs index 7f8e884e6..31c31d9c6 100644 --- a/c/sedona-geos/src/st_concavehull.rs +++ b/c/sedona-geos/src/st_concavehull.rs @@ -23,7 +23,10 @@ use datafusion_common::error::Result; use datafusion_common::{DataFusionError, ScalarValue}; use datafusion_expr::ColumnarValue; use geos::Geom; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_geometry::wkb_factory::WKB_MIN_PROBABLE_BYTES; use sedona_schema::{ datatypes::{SedonaType, WKB_GEOMETRY}, @@ -34,8 +37,8 @@ use crate::executor::GeosExecutor; use crate::geos_to_wkb::write_geos_geometry; /// ST_ConcaveHull() implementation using the geos crate -pub fn st_concave_hull_allow_holes_impl() -> ScalarKernelRef { - Arc::new(STConcaveHullAllowHoles {}) +pub fn st_concave_hull_allow_holes_impl() -> Vec { + ItemCrsKernel::wrap_impl(STConcaveHullAllowHoles {}) } #[derive(Debug)] @@ -64,8 +67,8 @@ impl SedonaScalarKernel for STConcaveHullAllowHoles { } } -pub fn st_concave_hull_impl() -> ScalarKernelRef { - Arc::new(STConcaveHull {}) +pub fn st_concave_hull_impl() -> Vec { + ItemCrsKernel::wrap_impl(STConcaveHull {}) } #[derive(Debug)] @@ -152,7 +155,7 @@ mod tests { use datafusion_common::ScalarValue; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY}; use sedona_testing::{ compare::{assert_array_equal, assert_scalar_equal_wkb_geometry}, create::create_array, @@ -471,4 +474,22 @@ mod tests { .unwrap(); tester.assert_scalar_result_equals(result, "POLYGON ((3 3, 1 1, 4 5, 5 6, 3 3))"); } + + #[rstest] + fn udf_invoke_item_crs(#[values(WKB_GEOMETRY_ITEM_CRS.clone())] sedona_type: SedonaType) { + let udf = SedonaScalarUDF::from_impl("st_concavehull", st_concave_hull_impl()); + let tester = ScalarUdfTester::new( + udf.into(), + vec![sedona_type.clone(), SedonaType::Arrow(DataType::Float64)], + ); + tester.assert_return_type(sedona_type); + + let result = tester + .invoke_scalar_scalar("POLYGON ((70 80, 50 60, 100 150, 160 170, 70 80))", 0.2) + .unwrap(); + tester.assert_scalar_result_equals( + result, + "POLYGON ((70 80, 50 60, 100 150, 160 170, 70 80))", + ); + } } diff --git a/c/sedona-geos/src/st_convexhull.rs b/c/sedona-geos/src/st_convexhull.rs index 48c76c5df..a034ead12 100644 --- a/c/sedona-geos/src/st_convexhull.rs +++ b/c/sedona-geos/src/st_convexhull.rs @@ -20,7 +20,10 @@ use arrow_array::builder::BinaryBuilder; use datafusion_common::{error::Result, DataFusionError}; use datafusion_expr::ColumnarValue; use geos::Geom; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_geometry::wkb_factory::WKB_MIN_PROBABLE_BYTES; use sedona_schema::{ datatypes::{SedonaType, WKB_GEOMETRY}, @@ -31,8 +34,8 @@ use crate::executor::GeosExecutor; use crate::geos_to_wkb::write_geos_geometry; /// ST_ConvexHull() implementation using the geos crate -pub fn st_convex_hull_impl() -> ScalarKernelRef { - Arc::new(STConvexHull {}) +pub fn st_convex_hull_impl() -> Vec { + ItemCrsKernel::wrap_impl(STConvexHull {}) } #[derive(Debug)] @@ -85,7 +88,7 @@ mod tests { use datafusion_common::ScalarValue; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + 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; use sedona_testing::testers::ScalarUdfTester; @@ -122,4 +125,16 @@ mod tests { ); assert_array_equal(&tester.invoke_wkb_array(input_wkt).unwrap(), &expected); } + + #[rstest] + fn udf_invoke_item_crs(#[values(WKB_GEOMETRY_ITEM_CRS.clone())] sedona_type: SedonaType) { + let udf = SedonaScalarUDF::from_impl("st_convex_hull", st_convex_hull_impl()); + let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type.clone()]); + tester.assert_return_type(sedona_type); + + let result = tester + .invoke_scalar("MULTIPOINT ((0 0), (0 1), (1 1), (1 0))") + .unwrap(); + tester.assert_scalar_result_equals(result, "POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))"); + } } diff --git a/c/sedona-geos/src/st_dwithin.rs b/c/sedona-geos/src/st_dwithin.rs index e24471c3e..6f1708c87 100644 --- a/c/sedona-geos/src/st_dwithin.rs +++ b/c/sedona-geos/src/st_dwithin.rs @@ -21,14 +21,17 @@ use arrow_schema::DataType; use datafusion_common::{cast::as_float64_array, error::Result, DataFusionError}; use datafusion_expr::ColumnarValue; use geos::Geom; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher}; use crate::executor::GeosExecutor; /// Implementation of ST_DWithin using the geos crate -pub fn st_dwithin_impl() -> ScalarKernelRef { - Arc::new(STDWithin {}) +pub fn st_dwithin_impl() -> Vec { + ItemCrsKernel::wrap_impl(STDWithin {}) } #[derive(Debug)] @@ -85,7 +88,7 @@ mod tests { use datafusion_common::ScalarValue; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + 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; use sedona_testing::testers::ScalarUdfTester; @@ -93,13 +96,16 @@ mod tests { use super::*; #[rstest] - fn udf(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType) { + fn udf( + #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY, WKB_GEOMETRY_ITEM_CRS.clone())] + sedona_type: SedonaType, + ) { let udf = SedonaScalarUDF::from_impl("st_dwithin", st_dwithin_impl()); let tester = ScalarUdfTester::new( udf.into(), vec![ sedona_type.clone(), - sedona_type, + sedona_type.clone(), SedonaType::Arrow(DataType::Float64), ], ); @@ -122,7 +128,7 @@ mod tests { None, Some("POINT EMPTY"), ], - &WKB_GEOMETRY, + &sedona_type, ); let arg2 = create_array( &[ @@ -131,7 +137,7 @@ mod tests { Some("POINT (0 0)"), Some("POINT EMPTY"), ], - &WKB_GEOMETRY, + &sedona_type, ); let distance = 1; diff --git a/c/sedona-geos/src/st_isring.rs b/c/sedona-geos/src/st_isring.rs index 0a6bb5854..4f3697ee3 100644 --- a/c/sedona-geos/src/st_isring.rs +++ b/c/sedona-geos/src/st_isring.rs @@ -22,14 +22,17 @@ use arrow_schema::DataType; use datafusion_common::{error::Result, DataFusionError}; use datafusion_expr::ColumnarValue; use geos::{Geom, GeometryTypes}; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher}; use crate::executor::GeosExecutor; /// ST_IsRing() implementation using the geos crate -pub fn st_is_ring_impl() -> ScalarKernelRef { - Arc::new(STIsRing {}) +pub fn st_is_ring_impl() -> Vec { + ItemCrsKernel::wrap_impl(STIsRing {}) } #[derive(Debug)] @@ -98,14 +101,17 @@ mod tests { use arrow_array::{create_array as arrow_array, ArrayRef}; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY}; use sedona_testing::compare::assert_array_equal; use sedona_testing::testers::ScalarUdfTester; use super::*; #[rstest] - fn udf(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType) { + fn udf( + #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY, WKB_GEOMETRY_ITEM_CRS.clone())] + sedona_type: SedonaType, + ) { let udf = SedonaScalarUDF::from_impl("st_isring", st_is_ring_impl()); let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type]); tester.assert_return_type(DataType::Boolean); diff --git a/c/sedona-geos/src/st_issimple.rs b/c/sedona-geos/src/st_issimple.rs index 1820a4653..f7a52faec 100644 --- a/c/sedona-geos/src/st_issimple.rs +++ b/c/sedona-geos/src/st_issimple.rs @@ -22,14 +22,17 @@ use arrow_schema::DataType; use datafusion_common::{DataFusionError, Result}; use datafusion_expr::ColumnarValue; use geos::Geom; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher}; use crate::executor::GeosExecutor; /// ST_IsSimple() implementation using the geos crate -pub fn st_is_simple_impl() -> ScalarKernelRef { - Arc::new(STIsSimple {}) +pub fn st_is_simple_impl() -> Vec { + ItemCrsKernel::wrap_impl(STIsSimple {}) } #[derive(Debug)] @@ -80,13 +83,16 @@ mod tests { use datafusion_common::ScalarValue; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY}; use sedona_testing::testers::ScalarUdfTester; use super::*; #[rstest] - fn udf(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType) { + fn udf( + #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY, WKB_GEOMETRY_ITEM_CRS.clone())] + sedona_type: SedonaType, + ) { let udf = SedonaScalarUDF::from_impl("st_issimple", st_is_simple_impl()); let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type]); tester.assert_return_type(DataType::Boolean); diff --git a/c/sedona-geos/src/st_isvalid.rs b/c/sedona-geos/src/st_isvalid.rs index 50fb40dfe..cb1839479 100644 --- a/c/sedona-geos/src/st_isvalid.rs +++ b/c/sedona-geos/src/st_isvalid.rs @@ -21,14 +21,17 @@ use arrow_schema::DataType; use datafusion_common::{DataFusionError, Result}; use datafusion_expr::ColumnarValue; use geos::Geom; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher}; use crate::executor::GeosExecutor; /// ST_IsValid() implementation using the geos crate -pub fn st_is_valid_impl() -> ScalarKernelRef { - Arc::new(STIsValid {}) +pub fn st_is_valid_impl() -> Vec { + ItemCrsKernel::wrap_impl(STIsValid {}) } #[derive(Debug)] @@ -81,13 +84,16 @@ mod tests { use datafusion_common::ScalarValue; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY}; use sedona_testing::testers::ScalarUdfTester; use super::*; #[rstest] - fn udf(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType) { + fn udf( + #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY, WKB_GEOMETRY_ITEM_CRS.clone())] + sedona_type: SedonaType, + ) { let udf = SedonaScalarUDF::from_impl("st_isvalid", st_is_valid_impl()); let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type]); tester.assert_return_type(DataType::Boolean); diff --git a/c/sedona-geos/src/st_isvalidreason.rs b/c/sedona-geos/src/st_isvalidreason.rs index 396c2ee93..527c520b1 100644 --- a/c/sedona-geos/src/st_isvalidreason.rs +++ b/c/sedona-geos/src/st_isvalidreason.rs @@ -21,15 +21,18 @@ use arrow_array::builder::StringBuilder; use arrow_schema::DataType; use datafusion_common::{DataFusionError, Result}; use geos::Geom; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_geometry::wkb_factory::WKB_MIN_PROBABLE_BYTES; use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher}; use crate::executor::GeosExecutor; /// ST_IsValidReason() implementation using the geos crate -pub fn st_is_valid_reason_impl() -> ScalarKernelRef { - Arc::new(STIsValidReason {}) +pub fn st_is_valid_reason_impl() -> Vec { + ItemCrsKernel::wrap_impl(STIsValidReason {}) } #[derive(Debug)] @@ -82,13 +85,16 @@ mod tests { use datafusion_common::ScalarValue; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY}; use sedona_testing::testers::ScalarUdfTester; use super::*; #[rstest] - fn udf(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType) { + fn udf( + #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY, WKB_GEOMETRY_ITEM_CRS.clone())] + sedona_type: SedonaType, + ) { use arrow_array::Array; let udf = SedonaScalarUDF::from_impl("st_isvalidreason", st_is_valid_reason_impl()); diff --git a/c/sedona-geos/src/st_length.rs b/c/sedona-geos/src/st_length.rs index 9ef119c2a..d196c27d2 100644 --- a/c/sedona-geos/src/st_length.rs +++ b/c/sedona-geos/src/st_length.rs @@ -24,14 +24,17 @@ use geos::{ GResult, Geom, GeometryTypes::{GeometryCollection, LineString, MultiLineString}, }; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher}; use crate::executor::GeosExecutor; /// ST_Length() implementation using the geos crate -pub fn st_length_impl() -> ScalarKernelRef { - Arc::new(STLength {}) +pub fn st_length_impl() -> Vec { + ItemCrsKernel::wrap_impl(STLength {}) } #[derive(Debug)] @@ -99,13 +102,16 @@ mod tests { use datafusion_common::ScalarValue; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY}; use sedona_testing::testers::ScalarUdfTester; use super::*; #[rstest] - fn udf(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType) { + fn udf( + #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY, WKB_GEOMETRY_ITEM_CRS.clone())] + sedona_type: SedonaType, + ) { let udf = SedonaScalarUDF::from_impl("st_length", st_length_impl()); let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type]); tester.assert_return_type(DataType::Float64); diff --git a/c/sedona-geos/src/st_line_merge.rs b/c/sedona-geos/src/st_line_merge.rs index db7146c86..4c1757b21 100644 --- a/c/sedona-geos/src/st_line_merge.rs +++ b/c/sedona-geos/src/st_line_merge.rs @@ -21,15 +21,18 @@ use arrow_array::builder::BinaryBuilder; use datafusion_common::{error::Result, DataFusionError, ScalarValue}; use datafusion_expr::ColumnarValue; use geos::Geom; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_geometry::wkb_factory::WKB_MIN_PROBABLE_BYTES; use sedona_schema::{datatypes::WKB_GEOMETRY, matchers::ArgMatcher}; use crate::executor::GeosExecutor; use crate::geos_to_wkb::write_geos_geometry; -pub fn st_line_merge_impl() -> ScalarKernelRef { - Arc::new(STLineMerge {}) +pub fn st_line_merge_impl() -> Vec { + ItemCrsKernel::wrap_impl(STLineMerge {}) } #[derive(Debug)] @@ -116,7 +119,9 @@ mod tests { use datafusion_common::ScalarValue; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{SedonaType, WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + use sedona_schema::datatypes::{ + SedonaType, WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY, + }; use sedona_testing::create::create_array; use sedona_testing::testers::ScalarUdfTester; @@ -178,4 +183,21 @@ mod tests { .unwrap(); assert!(result.is_null()); } + + #[rstest] + fn udf_invoke_item_crs(#[values(WKB_GEOMETRY_ITEM_CRS.clone())] sedona_type: SedonaType) { + use arrow_schema::DataType; + + let udf = SedonaScalarUDF::from_impl("st_linemerge", st_line_merge_impl()); + let tester = ScalarUdfTester::new( + udf.into(), + vec![sedona_type.clone(), SedonaType::Arrow(DataType::Boolean)], + ); + tester.assert_return_type(sedona_type); + + let result = tester + .invoke_scalar_scalar("MULTILINESTRING ((0 0, 1 0), (1 0, 1 1))", false) + .unwrap(); + tester.assert_scalar_result_equals(result, "LINESTRING (0 0, 1 0, 1 1)"); + } } diff --git a/c/sedona-geos/src/st_makevalid.rs b/c/sedona-geos/src/st_makevalid.rs index 71011846f..cefc7b747 100644 --- a/c/sedona-geos/src/st_makevalid.rs +++ b/c/sedona-geos/src/st_makevalid.rs @@ -21,7 +21,10 @@ use arrow_array::builder::BinaryBuilder; use datafusion_common::{DataFusionError, Result}; use datafusion_expr::ColumnarValue; use geos::Geom; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_geometry::wkb_factory::WKB_MIN_PROBABLE_BYTES; use sedona_schema::{ datatypes::{SedonaType, WKB_GEOMETRY}, @@ -32,8 +35,8 @@ use crate::executor::GeosExecutor; use crate::geos_to_wkb::write_geos_geometry; /// ST_MakeValid() implementation using the geos crate -pub fn st_make_valid_impl() -> ScalarKernelRef { - Arc::new(STMakeValid {}) +pub fn st_make_valid_impl() -> Vec { + ItemCrsKernel::wrap_impl(STMakeValid {}) } #[derive(Debug)] @@ -86,7 +89,7 @@ fn invoke_scalar(geos_geom: &geos::Geometry, writer: &mut impl std::io::Write) - mod tests { use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::WKB_VIEW_GEOMETRY; + use sedona_schema::datatypes::{WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY}; use sedona_testing::{create::create_array, testers::ScalarUdfTester}; use super::*; @@ -155,4 +158,16 @@ mod tests { "POLYGON((0 0,0 10,10 10,10 0,0 0),(5 5,5 5.0001,5.0001 5.0001,5.0001 5,5 5))", ); } + + #[rstest] + fn udf_invoke_item_crs(#[values(WKB_GEOMETRY_ITEM_CRS.clone())] sedona_type: SedonaType) { + let udf = SedonaScalarUDF::from_impl("st_makevalid", st_make_valid_impl()); + let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type.clone()]); + tester.assert_return_type(sedona_type); + + let result = tester + .invoke_scalar("POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))") + .unwrap(); + tester.assert_scalar_result_equals(result, "POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))"); + } } diff --git a/c/sedona-geos/src/st_minimumclearance.rs b/c/sedona-geos/src/st_minimumclearance.rs index 1b1838712..bdf8c6eed 100644 --- a/c/sedona-geos/src/st_minimumclearance.rs +++ b/c/sedona-geos/src/st_minimumclearance.rs @@ -22,14 +22,17 @@ use arrow_schema::DataType; use datafusion_common::{DataFusionError, Result}; use datafusion_expr::ColumnarValue; use geos::Geom; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher}; use crate::executor::GeosExecutor; /// ST_MinimumClearance() implementation using the geos crate -pub fn st_minimum_clearance_impl() -> ScalarKernelRef { - Arc::new(STMinimumClearance {}) +pub fn st_minimum_clearance_impl() -> Vec { + ItemCrsKernel::wrap_impl(STMinimumClearance {}) } #[derive(Debug)] @@ -77,13 +80,16 @@ mod tests { use arrow_array::{create_array, ArrayRef}; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY}; use sedona_testing::testers::ScalarUdfTester; use super::*; #[rstest] - fn udf(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType) { + fn udf( + #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY, WKB_GEOMETRY_ITEM_CRS.clone())] + sedona_type: SedonaType, + ) { let udf = SedonaScalarUDF::from_impl("st_minimumclearance", st_minimum_clearance_impl()); let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type]); tester.assert_return_type(DataType::Float64); diff --git a/c/sedona-geos/src/st_minimumclearance_line.rs b/c/sedona-geos/src/st_minimumclearance_line.rs index 984bdcb74..947cce48e 100644 --- a/c/sedona-geos/src/st_minimumclearance_line.rs +++ b/c/sedona-geos/src/st_minimumclearance_line.rs @@ -21,7 +21,10 @@ use arrow_array::builder::BinaryBuilder; use datafusion_common::{DataFusionError, Result}; use datafusion_expr::ColumnarValue; use geos::Geom; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_geometry::wkb_factory::WKB_MIN_PROBABLE_BYTES; use sedona_schema::{ datatypes::{SedonaType, WKB_GEOMETRY}, @@ -32,8 +35,8 @@ use crate::executor::GeosExecutor; use crate::geos_to_wkb::write_geos_geometry; /// ST_MinimumClearanceLine() implementation using the geos crate -pub fn st_minimum_clearance_line_impl() -> ScalarKernelRef { - Arc::new(STMinimumClearanceLine {}) +pub fn st_minimum_clearance_line_impl() -> Vec { + ItemCrsKernel::wrap_impl(STMinimumClearanceLine {}) } #[derive(Debug)] @@ -88,7 +91,7 @@ fn invoke_scalar(geos_geom: &geos::Geometry, writer: &mut impl std::io::Write) - mod tests { use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::WKB_VIEW_GEOMETRY; + use sedona_schema::datatypes::{WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY}; use sedona_testing::{create::create_array, testers::ScalarUdfTester}; use super::*; @@ -134,4 +137,17 @@ mod tests { assert_eq!(&tester.invoke_wkb_array(input_wkt).unwrap(), &expected); } + + #[rstest] + fn udf_invoke_item_crs(#[values(WKB_GEOMETRY_ITEM_CRS.clone())] sedona_type: SedonaType) { + let udf = + SedonaScalarUDF::from_impl("st_minimumclearanceline", st_minimum_clearance_line_impl()); + let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type.clone()]); + tester.assert_return_type(sedona_type); + + let result = tester + .invoke_scalar("POLYGON ((0 0, 1 0, 1 1, 0.5 3.2e-4, 0 0))") + .unwrap(); + tester.assert_scalar_result_equals(result, "LINESTRING(0.5 0.00032,0.5 0)"); + } } diff --git a/c/sedona-geos/src/st_nrings.rs b/c/sedona-geos/src/st_nrings.rs index 7893f0f61..e57e50367 100644 --- a/c/sedona-geos/src/st_nrings.rs +++ b/c/sedona-geos/src/st_nrings.rs @@ -23,11 +23,14 @@ use arrow_schema::DataType; use datafusion_common::{error::Result, DataFusionError}; use datafusion_expr::ColumnarValue; use geos::{Geom, GeometryTypes}; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher}; -pub fn st_nrings_impl() -> ScalarKernelRef { - Arc::new(STNRings {}) +pub fn st_nrings_impl() -> Vec { + ItemCrsKernel::wrap_impl(STNRings {}) } #[derive(Debug)] @@ -112,14 +115,19 @@ mod tests { use datafusion_common::ScalarValue; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{SedonaType, WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + use sedona_schema::datatypes::{ + SedonaType, WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY, + }; use sedona_testing::compare::assert_array_equal; use sedona_testing::testers::ScalarUdfTester; use super::*; #[rstest] - fn udf(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType) { + fn udf( + #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY, WKB_GEOMETRY_ITEM_CRS.clone())] + sedona_type: SedonaType, + ) { let udf = SedonaScalarUDF::from_impl("st_nrings", st_nrings_impl()); let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type]); tester.assert_return_type(DataType::Int32); diff --git a/c/sedona-geos/src/st_numinteriorrings.rs b/c/sedona-geos/src/st_numinteriorrings.rs index 3f127e54c..71b368ddd 100644 --- a/c/sedona-geos/src/st_numinteriorrings.rs +++ b/c/sedona-geos/src/st_numinteriorrings.rs @@ -23,11 +23,14 @@ use arrow_schema::DataType; use datafusion_common::{error::Result, DataFusionError}; use datafusion_expr::ColumnarValue; use geos::{Geom, Geometry, GeometryTypes}; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher}; -pub fn st_num_interior_rings_impl() -> ScalarKernelRef { - Arc::new(STNumInteriorRings {}) +pub fn st_num_interior_rings_impl() -> Vec { + ItemCrsKernel::wrap_impl(STNumInteriorRings {}) } #[derive(Debug)] @@ -99,14 +102,19 @@ mod tests { use datafusion_common::ScalarValue; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{SedonaType, WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + use sedona_schema::datatypes::{ + SedonaType, WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY, + }; use sedona_testing::compare::assert_array_equal; use sedona_testing::testers::ScalarUdfTester; use super::*; #[rstest] - fn udf(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType) { + fn udf( + #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY, WKB_GEOMETRY_ITEM_CRS.clone())] + sedona_type: SedonaType, + ) { let udf = SedonaScalarUDF::from_impl("st_numinteriorrings", st_num_interior_rings_impl()); let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type]); tester.assert_return_type(DataType::Int32); diff --git a/c/sedona-geos/src/st_numpoints.rs b/c/sedona-geos/src/st_numpoints.rs index fd77b53cf..9112578a2 100644 --- a/c/sedona-geos/src/st_numpoints.rs +++ b/c/sedona-geos/src/st_numpoints.rs @@ -23,11 +23,14 @@ use arrow_schema::DataType; use datafusion_common::{error::Result, DataFusionError}; use datafusion_expr::ColumnarValue; use geos::{Geom, Geometry, GeometryTypes}; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher}; -pub fn st_num_points_impl() -> ScalarKernelRef { - Arc::new(STNumPoints {}) +pub fn st_num_points_impl() -> Vec { + ItemCrsKernel::wrap_impl(STNumPoints {}) } #[derive(Debug)] @@ -92,14 +95,19 @@ mod tests { use datafusion_common::ScalarValue; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{SedonaType, WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + use sedona_schema::datatypes::{ + SedonaType, WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY, + }; use sedona_testing::compare::assert_array_equal; use sedona_testing::testers::ScalarUdfTester; use super::*; #[rstest] - fn udf(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType) { + fn udf( + #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY, WKB_GEOMETRY_ITEM_CRS.clone())] + sedona_type: SedonaType, + ) { let udf = SedonaScalarUDF::from_impl("st_numpoints", st_num_points_impl()); let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type]); tester.assert_return_type(DataType::Int32); diff --git a/c/sedona-geos/src/st_perimeter.rs b/c/sedona-geos/src/st_perimeter.rs index f3c80826e..592a74611 100644 --- a/c/sedona-geos/src/st_perimeter.rs +++ b/c/sedona-geos/src/st_perimeter.rs @@ -24,13 +24,16 @@ use geos::{ GResult, Geom, GeometryTypes::{GeometryCollection, MultiPolygon, Polygon}, }; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher}; use crate::executor::GeosExecutor; -pub fn st_perimeter_impl() -> ScalarKernelRef { - Arc::new(STPerimeter {}) +pub fn st_perimeter_impl() -> Vec { + ItemCrsKernel::wrap_impl(STPerimeter {}) } #[derive(Debug)] @@ -98,13 +101,16 @@ mod tests { use datafusion_common::ScalarValue; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY}; use sedona_testing::testers::ScalarUdfTester; use super::*; #[rstest] - fn udf(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType) { + fn udf( + #[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY, WKB_GEOMETRY_ITEM_CRS.clone())] + sedona_type: SedonaType, + ) { let udf = SedonaScalarUDF::from_impl("st_perimeter", st_perimeter_impl()); let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type]); tester.assert_return_type(DataType::Float64); diff --git a/c/sedona-geos/src/st_polygonize.rs b/c/sedona-geos/src/st_polygonize.rs index 717089848..3d7a280cc 100644 --- a/c/sedona-geos/src/st_polygonize.rs +++ b/c/sedona-geos/src/st_polygonize.rs @@ -20,7 +20,10 @@ use std::sync::Arc; use arrow_array::builder::BinaryBuilder; use datafusion_common::{DataFusionError, Result}; use datafusion_expr::ColumnarValue; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_geometry::wkb_factory::WKB_MIN_PROBABLE_BYTES; use sedona_schema::{ datatypes::{SedonaType, WKB_GEOMETRY}, @@ -31,8 +34,8 @@ use crate::executor::GeosExecutor; use crate::geos_to_wkb::write_geos_geometry; /// ST_Polygonize() scalar implementation using GEOS -pub fn st_polygonize_impl() -> ScalarKernelRef { - Arc::new(STPolygonize {}) +pub fn st_polygonize_impl() -> Vec { + ItemCrsKernel::wrap_impl(STPolygonize {}) } #[derive(Debug)] @@ -83,7 +86,7 @@ fn invoke_scalar(geos_geom: &geos::Geometry, writer: &mut impl std::io::Write) - mod tests { use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{SedonaType, WKB_VIEW_GEOMETRY}; + use sedona_schema::datatypes::{SedonaType, WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY}; use sedona_testing::{ compare::assert_array_equal, create::create_array, testers::ScalarUdfTester, }; @@ -139,4 +142,19 @@ mod tests { &expected_geometries, ); } + + #[rstest] + fn udf_invoke_item_crs(#[values(WKB_GEOMETRY_ITEM_CRS.clone())] sedona_type: SedonaType) { + let udf = SedonaScalarUDF::from_impl("st_polygonize", st_polygonize_impl()); + let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type.clone()]); + tester.assert_return_type(sedona_type); + + let result = tester + .invoke_scalar("LINESTRING(0 0, 0 1, 1 1, 1 0, 0 0)") + .unwrap(); + tester.assert_scalar_result_equals( + result, + "GEOMETRYCOLLECTION(POLYGON((0 0, 0 1, 1 1, 1 0, 0 0)))", + ); + } } diff --git a/c/sedona-geos/src/st_simplify.rs b/c/sedona-geos/src/st_simplify.rs index 8f76606f8..0217533c2 100644 --- a/c/sedona-geos/src/st_simplify.rs +++ b/c/sedona-geos/src/st_simplify.rs @@ -22,7 +22,10 @@ use arrow_schema::DataType; use datafusion_common::{cast::as_float64_array, DataFusionError, Result}; use datafusion_expr::ColumnarValue; use geos::{Geom, Geometry, GeometryTypes}; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_geometry::wkb_factory::WKB_MIN_PROBABLE_BYTES; use sedona_schema::{ datatypes::{SedonaType, WKB_GEOMETRY}, @@ -33,8 +36,8 @@ use crate::executor::GeosExecutor; use crate::geos_to_wkb::write_geos_geometry; /// ST_Simplify() implementation using the geos crate -pub fn st_simplify_impl() -> ScalarKernelRef { - Arc::new(STSimplify {}) +pub fn st_simplify_impl() -> Vec { + ItemCrsKernel::wrap_impl(STSimplify {}) } #[derive(Debug)] @@ -147,7 +150,7 @@ mod tests { use datafusion_common::ScalarValue; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY}; use sedona_testing::{ compare::assert_array_equal, create::create_array, testers::ScalarUdfTester, }; @@ -628,4 +631,19 @@ mod tests { .unwrap(); tester.assert_scalar_result_equals(result, "LINESTRING(0 0, 10 0, 5 15, 0 0)"); } + + #[rstest] + fn udf_invoke_item_crs(#[values(WKB_GEOMETRY_ITEM_CRS.clone())] sedona_type: SedonaType) { + let udf = SedonaScalarUDF::from_impl("st_simplify", st_simplify_impl()); + let tester = ScalarUdfTester::new( + udf.into(), + vec![sedona_type.clone(), SedonaType::Arrow(DataType::Float64)], + ); + tester.assert_return_type(sedona_type); + + let result = tester + .invoke_scalar_scalar("LINESTRING(0 0, 1 1, 2 0, 3 1, 4 0)", 1.5) + .unwrap(); + tester.assert_scalar_result_equals(result, "LINESTRING(0 0, 4 0)"); + } } diff --git a/c/sedona-geos/src/st_simplifypreservetopology.rs b/c/sedona-geos/src/st_simplifypreservetopology.rs index 625ce19bc..748e01fbd 100644 --- a/c/sedona-geos/src/st_simplifypreservetopology.rs +++ b/c/sedona-geos/src/st_simplifypreservetopology.rs @@ -23,7 +23,10 @@ use datafusion_common::cast::as_float64_array; use datafusion_common::error::Result; use datafusion_common::DataFusionError; use datafusion_expr::ColumnarValue; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_geometry::wkb_factory::WKB_MIN_PROBABLE_BYTES; use sedona_schema::{ datatypes::{SedonaType, WKB_GEOMETRY}, @@ -34,8 +37,8 @@ use crate::executor::GeosExecutor; use crate::geos_to_wkb::write_geos_geometry; /// ST_SimplifyPreserveTopology() implementation using the geos crate -pub fn st_simplify_preserve_topology_impl() -> ScalarKernelRef { - Arc::new(STSimplifyPreserveTopology {}) +pub fn st_simplify_preserve_topology_impl() -> Vec { + ItemCrsKernel::wrap_impl(STSimplifyPreserveTopology {}) } #[derive(Debug)] @@ -103,7 +106,7 @@ mod tests { use datafusion_common::ScalarValue; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + 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; use sedona_testing::testers::ScalarUdfTester; @@ -226,4 +229,22 @@ mod tests { &expected_array, ); } + + #[rstest] + fn udf_invoke_item_crs(#[values(WKB_GEOMETRY_ITEM_CRS.clone())] sedona_type: SedonaType) { + let udf = SedonaScalarUDF::from_impl( + "st_simplifypreservetopology", + st_simplify_preserve_topology_impl(), + ); + let tester = ScalarUdfTester::new( + udf.into(), + vec![sedona_type.clone(), SedonaType::Arrow(DataType::Float64)], + ); + tester.assert_return_type(sedona_type); + + let result = tester + .invoke_scalar_scalar("LINESTRING(0 0, 0 10, 0 51, 50 20, 30 20, 7 32)", 2.0) + .unwrap(); + tester.assert_scalar_result_equals(result, "LINESTRING(0 0,0 51,50 20,30 20,7 32)"); + } } diff --git a/c/sedona-geos/src/st_snap.rs b/c/sedona-geos/src/st_snap.rs index 88862b671..731671b5c 100644 --- a/c/sedona-geos/src/st_snap.rs +++ b/c/sedona-geos/src/st_snap.rs @@ -22,7 +22,10 @@ use arrow_schema::DataType; use datafusion_common::{cast::as_float64_array, DataFusionError, Result}; use datafusion_expr::ColumnarValue; use geos::Geom; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_geometry::wkb_factory::WKB_MIN_PROBABLE_BYTES; use sedona_schema::{ datatypes::{SedonaType, WKB_GEOMETRY}, @@ -33,8 +36,8 @@ use crate::executor::GeosExecutor; use crate::geos_to_wkb::write_geos_geometry; /// ST_Snap() implementation using the geos crate -pub fn st_snap_impl() -> ScalarKernelRef { - Arc::new(STSnap {}) +pub fn st_snap_impl() -> Vec { + ItemCrsKernel::wrap_impl(STSnap {}) } #[derive(Debug)] @@ -115,7 +118,7 @@ fn invoke_scalar( mod tests { use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{SedonaType, WKB_VIEW_GEOMETRY}; + use sedona_schema::datatypes::{SedonaType, WKB_GEOMETRY_ITEM_CRS, WKB_VIEW_GEOMETRY}; use sedona_testing::{ compare::assert_array_equal, create::create_array, testers::ScalarUdfTester, }; @@ -254,4 +257,23 @@ mod tests { &expected_geometries, ); } + + #[rstest] + fn udf_invoke_item_crs(#[values(WKB_GEOMETRY_ITEM_CRS.clone())] sedona_type: SedonaType) { + let udf = SedonaScalarUDF::from_impl("st_snap", st_snap_impl()); + let tester = ScalarUdfTester::new( + udf.into(), + vec![ + sedona_type.clone(), + sedona_type.clone(), + SedonaType::Arrow(DataType::Float64), + ], + ); + tester.assert_return_type(sedona_type); + + let result = tester + .invoke_scalar_scalar_scalar("POINT (1.1 2.1)", "POINT (1 2)", 0.5) + .unwrap(); + tester.assert_scalar_result_equals(result, "POINT (1 2)"); + } } diff --git a/c/sedona-geos/src/st_unaryunion.rs b/c/sedona-geos/src/st_unaryunion.rs index d1cc3d19e..ba08f0bf1 100644 --- a/c/sedona-geos/src/st_unaryunion.rs +++ b/c/sedona-geos/src/st_unaryunion.rs @@ -21,7 +21,10 @@ use arrow_array::builder::BinaryBuilder; use datafusion_common::{DataFusionError, Result}; use datafusion_expr::ColumnarValue; use geos::Geom; -use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel}; +use sedona_expr::{ + item_crs::ItemCrsKernel, + scalar_udf::{ScalarKernelRef, SedonaScalarKernel}, +}; use sedona_geometry::wkb_factory::WKB_MIN_PROBABLE_BYTES; use sedona_schema::datatypes::SedonaType; use sedona_schema::{datatypes::WKB_GEOMETRY, matchers::ArgMatcher}; @@ -30,8 +33,8 @@ use crate::executor::GeosExecutor; use crate::geos_to_wkb::write_geos_geometry; /// ST_UnaryUnion() implementation using the geos crate -pub fn st_unary_union_impl() -> ScalarKernelRef { - Arc::new(STUnaryUnion {}) +pub fn st_unary_union_impl() -> Vec { + ItemCrsKernel::wrap_impl(STUnaryUnion {}) } #[derive(Debug)] @@ -84,7 +87,7 @@ mod tests { use datafusion_common::ScalarValue; use rstest::rstest; use sedona_expr::scalar_udf::SedonaScalarUDF; - use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + 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; use sedona_testing::testers::ScalarUdfTester; @@ -130,4 +133,18 @@ mod tests { ); assert_array_equal(&tester.invoke_wkb_array(input_wkt).unwrap(), &expected); } + + #[rstest] + fn udf_invoke_item_crs(#[values(WKB_GEOMETRY_ITEM_CRS.clone())] sedona_type: SedonaType) { + let udf = SedonaScalarUDF::from_impl("st_unary_union", st_unary_union_impl()); + let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type.clone()]); + tester.assert_return_type(sedona_type); + + let result = tester + .invoke_scalar( + "MULTIPOLYGON (((0 0, 1 0, 1 1, 0 1, 0 0)), ((1 0, 2 0, 2 1, 1 1, 1 0)))", + ) + .unwrap(); + tester.assert_scalar_result_equals(result, "POLYGON ((0 0, 0 1, 1 1, 2 1, 2 0, 1 0, 0 0))"); + } }