1use std::hash::{Hash, Hasher};
8use std::sync::Arc;
9
10use arrow::datatypes::DataType;
11use arrow_array::{Array, ArrayRef, LargeBinaryArray, StringArray};
12use arrow_schema::Field;
13use datafusion_common::{Result, ScalarValue};
14use datafusion_expr::function::AccumulatorArgs;
15use datafusion_expr::{Accumulator, AggregateUDFImpl, Signature, TypeSignature, Volatility};
16
17use super::json_types;
18
19#[derive(Debug)]
28pub struct JsonAgg {
29 signature: Signature,
30}
31
32impl JsonAgg {
33 #[must_use]
35 pub fn new() -> Self {
36 Self {
37 signature: Signature::new(TypeSignature::Any(1), Volatility::Immutable),
38 }
39 }
40}
41
42impl Default for JsonAgg {
43 fn default() -> Self {
44 Self::new()
45 }
46}
47
48impl PartialEq for JsonAgg {
49 fn eq(&self, _other: &Self) -> bool {
50 true
51 }
52}
53
54impl Eq for JsonAgg {}
55
56impl Hash for JsonAgg {
57 fn hash<H: Hasher>(&self, state: &mut H) {
58 "json_agg".hash(state);
59 }
60}
61
62impl AggregateUDFImpl for JsonAgg {
63 fn as_any(&self) -> &dyn std::any::Any {
64 self
65 }
66
67 fn name(&self) -> &'static str {
68 "json_agg"
69 }
70
71 fn signature(&self) -> &Signature {
72 &self.signature
73 }
74
75 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
76 Ok(DataType::LargeBinary)
77 }
78
79 fn state_fields(
80 &self,
81 _args: datafusion_expr::function::StateFieldsArgs,
82 ) -> Result<Vec<Arc<Field>>> {
83 Ok(vec![Arc::new(Field::new(
85 "json_agg_state",
86 DataType::LargeBinary,
87 true,
88 ))])
89 }
90
91 fn accumulator(&self, _args: AccumulatorArgs<'_>) -> Result<Box<dyn Accumulator>> {
92 Ok(Box::new(JsonAggAccumulator::new()))
93 }
94}
95
96#[derive(Debug)]
100struct JsonAggAccumulator {
101 values: Vec<serde_json::Value>,
102}
103
104impl JsonAggAccumulator {
105 fn new() -> Self {
106 Self { values: Vec::new() }
107 }
108}
109
110impl Accumulator for JsonAggAccumulator {
111 fn update_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
112 let arr = &values[0];
113 for i in 0..arr.len() {
114 if arr.is_null(i) {
115 self.values.push(serde_json::Value::Null);
116 } else {
117 self.values.push(array_value_to_json(arr, i));
118 }
119 }
120 Ok(())
121 }
122
123 fn evaluate(&mut self) -> Result<ScalarValue> {
124 let json_arr = serde_json::Value::Array(self.values.clone());
125 let bytes = json_types::encode_jsonb(&json_arr);
126 Ok(ScalarValue::LargeBinary(Some(bytes)))
127 }
128
129 fn size(&self) -> usize {
130 std::mem::size_of::<Self>()
131 + self.values.capacity() * std::mem::size_of::<serde_json::Value>()
132 }
133
134 fn state(&mut self) -> Result<Vec<ScalarValue>> {
135 let json_arr = serde_json::Value::Array(self.values.clone());
137 let bytes = json_types::encode_jsonb(&json_arr);
138 Ok(vec![ScalarValue::LargeBinary(Some(bytes))])
139 }
140
141 fn merge_batch(&mut self, states: &[ArrayRef]) -> Result<()> {
142 let arr = states[0]
143 .as_any()
144 .downcast_ref::<LargeBinaryArray>()
145 .ok_or_else(|| {
146 datafusion_common::DataFusionError::Internal(
147 "json_agg: merge state must be LargeBinary".into(),
148 )
149 })?;
150 for i in 0..arr.len() {
151 if !arr.is_null(i) {
152 let bytes = arr.value(i);
153 if let Some(json_str) = json_types::jsonb_to_text(bytes) {
155 if let Ok(serde_json::Value::Array(elems)) =
156 serde_json::from_str::<serde_json::Value>(&json_str)
157 {
158 self.values.extend(elems);
159 }
160 }
161 }
162 }
163 Ok(())
164 }
165}
166
167#[derive(Debug)]
176pub struct JsonObjectAgg {
177 signature: Signature,
178}
179
180impl JsonObjectAgg {
181 #[must_use]
183 pub fn new() -> Self {
184 Self {
185 signature: Signature::new(TypeSignature::Any(2), Volatility::Immutable),
186 }
187 }
188}
189
190impl Default for JsonObjectAgg {
191 fn default() -> Self {
192 Self::new()
193 }
194}
195
196impl PartialEq for JsonObjectAgg {
197 fn eq(&self, _other: &Self) -> bool {
198 true
199 }
200}
201
202impl Eq for JsonObjectAgg {}
203
204impl Hash for JsonObjectAgg {
205 fn hash<H: Hasher>(&self, state: &mut H) {
206 "json_object_agg".hash(state);
207 }
208}
209
210impl AggregateUDFImpl for JsonObjectAgg {
211 fn as_any(&self) -> &dyn std::any::Any {
212 self
213 }
214
215 fn name(&self) -> &'static str {
216 "json_object_agg"
217 }
218
219 fn signature(&self) -> &Signature {
220 &self.signature
221 }
222
223 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
224 Ok(DataType::LargeBinary)
225 }
226
227 fn state_fields(
228 &self,
229 _args: datafusion_expr::function::StateFieldsArgs,
230 ) -> Result<Vec<Arc<Field>>> {
231 Ok(vec![Arc::new(Field::new(
232 "json_object_agg_state",
233 DataType::LargeBinary,
234 true,
235 ))])
236 }
237
238 fn accumulator(&self, _args: AccumulatorArgs<'_>) -> Result<Box<dyn Accumulator>> {
239 Ok(Box::new(JsonObjectAggAccumulator::new()))
240 }
241}
242
243#[derive(Debug)]
247struct JsonObjectAggAccumulator {
248 entries: serde_json::Map<String, serde_json::Value>,
249}
250
251impl JsonObjectAggAccumulator {
252 fn new() -> Self {
253 Self {
254 entries: serde_json::Map::new(),
255 }
256 }
257}
258
259impl Accumulator for JsonObjectAggAccumulator {
260 fn update_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
261 let key_arr = &values[0];
262 let val_arr = &values[1];
263
264 for i in 0..key_arr.len() {
265 if key_arr.is_null(i) {
266 continue; }
268 let key = array_value_to_string(key_arr, i)?;
269 let val = if val_arr.is_null(i) {
270 serde_json::Value::Null
271 } else {
272 array_value_to_json(val_arr, i)
273 };
274 self.entries.insert(key, val); }
276 Ok(())
277 }
278
279 fn evaluate(&mut self) -> Result<ScalarValue> {
280 let obj = serde_json::Value::Object(self.entries.clone());
281 let bytes = json_types::encode_jsonb(&obj);
282 Ok(ScalarValue::LargeBinary(Some(bytes)))
283 }
284
285 fn size(&self) -> usize {
286 std::mem::size_of::<Self>() + self.entries.len() * 64 }
288
289 fn state(&mut self) -> Result<Vec<ScalarValue>> {
290 let obj = serde_json::Value::Object(self.entries.clone());
291 let bytes = json_types::encode_jsonb(&obj);
292 Ok(vec![ScalarValue::LargeBinary(Some(bytes))])
293 }
294
295 fn merge_batch(&mut self, states: &[ArrayRef]) -> Result<()> {
296 let arr = states[0]
297 .as_any()
298 .downcast_ref::<LargeBinaryArray>()
299 .ok_or_else(|| {
300 datafusion_common::DataFusionError::Internal(
301 "json_object_agg: merge state must be LargeBinary".into(),
302 )
303 })?;
304 for i in 0..arr.len() {
305 if !arr.is_null(i) {
306 let bytes = arr.value(i);
307 if let Some(json_str) = json_types::jsonb_to_text(bytes) {
308 if let Ok(serde_json::Value::Object(map)) =
309 serde_json::from_str::<serde_json::Value>(&json_str)
310 {
311 for (k, v) in map {
312 self.entries.insert(k, v);
313 }
314 }
315 }
316 }
317 }
318 Ok(())
319 }
320}
321
322fn array_value_to_json(arr: &ArrayRef, row: usize) -> serde_json::Value {
326 if arr.is_null(row) {
327 return serde_json::Value::Null;
328 }
329 if let Some(a) = arr.as_any().downcast_ref::<StringArray>() {
330 return serde_json::Value::String(a.value(row).to_owned());
331 }
332 if let Some(a) = arr.as_any().downcast_ref::<arrow_array::Int64Array>() {
333 return serde_json::Value::Number(a.value(row).into());
334 }
335 if let Some(a) = arr.as_any().downcast_ref::<arrow_array::Int32Array>() {
336 return serde_json::Value::Number(i64::from(a.value(row)).into());
337 }
338 if let Some(a) = arr.as_any().downcast_ref::<arrow_array::Float64Array>() {
339 if let Some(n) = serde_json::Number::from_f64(a.value(row)) {
340 return serde_json::Value::Number(n);
341 }
342 return serde_json::Value::Null;
343 }
344 if let Some(a) = arr.as_any().downcast_ref::<arrow_array::BooleanArray>() {
345 return serde_json::Value::Bool(a.value(row));
346 }
347 let scalar = ScalarValue::try_from_array(arr, row).ok();
349 match scalar {
350 Some(s) => serde_json::Value::String(s.to_string()),
351 None => serde_json::Value::Null,
352 }
353}
354
355fn array_value_to_string(arr: &ArrayRef, row: usize) -> Result<String> {
357 if let Some(a) = arr.as_any().downcast_ref::<StringArray>() {
358 return Ok(a.value(row).to_owned());
359 }
360 let sv = ScalarValue::try_from_array(arr, row)?;
362 Ok(sv.to_string())
363}
364
365#[cfg(test)]
366mod tests {
367 use super::*;
368 use arrow_array::Int64Array;
369
370 fn make_string_array(vals: &[&str]) -> StringArray {
371 StringArray::from(vals.to_vec())
372 }
373
374 #[test]
375 fn test_json_agg_basic() {
376 let mut acc = JsonAggAccumulator::new();
377 let vals = Arc::new(Int64Array::from(vec![1, 2, 3])) as ArrayRef;
378 acc.update_batch(&[vals]).unwrap();
379 let result = acc.evaluate().unwrap();
380 match result {
381 ScalarValue::LargeBinary(Some(bytes)) => {
382 assert_eq!(json_types::jsonb_type_name(&bytes), Some("array"));
383 let e0 = json_types::jsonb_array_get(&bytes, 0).unwrap();
384 assert_eq!(json_types::jsonb_to_text(e0), Some("1".to_owned()));
385 let e2 = json_types::jsonb_array_get(&bytes, 2).unwrap();
386 assert_eq!(json_types::jsonb_to_text(e2), Some("3".to_owned()));
387 }
388 other => panic!("Expected LargeBinary, got {other:?}"),
389 }
390 }
391
392 #[test]
393 fn test_json_agg_strings() {
394 let mut acc = JsonAggAccumulator::new();
395 let vals = Arc::new(make_string_array(&["a", "b", "c"])) as ArrayRef;
396 acc.update_batch(&[vals]).unwrap();
397 let result = acc.evaluate().unwrap();
398 match result {
399 ScalarValue::LargeBinary(Some(bytes)) => {
400 let e0 = json_types::jsonb_array_get(&bytes, 0).unwrap();
401 assert_eq!(json_types::jsonb_to_text(e0), Some("a".to_owned()));
402 }
403 other => panic!("Expected LargeBinary, got {other:?}"),
404 }
405 }
406
407 #[test]
408 fn test_json_agg_multiple_batches() {
409 let mut acc = JsonAggAccumulator::new();
410 let v1 = Arc::new(Int64Array::from(vec![1, 2])) as ArrayRef;
411 let v2 = Arc::new(Int64Array::from(vec![3])) as ArrayRef;
412 acc.update_batch(&[v1]).unwrap();
413 acc.update_batch(&[v2]).unwrap();
414 let result = acc.evaluate().unwrap();
415 match result {
416 ScalarValue::LargeBinary(Some(bytes)) => {
417 let text = json_types::jsonb_to_text(&bytes).unwrap();
419 assert_eq!(text, "[1,2,3]");
420 }
421 other => panic!("Expected LargeBinary, got {other:?}"),
422 }
423 }
424
425 #[test]
426 fn test_json_object_agg_basic() {
427 let mut acc = JsonObjectAggAccumulator::new();
428 let keys = Arc::new(make_string_array(&["a", "b", "c"])) as ArrayRef;
429 let vals = Arc::new(Int64Array::from(vec![1, 2, 3])) as ArrayRef;
430 acc.update_batch(&[keys, vals]).unwrap();
431 let result = acc.evaluate().unwrap();
432 match result {
433 ScalarValue::LargeBinary(Some(bytes)) => {
434 assert_eq!(json_types::jsonb_type_name(&bytes), Some("object"));
435 let a = json_types::jsonb_get_field(&bytes, "a").unwrap();
436 assert_eq!(json_types::jsonb_to_text(a), Some("1".to_owned()));
437 let c = json_types::jsonb_get_field(&bytes, "c").unwrap();
438 assert_eq!(json_types::jsonb_to_text(c), Some("3".to_owned()));
439 }
440 other => panic!("Expected LargeBinary, got {other:?}"),
441 }
442 }
443
444 #[test]
445 fn test_json_object_agg_last_value_wins() {
446 let mut acc = JsonObjectAggAccumulator::new();
447 let keys = Arc::new(make_string_array(&["a", "a"])) as ArrayRef;
448 let vals = Arc::new(Int64Array::from(vec![1, 2])) as ArrayRef;
449 acc.update_batch(&[keys, vals]).unwrap();
450 let result = acc.evaluate().unwrap();
451 match result {
452 ScalarValue::LargeBinary(Some(bytes)) => {
453 let a = json_types::jsonb_get_field(&bytes, "a").unwrap();
454 assert_eq!(json_types::jsonb_to_text(a), Some("2".to_owned()));
455 }
456 other => panic!("Expected LargeBinary, got {other:?}"),
457 }
458 }
459
460 #[test]
461 fn test_json_agg_state_merge() {
462 let mut acc1 = JsonAggAccumulator::new();
463 let v1 = Arc::new(Int64Array::from(vec![1, 2])) as ArrayRef;
464 acc1.update_batch(&[v1]).unwrap();
465 let state = acc1.state().unwrap();
466
467 let mut acc2 = JsonAggAccumulator::new();
468 let v2 = Arc::new(Int64Array::from(vec![3])) as ArrayRef;
469 acc2.update_batch(&[v2]).unwrap();
470
471 let state_arr: ArrayRef = match &state[0] {
473 ScalarValue::LargeBinary(Some(b)) => {
474 Arc::new(LargeBinaryArray::from_iter_values(vec![b.as_slice()]))
475 }
476 _ => panic!("expected LargeBinary state"),
477 };
478 acc2.merge_batch(&[state_arr]).unwrap();
479
480 let result = acc2.evaluate().unwrap();
481 match result {
482 ScalarValue::LargeBinary(Some(bytes)) => {
483 let text = json_types::jsonb_to_text(&bytes).unwrap();
484 assert_eq!(text, "[3,1,2]");
485 }
486 other => panic!("Expected LargeBinary, got {other:?}"),
487 }
488 }
489
490 #[test]
491 fn test_udaf_registration() {
492 let json_agg = datafusion_expr::AggregateUDF::new_from_impl(JsonAgg::new());
493 assert_eq!(json_agg.name(), "json_agg");
494
495 let json_obj_agg = datafusion_expr::AggregateUDF::new_from_impl(JsonObjectAgg::new());
496 assert_eq!(json_obj_agg.name(), "json_object_agg");
497 }
498}