1use std::{str::FromStr, sync::Arc};
18
19use arrow_array::{ArrayRef, BinaryArray, BinaryViewArray, StringViewArray, StructArray};
20use arrow_schema::{DataType, Field};
21use datafusion_common::ScalarValue;
22use datafusion_expr::ColumnarValue;
23use sedona_schema::datatypes::SedonaType;
24use wkb::{writer::WriteOptions, Endianness};
25use wkt::Wkt;
26
27pub fn create_array_value(wkt_values: &[Option<&str>], data_type: &SedonaType) -> ColumnarValue {
31 ColumnarValue::Array(create_array_storage(wkt_values, data_type))
32}
33
34pub fn create_scalar_value(wkt_value: Option<&str>, data_type: &SedonaType) -> ColumnarValue {
38 ColumnarValue::Scalar(create_scalar_storage(wkt_value, data_type))
39}
40
41pub fn create_scalar(wkt_value: Option<&str>, data_type: &SedonaType) -> ScalarValue {
45 create_scalar_storage(wkt_value, data_type)
46}
47
48pub fn create_array(wkt_values: &[Option<&str>], data_type: &SedonaType) -> ArrayRef {
52 create_array_storage(wkt_values, data_type)
53}
54
55pub fn create_array_storage(wkt_values: &[Option<&str>], data_type: &SedonaType) -> ArrayRef {
60 match data_type {
61 SedonaType::Wkb(_, _) => Arc::new(make_wkb_array::<BinaryArray>(wkt_values)),
62 SedonaType::WkbView(_, _) => Arc::new(make_wkb_array::<BinaryViewArray>(wkt_values)),
63 SedonaType::Arrow(DataType::Struct(fields))
64 if fields.iter().map(|f| f.name()).collect::<Vec<_>>() == vec!["item", "crs"] =>
65 {
66 let item_type = SedonaType::from_storage_field(&fields[0]).unwrap();
67 create_array_item_crs(wkt_values, (0..wkt_values.len()).map(|_| None), &item_type)
68 }
69 _ => panic!("create_array_storage not implemented for {data_type:?}"),
70 }
71}
72
73pub fn create_array_item_crs<'a>(
77 wkt_values: &[Option<&str>],
78 crs: impl IntoIterator<Item = Option<&'a str>>,
79 item_type: &SedonaType,
80) -> ArrayRef {
81 let out_fields = vec![
82 item_type.to_storage_field("item", true).unwrap(),
83 Field::new("crs", DataType::Utf8View, true),
84 ];
85
86 let item_array = create_array_storage(wkt_values, item_type);
87 let crs_array = Arc::new(crs.into_iter().collect::<StringViewArray>());
88 let nulls = item_array.nulls().cloned();
89 Arc::new(StructArray::new(
90 out_fields.into(),
91 vec![item_array, crs_array],
92 nulls,
93 ))
94}
95
96pub fn create_scalar_storage(wkt_value: Option<&str>, data_type: &SedonaType) -> ScalarValue {
102 match data_type {
103 SedonaType::Wkb(_, _) => ScalarValue::Binary(wkt_value.map(make_wkb)),
104 SedonaType::WkbView(_, _) => ScalarValue::BinaryView(wkt_value.map(make_wkb)),
105 SedonaType::Arrow(DataType::Struct(fields))
106 if fields.iter().map(|f| f.name()).collect::<Vec<_>>() == vec!["item", "crs"] =>
107 {
108 let item_type = SedonaType::from_storage_field(&fields[0]).unwrap();
109 create_scalar_item_crs(wkt_value, None, &item_type)
110 }
111 _ => panic!("create_scalar_storage not implemented for {data_type:?}"),
112 }
113}
114
115pub fn create_scalar_item_crs(
119 wkt_value: Option<&str>,
120 crs: Option<&str>,
121 item_type: &SedonaType,
122) -> ScalarValue {
123 let out_fields = vec![
124 item_type.to_storage_field("item", true).unwrap(),
125 Field::new("crs", DataType::Utf8View, true),
126 ];
127
128 let storage_item = create_scalar_storage(wkt_value, item_type)
129 .to_array()
130 .unwrap();
131 let storage_crs = ScalarValue::Utf8View(crs.map(|item| item.to_string()))
132 .to_array()
133 .unwrap();
134 let nulls = storage_item.nulls().cloned();
135 let item_crs_array =
136 StructArray::try_new(out_fields.into(), vec![storage_item, storage_crs], nulls).unwrap();
137
138 ScalarValue::Struct(Arc::new(item_crs_array))
139}
140
141fn make_wkb_array<T>(wkt_values: &[Option<&str>]) -> T
142where
143 T: FromIterator<Option<Vec<u8>>>,
144{
145 wkt_values
146 .iter()
147 .map(|maybe_wkt| maybe_wkt.map(make_wkb))
148 .collect()
149}
150
151pub fn make_wkb(wkt_value: &str) -> Vec<u8> {
153 let geom = Wkt::<f64>::from_str(wkt_value).unwrap();
154 let mut out: Vec<u8> = vec![];
155 wkb::writer::write_geometry(
156 &mut out,
157 &geom,
158 &WriteOptions {
159 endianness: Endianness::LittleEndian,
160 },
161 )
162 .unwrap();
163 out
164}
165
166#[cfg(test)]
167mod tests {
168 use arrow_schema::DataType;
169 use datafusion_common::cast::as_binary_array;
170 use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY};
171
172 use super::*;
173
174 #[test]
175 fn scalars() {
176 let wkb_scalar = create_scalar_storage(Some("POINT (0 1)"), &WKB_GEOMETRY);
177 assert_eq!(&wkb_scalar.data_type(), WKB_GEOMETRY.storage_type());
178 assert!(create_scalar_storage(None, &WKB_GEOMETRY).is_null());
179
180 let wkb_view_scalar = create_scalar_storage(Some("POINT (0 1)"), &WKB_VIEW_GEOMETRY);
181 assert_eq!(
182 &wkb_view_scalar.data_type(),
183 WKB_VIEW_GEOMETRY.storage_type()
184 );
185 assert!(create_scalar_storage(None, &WKB_VIEW_GEOMETRY).is_null());
186 }
187
188 #[test]
189 #[should_panic(expected = "create_scalar_storage not implemented")]
190 fn scalar_storage_invalid() {
191 create_scalar_storage(Some("POINT (0 1)"), &SedonaType::Arrow(DataType::Null));
192 }
193
194 #[test]
195 fn arrays() {
196 let wkb_array = create_array_storage(
197 &[Some("POINT (0 1)"), None, Some("POINT (1 2)")],
198 &WKB_GEOMETRY,
199 );
200 assert_eq!(wkb_array.data_type(), WKB_GEOMETRY.storage_type());
201 assert_eq!(wkb_array.len(), 3);
202 let wkb_binary_array = as_binary_array(&wkb_array).unwrap();
203 assert_eq!(
204 wkb_binary_array
205 .iter()
206 .map(|maybe_item| maybe_item.is_some())
207 .collect::<Vec<bool>>(),
208 vec![true, false, true]
209 );
210
211 let wkb_array = create_array_storage(
212 &[Some("POINT (0 1)"), None, Some("POINT (1 2)")],
213 &WKB_VIEW_GEOMETRY,
214 );
215 assert_eq!(wkb_array.data_type(), WKB_VIEW_GEOMETRY.storage_type());
216 }
217
218 #[test]
219 #[should_panic(expected = "create_array_storage not implemented")]
220 fn array_storage_invalid() {
221 create_array_storage(&[Some("POINT (0 1)")], &SedonaType::Arrow(DataType::Null));
222 }
223}