common_function/scalars/geo/
s2.rs1use std::sync::{Arc, LazyLock};
16
17use common_query::error::InvalidFuncArgsSnafu;
18use datafusion_common::ScalarValue;
19use datafusion_common::arrow::array::{Array, AsArray, StringViewBuilder, UInt64Builder};
20use datafusion_common::arrow::datatypes::{DataType, Float64Type};
21use datafusion_expr::{ColumnarValue, ScalarFunctionArgs, Signature, TypeSignature, Volatility};
22use derive_more::Display;
23use s2::cellid::{CellID, MAX_LEVEL};
24use s2::latlng::LatLng;
25use snafu::ensure;
26
27use crate::function::{Function, extract_args};
28use crate::helper::INTEGER_TYPES;
29use crate::scalars::geo::helpers;
30use crate::scalars::geo::helpers::ensure_and_coerce;
31
32static CELL_TYPES: LazyLock<Vec<DataType>> =
33 LazyLock::new(|| vec![DataType::Int64, DataType::UInt64]);
34
35static COORDINATE_TYPES: LazyLock<Vec<DataType>> =
36 LazyLock::new(|| vec![DataType::Float32, DataType::Float64]);
37
38static LEVEL_TYPES: &[DataType] = INTEGER_TYPES;
39
40#[derive(Clone, Debug, Display)]
44#[display("{}", self.name())]
45pub(crate) struct S2LatLngToCell {
46 signature: Signature,
47}
48
49impl Default for S2LatLngToCell {
50 fn default() -> Self {
51 let mut signatures = Vec::with_capacity(COORDINATE_TYPES.len());
52 for coord_type in COORDINATE_TYPES.as_slice() {
53 signatures.push(TypeSignature::Exact(vec![
54 coord_type.clone(),
56 coord_type.clone(),
58 ]));
59 }
60 Self {
61 signature: Signature::one_of(signatures, Volatility::Stable),
62 }
63 }
64}
65
66impl Function for S2LatLngToCell {
67 fn name(&self) -> &str {
68 "s2_latlng_to_cell"
69 }
70
71 fn return_type(&self, _: &[DataType]) -> datafusion_common::Result<DataType> {
72 Ok(DataType::UInt64)
73 }
74
75 fn signature(&self) -> &Signature {
76 &self.signature
77 }
78
79 fn invoke_with_args(
80 &self,
81 args: ScalarFunctionArgs,
82 ) -> datafusion_common::Result<ColumnarValue> {
83 let [arg0, arg1] = extract_args(self.name(), &args)?;
84
85 let arg0 = helpers::cast::<Float64Type>(&arg0)?;
86 let lat_vec = arg0.as_primitive::<Float64Type>();
87 let arg1 = helpers::cast::<Float64Type>(&arg1)?;
88 let lon_vec = arg1.as_primitive::<Float64Type>();
89
90 let size = lat_vec.len();
91 let mut builder = UInt64Builder::with_capacity(size);
92
93 for i in 0..size {
94 let lat = lat_vec.is_valid(i).then(|| lat_vec.value(i));
95 let lon = lon_vec.is_valid(i).then(|| lon_vec.value(i));
96
97 let result = match (lat, lon) {
98 (Some(lat), Some(lon)) => {
99 let coord = LatLng::from_degrees(lat, lon);
100 ensure!(
101 coord.is_valid(),
102 InvalidFuncArgsSnafu {
103 err_msg: "The input coordinates are invalid",
104 }
105 );
106 let cellid = CellID::from(coord);
107 let encoded: u64 = cellid.0;
108 Some(encoded)
109 }
110 _ => None,
111 };
112
113 builder.append_option(result);
114 }
115
116 Ok(ColumnarValue::Array(Arc::new(builder.finish())))
117 }
118}
119
120#[derive(Clone, Debug, Display)]
122#[display("{}", self.name())]
123pub(crate) struct S2CellLevel {
124 signature: Signature,
125}
126
127impl Default for S2CellLevel {
128 fn default() -> Self {
129 Self {
130 signature: signature_of_cell(),
131 }
132 }
133}
134
135impl Function for S2CellLevel {
136 fn name(&self) -> &str {
137 "s2_cell_level"
138 }
139
140 fn return_type(&self, _: &[DataType]) -> datafusion_common::Result<DataType> {
141 Ok(DataType::UInt64)
142 }
143
144 fn signature(&self) -> &Signature {
145 &self.signature
146 }
147
148 fn invoke_with_args(
149 &self,
150 args: ScalarFunctionArgs,
151 ) -> datafusion_common::Result<ColumnarValue> {
152 let [cell_vec] = extract_args(self.name(), &args)?;
153
154 let size = cell_vec.len();
155 let mut builder = UInt64Builder::with_capacity(size);
156
157 for i in 0..size {
158 let v = ScalarValue::try_from_array(&cell_vec, i)?;
159 let v = cell_from_value(v).map(|x| x.level());
160
161 builder.append_option(v);
162 }
163
164 Ok(ColumnarValue::Array(Arc::new(builder.finish())))
165 }
166}
167
168#[derive(Clone, Debug, Display)]
170#[display("{}", self.name())]
171pub(crate) struct S2CellToToken {
172 signature: Signature,
173}
174
175impl Default for S2CellToToken {
176 fn default() -> Self {
177 Self {
178 signature: signature_of_cell(),
179 }
180 }
181}
182
183impl Function for S2CellToToken {
184 fn name(&self) -> &str {
185 "s2_cell_to_token"
186 }
187
188 fn return_type(&self, _: &[DataType]) -> datafusion_common::Result<DataType> {
189 Ok(DataType::Utf8View)
190 }
191
192 fn signature(&self) -> &Signature {
193 &self.signature
194 }
195
196 fn invoke_with_args(
197 &self,
198 args: ScalarFunctionArgs,
199 ) -> datafusion_common::Result<ColumnarValue> {
200 let [cell_vec] = extract_args(self.name(), &args)?;
201
202 let size = cell_vec.len();
203 let mut builder = StringViewBuilder::with_capacity(size);
204
205 for i in 0..size {
206 let v = ScalarValue::try_from_array(&cell_vec, i)?;
207 let v = cell_from_value(v).map(|x| x.to_token());
208
209 builder.append_option(v.as_deref());
210 }
211
212 Ok(ColumnarValue::Array(Arc::new(builder.finish())))
213 }
214}
215
216#[derive(Clone, Debug, Display)]
218#[display("{}", self.name())]
219pub(crate) struct S2CellParent {
220 signature: Signature,
221}
222
223impl Default for S2CellParent {
224 fn default() -> Self {
225 Self {
226 signature: signature_of_cell_and_level(),
227 }
228 }
229}
230
231impl Function for S2CellParent {
232 fn name(&self) -> &str {
233 "s2_cell_parent"
234 }
235
236 fn return_type(&self, _: &[DataType]) -> datafusion_common::Result<DataType> {
237 Ok(DataType::UInt64)
238 }
239
240 fn signature(&self) -> &Signature {
241 &self.signature
242 }
243
244 fn invoke_with_args(
245 &self,
246 args: ScalarFunctionArgs,
247 ) -> datafusion_common::Result<ColumnarValue> {
248 let [cell_vec, levels] = extract_args(self.name(), &args)?;
249
250 let size = cell_vec.len();
251 let mut builder = UInt64Builder::with_capacity(size);
252
253 for i in 0..size {
254 let cell = ScalarValue::try_from_array(&cell_vec, i).map(cell_from_value)?;
255 let level = ScalarValue::try_from_array(&levels, i).and_then(value_to_level)?;
256 let result = if let (Some(cell), Some(level)) = (cell, level) {
257 Some(cell.parent(level).0)
258 } else {
259 None
260 };
261
262 builder.append_option(result);
263 }
264
265 Ok(ColumnarValue::Array(Arc::new(builder.finish())))
266 }
267}
268
269fn signature_of_cell() -> Signature {
270 let mut signatures = Vec::with_capacity(CELL_TYPES.len());
271 for cell_type in CELL_TYPES.as_slice() {
272 signatures.push(TypeSignature::Exact(vec![cell_type.clone()]));
273 }
274
275 Signature::one_of(signatures, Volatility::Stable)
276}
277
278fn signature_of_cell_and_level() -> Signature {
279 let mut signatures = Vec::with_capacity(CELL_TYPES.len() * LEVEL_TYPES.len());
280 for cell_type in CELL_TYPES.as_slice() {
281 for level_type in LEVEL_TYPES {
282 signatures.push(TypeSignature::Exact(vec![
283 cell_type.clone(),
284 level_type.clone(),
285 ]));
286 }
287 }
288 Signature::one_of(signatures, Volatility::Stable)
289}
290
291fn cell_from_value(v: ScalarValue) -> Option<CellID> {
292 match v {
293 ScalarValue::Int64(v) => v.map(|x| CellID(x as u64)),
294 ScalarValue::UInt64(v) => v.map(CellID),
295 _ => None,
296 }
297}
298
299fn value_to_level(v: ScalarValue) -> datafusion_common::Result<Option<u64>> {
300 match v {
301 ScalarValue::Int8(Some(v)) => ensure_and_coerce!(v >= 0 && v <= MAX_LEVEL as i8, v as u64),
302 ScalarValue::Int16(Some(v)) => {
303 ensure_and_coerce!(v >= 0 && v <= MAX_LEVEL as i16, v as u64)
304 }
305 ScalarValue::Int32(Some(v)) => {
306 ensure_and_coerce!(v >= 0 && v <= MAX_LEVEL as i32, v as u64)
307 }
308 ScalarValue::Int64(Some(v)) => {
309 ensure_and_coerce!(v >= 0 && v <= MAX_LEVEL as i64, v as u64)
310 }
311 ScalarValue::UInt8(Some(v)) => ensure_and_coerce!(v <= MAX_LEVEL as u8, v as u64),
312 ScalarValue::UInt16(Some(v)) => ensure_and_coerce!(v <= MAX_LEVEL as u16, v as u64),
313 ScalarValue::UInt32(Some(v)) => ensure_and_coerce!(v <= MAX_LEVEL as u32, v as u64),
314 ScalarValue::UInt64(Some(v)) => ensure_and_coerce!(v <= MAX_LEVEL, v),
315 _ => Ok(None),
316 }
317}