blob: 9d785d69aa3f095644c4ba6d22bcbdd246a57829 [file] [log] [blame]
// 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::{str::FromStr, sync::Arc};
use arrow_array::{ArrayRef, BinaryArray, BinaryViewArray};
use datafusion_common::ScalarValue;
use datafusion_expr::ColumnarValue;
use sedona_schema::datatypes::SedonaType;
use wkb::{writer::WriteOptions, Endianness};
use wkt::Wkt;
/// Create a [`ColumnarValue`] array from a sequence of WKT literals
///
/// Panics on invalid WKT or unsupported data type.
pub fn create_array_value(wkt_values: &[Option<&str>], data_type: &SedonaType) -> ColumnarValue {
ColumnarValue::Array(create_array_storage(wkt_values, data_type))
}
/// Create a [`ColumnarValue`] scalar from a WKT literal
///
/// Panics on invalid WKT or unsupported data type.
pub fn create_scalar_value(wkt_value: Option<&str>, data_type: &SedonaType) -> ColumnarValue {
ColumnarValue::Scalar(create_scalar_storage(wkt_value, data_type))
}
/// Create a [`ScalarValue`] from a WKT literal
///
/// Panics on invalid WKT or unsupported data type.
pub fn create_scalar(wkt_value: Option<&str>, data_type: &SedonaType) -> ScalarValue {
create_scalar_storage(wkt_value, data_type)
}
/// Create an [`ArrayRef`] from a sequence of WKT literals
///
/// Panics on invalid WKT or unsupported data type.
pub fn create_array(wkt_values: &[Option<&str>], data_type: &SedonaType) -> ArrayRef {
create_array_storage(wkt_values, data_type)
}
/// Create the storage [`ArrayRef`] from a sequence of WKT literals
///
/// Panics on invalid WKT or unsupported data type.
pub fn create_array_storage(wkt_values: &[Option<&str>], data_type: &SedonaType) -> ArrayRef {
match data_type {
SedonaType::Wkb(_, _) => Arc::new(make_wkb_array::<BinaryArray>(wkt_values)),
SedonaType::WkbView(_, _) => Arc::new(make_wkb_array::<BinaryViewArray>(wkt_values)),
_ => panic!("create_array_storage not implemented for {data_type:?}"),
}
}
/// Create the storage [`ScalarValue`] from a WKT literal
///
/// Panics on invalid WKT or unsupported data type.
pub fn create_scalar_storage(wkt_value: Option<&str>, data_type: &SedonaType) -> ScalarValue {
match data_type {
SedonaType::Wkb(_, _) => ScalarValue::Binary(wkt_value.map(make_wkb)),
SedonaType::WkbView(_, _) => ScalarValue::BinaryView(wkt_value.map(make_wkb)),
_ => panic!("create_scalar_storage not implemented for {data_type:?}"),
}
}
fn make_wkb_array<T>(wkt_values: &[Option<&str>]) -> T
where
T: FromIterator<Option<Vec<u8>>>,
{
wkt_values
.iter()
.map(|maybe_wkt| maybe_wkt.map(make_wkb))
.collect()
}
/// Create a WKB from a WKT string.
pub fn make_wkb(wkt_value: &str) -> Vec<u8> {
let geom = Wkt::<f64>::from_str(wkt_value).unwrap();
let mut out: Vec<u8> = vec![];
wkb::writer::write_geometry(
&mut out,
&geom,
&WriteOptions {
endianness: Endianness::LittleEndian,
},
)
.unwrap();
out
}
#[cfg(test)]
mod tests {
use arrow_schema::DataType;
use datafusion_common::cast::as_binary_array;
use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY};
use super::*;
#[test]
fn scalars() {
let wkb_scalar = create_scalar_storage(Some("POINT (0 1)"), &WKB_GEOMETRY);
assert_eq!(&wkb_scalar.data_type(), WKB_GEOMETRY.storage_type());
assert!(create_scalar_storage(None, &WKB_GEOMETRY).is_null());
let wkb_view_scalar = create_scalar_storage(Some("POINT (0 1)"), &WKB_VIEW_GEOMETRY);
assert_eq!(
&wkb_view_scalar.data_type(),
WKB_VIEW_GEOMETRY.storage_type()
);
assert!(create_scalar_storage(None, &WKB_VIEW_GEOMETRY).is_null());
}
#[test]
#[should_panic(expected = "create_scalar_storage not implemented")]
fn scalar_storage_invalid() {
create_scalar_storage(Some("POINT (0 1)"), &SedonaType::Arrow(DataType::Null));
}
#[test]
fn arrays() {
let wkb_array = create_array_storage(
&[Some("POINT (0 1)"), None, Some("POINT (1 2)")],
&WKB_GEOMETRY,
);
assert_eq!(wkb_array.data_type(), WKB_GEOMETRY.storage_type());
assert_eq!(wkb_array.len(), 3);
let wkb_binary_array = as_binary_array(&wkb_array).unwrap();
assert_eq!(
wkb_binary_array
.iter()
.map(|maybe_item| maybe_item.is_some())
.collect::<Vec<bool>>(),
vec![true, false, true]
);
let wkb_array = create_array_storage(
&[Some("POINT (0 1)"), None, Some("POINT (1 2)")],
&WKB_VIEW_GEOMETRY,
);
assert_eq!(wkb_array.data_type(), WKB_VIEW_GEOMETRY.storage_type());
}
#[test]
#[should_panic(expected = "create_array_storage not implemented")]
fn array_storage_invalid() {
create_array_storage(&[Some("POINT (0 1)")], &SedonaType::Arrow(DataType::Null));
}
}