laminar_sql/datafusion/json_udf/
predicates.rs1use std::hash::{Hash, Hasher};
4use std::sync::Arc;
5
6use arrow::datatypes::DataType;
7use arrow_array::{Array, BooleanArray, LargeBinaryArray, ListArray, StringArray};
8use datafusion_common::Result;
9use datafusion_expr::{
10 ColumnarValue, ScalarFunctionArgs, ScalarUDFImpl, Signature, TypeSignature, Volatility,
11};
12
13use super::{expand_args, json_types};
14
15#[derive(Debug)]
17pub struct JsonbExists {
18 signature: Signature,
19}
20
21impl JsonbExists {
22 #[must_use]
24 pub fn new() -> Self {
25 Self {
26 signature: Signature::new(
27 TypeSignature::Exact(vec![DataType::LargeBinary, DataType::Utf8]),
28 Volatility::Immutable,
29 ),
30 }
31 }
32}
33
34impl Default for JsonbExists {
35 fn default() -> Self {
36 Self::new()
37 }
38}
39
40impl PartialEq for JsonbExists {
41 fn eq(&self, _other: &Self) -> bool {
42 true
43 }
44}
45
46impl Eq for JsonbExists {}
47
48impl Hash for JsonbExists {
49 fn hash<H: Hasher>(&self, state: &mut H) {
50 "jsonb_exists".hash(state);
51 }
52}
53
54impl ScalarUDFImpl for JsonbExists {
55 fn as_any(&self) -> &dyn std::any::Any {
56 self
57 }
58
59 fn name(&self) -> &'static str {
60 "jsonb_exists"
61 }
62
63 fn signature(&self) -> &Signature {
64 &self.signature
65 }
66
67 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
68 Ok(DataType::Boolean)
69 }
70
71 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
72 let expanded = expand_args(&args.args)?;
73 let jsonb_arr = expanded[0]
74 .as_any()
75 .downcast_ref::<LargeBinaryArray>()
76 .ok_or_else(|| {
77 datafusion_common::DataFusionError::Internal(
78 "jsonb_exists: first arg must be LargeBinary".into(),
79 )
80 })?;
81 let key_arr = expanded[1]
82 .as_any()
83 .downcast_ref::<StringArray>()
84 .ok_or_else(|| {
85 datafusion_common::DataFusionError::Internal(
86 "jsonb_exists: second arg must be Utf8".into(),
87 )
88 })?;
89
90 let result: BooleanArray = (0..jsonb_arr.len())
91 .map(|i| {
92 if jsonb_arr.is_null(i) || key_arr.is_null(i) {
93 None
94 } else {
95 Some(json_types::jsonb_has_key(
96 jsonb_arr.value(i),
97 key_arr.value(i),
98 ))
99 }
100 })
101 .collect();
102 Ok(ColumnarValue::Array(Arc::new(result)))
103 }
104}
105
106#[derive(Debug)]
115pub struct JsonbExistsAny {
116 signature: Signature,
117}
118
119impl JsonbExistsAny {
120 #[must_use]
122 pub fn new() -> Self {
123 Self {
124 signature: Signature::new(
125 TypeSignature::Exact(vec![
126 DataType::LargeBinary,
127 DataType::List(Arc::new(arrow_schema::Field::new(
128 "item",
129 DataType::Utf8,
130 true,
131 ))),
132 ]),
133 Volatility::Immutable,
134 ),
135 }
136 }
137}
138
139impl Default for JsonbExistsAny {
140 fn default() -> Self {
141 Self::new()
142 }
143}
144
145impl PartialEq for JsonbExistsAny {
146 fn eq(&self, _other: &Self) -> bool {
147 true
148 }
149}
150
151impl Eq for JsonbExistsAny {}
152
153impl Hash for JsonbExistsAny {
154 fn hash<H: Hasher>(&self, state: &mut H) {
155 "jsonb_exists_any".hash(state);
156 }
157}
158
159impl ScalarUDFImpl for JsonbExistsAny {
160 fn as_any(&self) -> &dyn std::any::Any {
161 self
162 }
163
164 fn name(&self) -> &'static str {
165 "jsonb_exists_any"
166 }
167
168 fn signature(&self) -> &Signature {
169 &self.signature
170 }
171
172 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
173 Ok(DataType::Boolean)
174 }
175
176 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
177 let expanded = expand_args(&args.args)?;
178 let jsonb_arr = expanded[0]
179 .as_any()
180 .downcast_ref::<LargeBinaryArray>()
181 .ok_or_else(|| {
182 datafusion_common::DataFusionError::Internal(
183 "jsonb_exists_any: first arg must be LargeBinary".into(),
184 )
185 })?;
186 let keys_arr = expanded[1]
187 .as_any()
188 .downcast_ref::<ListArray>()
189 .ok_or_else(|| {
190 datafusion_common::DataFusionError::Internal(
191 "jsonb_exists_any: second arg must be List<Utf8>".into(),
192 )
193 })?;
194
195 let result: BooleanArray =
196 (0..jsonb_arr.len())
197 .map(|i| {
198 if jsonb_arr.is_null(i) || keys_arr.is_null(i) {
199 return None;
200 }
201 let jsonb = jsonb_arr.value(i);
202 let keys_list = keys_arr.value(i);
203 let keys = keys_list.as_any().downcast_ref::<StringArray>()?;
204 Some((0..keys.len()).any(|k| {
205 !keys.is_null(k) && json_types::jsonb_has_key(jsonb, keys.value(k))
206 }))
207 })
208 .collect();
209 Ok(ColumnarValue::Array(Arc::new(result)))
210 }
211}
212
213#[derive(Debug)]
222pub struct JsonbExistsAll {
223 signature: Signature,
224}
225
226impl JsonbExistsAll {
227 #[must_use]
229 pub fn new() -> Self {
230 Self {
231 signature: Signature::new(
232 TypeSignature::Exact(vec![
233 DataType::LargeBinary,
234 DataType::List(Arc::new(arrow_schema::Field::new(
235 "item",
236 DataType::Utf8,
237 true,
238 ))),
239 ]),
240 Volatility::Immutable,
241 ),
242 }
243 }
244}
245
246impl Default for JsonbExistsAll {
247 fn default() -> Self {
248 Self::new()
249 }
250}
251
252impl PartialEq for JsonbExistsAll {
253 fn eq(&self, _other: &Self) -> bool {
254 true
255 }
256}
257
258impl Eq for JsonbExistsAll {}
259
260impl Hash for JsonbExistsAll {
261 fn hash<H: Hasher>(&self, state: &mut H) {
262 "jsonb_exists_all".hash(state);
263 }
264}
265
266impl ScalarUDFImpl for JsonbExistsAll {
267 fn as_any(&self) -> &dyn std::any::Any {
268 self
269 }
270
271 fn name(&self) -> &'static str {
272 "jsonb_exists_all"
273 }
274
275 fn signature(&self) -> &Signature {
276 &self.signature
277 }
278
279 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
280 Ok(DataType::Boolean)
281 }
282
283 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
284 let expanded = expand_args(&args.args)?;
285 let jsonb_arr = expanded[0]
286 .as_any()
287 .downcast_ref::<LargeBinaryArray>()
288 .ok_or_else(|| {
289 datafusion_common::DataFusionError::Internal(
290 "jsonb_exists_all: first arg must be LargeBinary".into(),
291 )
292 })?;
293 let keys_arr = expanded[1]
294 .as_any()
295 .downcast_ref::<ListArray>()
296 .ok_or_else(|| {
297 datafusion_common::DataFusionError::Internal(
298 "jsonb_exists_all: second arg must be List<Utf8>".into(),
299 )
300 })?;
301
302 let result: BooleanArray =
303 (0..jsonb_arr.len())
304 .map(|i| {
305 if jsonb_arr.is_null(i) || keys_arr.is_null(i) {
306 return None;
307 }
308 let jsonb = jsonb_arr.value(i);
309 let keys_list = keys_arr.value(i);
310 let keys = keys_list.as_any().downcast_ref::<StringArray>()?;
311 Some((0..keys.len()).all(|k| {
312 !keys.is_null(k) && json_types::jsonb_has_key(jsonb, keys.value(k))
313 }))
314 })
315 .collect();
316 Ok(ColumnarValue::Array(Arc::new(result)))
317 }
318}
319
320#[derive(Debug)]
329pub struct JsonbContains {
330 signature: Signature,
331}
332
333impl JsonbContains {
334 #[must_use]
336 pub fn new() -> Self {
337 Self {
338 signature: Signature::new(
339 TypeSignature::Exact(vec![DataType::LargeBinary, DataType::LargeBinary]),
340 Volatility::Immutable,
341 ),
342 }
343 }
344}
345
346impl Default for JsonbContains {
347 fn default() -> Self {
348 Self::new()
349 }
350}
351
352impl PartialEq for JsonbContains {
353 fn eq(&self, _other: &Self) -> bool {
354 true
355 }
356}
357
358impl Eq for JsonbContains {}
359
360impl Hash for JsonbContains {
361 fn hash<H: Hasher>(&self, state: &mut H) {
362 "jsonb_contains".hash(state);
363 }
364}
365
366impl ScalarUDFImpl for JsonbContains {
367 fn as_any(&self) -> &dyn std::any::Any {
368 self
369 }
370
371 fn name(&self) -> &'static str {
372 "jsonb_contains"
373 }
374
375 fn signature(&self) -> &Signature {
376 &self.signature
377 }
378
379 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
380 Ok(DataType::Boolean)
381 }
382
383 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
384 let expanded = expand_args(&args.args)?;
385 let left_arr = expanded[0]
386 .as_any()
387 .downcast_ref::<LargeBinaryArray>()
388 .ok_or_else(|| {
389 datafusion_common::DataFusionError::Internal(
390 "jsonb_contains: first arg must be LargeBinary".into(),
391 )
392 })?;
393 let right_arr = expanded[1]
394 .as_any()
395 .downcast_ref::<LargeBinaryArray>()
396 .ok_or_else(|| {
397 datafusion_common::DataFusionError::Internal(
398 "jsonb_contains: second arg must be LargeBinary".into(),
399 )
400 })?;
401
402 let result: BooleanArray = (0..left_arr.len())
403 .map(|i| {
404 if left_arr.is_null(i) || right_arr.is_null(i) {
405 None
406 } else {
407 json_types::jsonb_contains(left_arr.value(i), right_arr.value(i))
408 }
409 })
410 .collect();
411 Ok(ColumnarValue::Array(Arc::new(result)))
412 }
413}
414
415#[derive(Debug)]
424pub struct JsonbContainedBy {
425 signature: Signature,
426}
427
428impl JsonbContainedBy {
429 #[must_use]
431 pub fn new() -> Self {
432 Self {
433 signature: Signature::new(
434 TypeSignature::Exact(vec![DataType::LargeBinary, DataType::LargeBinary]),
435 Volatility::Immutable,
436 ),
437 }
438 }
439}
440
441impl Default for JsonbContainedBy {
442 fn default() -> Self {
443 Self::new()
444 }
445}
446
447impl PartialEq for JsonbContainedBy {
448 fn eq(&self, _other: &Self) -> bool {
449 true
450 }
451}
452
453impl Eq for JsonbContainedBy {}
454
455impl Hash for JsonbContainedBy {
456 fn hash<H: Hasher>(&self, state: &mut H) {
457 "jsonb_contained_by".hash(state);
458 }
459}
460
461impl ScalarUDFImpl for JsonbContainedBy {
462 fn as_any(&self) -> &dyn std::any::Any {
463 self
464 }
465
466 fn name(&self) -> &'static str {
467 "jsonb_contained_by"
468 }
469
470 fn signature(&self) -> &Signature {
471 &self.signature
472 }
473
474 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
475 Ok(DataType::Boolean)
476 }
477
478 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
479 let expanded = expand_args(&args.args)?;
480 let left_arr = expanded[0]
481 .as_any()
482 .downcast_ref::<LargeBinaryArray>()
483 .ok_or_else(|| {
484 datafusion_common::DataFusionError::Internal(
485 "jsonb_contained_by: first arg must be LargeBinary".into(),
486 )
487 })?;
488 let right_arr = expanded[1]
489 .as_any()
490 .downcast_ref::<LargeBinaryArray>()
491 .ok_or_else(|| {
492 datafusion_common::DataFusionError::Internal(
493 "jsonb_contained_by: second arg must be LargeBinary".into(),
494 )
495 })?;
496
497 let result: BooleanArray = (0..left_arr.len())
499 .map(|i| {
500 if left_arr.is_null(i) || right_arr.is_null(i) {
501 None
502 } else {
503 json_types::jsonb_contains(right_arr.value(i), left_arr.value(i))
504 }
505 })
506 .collect();
507 Ok(ColumnarValue::Array(Arc::new(result)))
508 }
509}