1use anyhow::{Result, anyhow};
10use arrow_array::{
11 Array, BinaryArray, BooleanArray, Date32Array, FixedSizeListArray, Float32Array, Float64Array,
12 Int32Array, Int64Array, LargeBinaryArray, ListArray, StringArray, StructArray,
13 Time64NanosecondArray, TimestampNanosecondArray, UInt32Array,
14};
15use serde_json::Value;
16use uni_common::{DataType, TemporalValue};
17use uni_crdt::Crdt;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
21pub enum CrdtDecodeMode {
22 #[default]
24 Strict,
25 Lenient,
27}
28
29pub const MAX_DECODE_DEPTH: usize = 32;
32
33pub fn value_from_column(
44 col: &dyn Array,
45 data_type: &DataType,
46 row: usize,
47 crdt_mode: CrdtDecodeMode,
48) -> Result<Value> {
49 value_from_column_inner(col, data_type, row, crdt_mode, 0)
50}
51
52fn value_from_column_inner(
54 col: &dyn Array,
55 data_type: &DataType,
56 row: usize,
57 crdt_mode: CrdtDecodeMode,
58 depth: usize,
59) -> Result<Value> {
60 if depth > MAX_DECODE_DEPTH {
61 return Err(anyhow!("decode depth exceeded (max {})", MAX_DECODE_DEPTH));
62 }
63 match data_type {
64 DataType::String => {
65 let s = col
66 .as_any()
67 .downcast_ref::<StringArray>()
68 .ok_or_else(|| anyhow!("Invalid string col"))?
69 .value(row);
70 Ok(Value::String(s.to_string()))
71 }
72 DataType::Int32 => {
73 let v = col
74 .as_any()
75 .downcast_ref::<Int32Array>()
76 .ok_or_else(|| anyhow!("Invalid int32 col"))?
77 .value(row);
78 Ok(serde_json::json!(v))
79 }
80 DataType::Int64 => {
81 let v = col
82 .as_any()
83 .downcast_ref::<Int64Array>()
84 .ok_or_else(|| anyhow!("Invalid int64 col"))?
85 .value(row);
86 Ok(serde_json::json!(v))
87 }
88 DataType::Float32 => {
89 let v = col
90 .as_any()
91 .downcast_ref::<Float32Array>()
92 .ok_or_else(|| anyhow!("Invalid float32 col"))?
93 .value(row);
94 Ok(serde_json::json!(v))
95 }
96 DataType::Float64 => {
97 let v = col
98 .as_any()
99 .downcast_ref::<Float64Array>()
100 .ok_or_else(|| anyhow!("Invalid float64 col"))?
101 .value(row);
102 Ok(serde_json::json!(v))
103 }
104 DataType::Bool => {
105 let v = col
106 .as_any()
107 .downcast_ref::<BooleanArray>()
108 .ok_or_else(|| anyhow!("Invalid bool col"))?
109 .value(row);
110 Ok(serde_json::json!(v))
111 }
112 DataType::Vector { .. } => {
113 let list_arr = col
114 .as_any()
115 .downcast_ref::<FixedSizeListArray>()
116 .ok_or_else(|| anyhow!("Invalid fixed list col for vector"))?;
117 let values = list_arr.value(row);
118 let float_values = values
119 .as_any()
120 .downcast_ref::<Float32Array>()
121 .ok_or_else(|| anyhow!("Invalid float32 inner col for vector"))?;
122
123 let vec: Vec<f32> = (0..float_values.len())
124 .map(|i| float_values.value(i))
125 .collect();
126 Ok(serde_json::json!(vec))
127 }
128 DataType::SparseVector { .. } => {
129 let struct_arr = col
135 .as_any()
136 .downcast_ref::<StructArray>()
137 .ok_or_else(|| anyhow!("Invalid struct col for sparse vector"))?;
138 if struct_arr.is_null(row) {
139 return Ok(Value::Null);
140 }
141 let indices_list = struct_arr
142 .column_by_name("indices")
143 .and_then(|c| c.as_any().downcast_ref::<ListArray>())
144 .ok_or_else(|| anyhow!("sparse vector missing list column 'indices'"))?;
145 let values_list = struct_arr
146 .column_by_name("values")
147 .and_then(|c| c.as_any().downcast_ref::<ListArray>())
148 .ok_or_else(|| anyhow!("sparse vector missing list column 'values'"))?;
149 let idx_vals = indices_list.value(row);
150 let idx_arr = idx_vals
151 .as_any()
152 .downcast_ref::<UInt32Array>()
153 .ok_or_else(|| anyhow!("sparse 'indices' inner not UInt32"))?;
154 let w_vals = values_list.value(row);
155 let w_arr = w_vals
156 .as_any()
157 .downcast_ref::<Float32Array>()
158 .ok_or_else(|| anyhow!("sparse 'values' inner not Float32"))?;
159 let indices: Vec<Value> = (0..idx_arr.len())
160 .map(|i| serde_json::json!(idx_arr.value(i)))
161 .collect();
162 let values: Vec<Value> = (0..w_arr.len())
163 .map(|i| serde_json::json!(w_arr.value(i)))
164 .collect();
165 let mut map = serde_json::Map::new();
166 map.insert("indices".to_string(), Value::Array(indices));
167 map.insert("values".to_string(), Value::Array(values));
168 Ok(Value::Object(map))
169 }
170 DataType::CypherValue => {
171 let bytes = col
172 .as_any()
173 .downcast_ref::<LargeBinaryArray>()
174 .ok_or_else(|| anyhow!("Invalid large binary col for CypherValue"))?
175 .value(row);
176 if bytes.is_empty() {
177 return Ok(Value::Null);
178 }
179 let uni_val = uni_common::cypher_value_codec::decode(bytes)
180 .map_err(|e| anyhow!("CypherValue decode error: {}", e))?;
181 Ok(uni_val.into())
183 }
184 DataType::Bytes => {
185 let arr = col
186 .as_any()
187 .downcast_ref::<LargeBinaryArray>()
188 .ok_or_else(|| anyhow!("Invalid large binary col for Bytes"))?;
189 if arr.is_null(row) {
190 return Ok(Value::Null);
191 }
192 let bytes = arr.value(row);
194 Ok(Value::Array(
195 bytes.iter().map(|b| serde_json::json!(*b)).collect(),
196 ))
197 }
198 DataType::Crdt(_) => {
199 let bytes = col
200 .as_any()
201 .downcast_ref::<BinaryArray>()
202 .ok_or_else(|| anyhow!("Invalid binary col for CRDT"))?
203 .value(row);
204
205 match crdt_mode {
206 CrdtDecodeMode::Strict => {
207 let crdt = Crdt::from_msgpack(bytes)
208 .map_err(|e| anyhow!("CRDT decode error: {}", e))?;
209 Ok(serde_json::to_value(crdt)?)
210 }
211 CrdtDecodeMode::Lenient => {
212 let crdt = Crdt::from_msgpack(bytes).unwrap_or_else(|e| {
213 log::warn!("Failed to deserialize CRDT: {}", e);
214 Crdt::GCounter(uni_crdt::GCounter::new())
215 });
216 Ok(serde_json::to_value(crdt).unwrap_or(Value::Null))
217 }
218 }
219 }
220 DataType::List(inner) => {
221 let list_arr = col
222 .as_any()
223 .downcast_ref::<ListArray>()
224 .ok_or_else(|| anyhow!("Invalid list col"))?;
225 if list_arr.is_null(row) {
226 return Ok(Value::Null);
227 }
228 let values = list_arr.value(row);
229 let mut vec = Vec::with_capacity(values.len());
230 for i in 0..values.len() {
231 vec.push(value_from_column_inner(
232 values.as_ref(),
233 inner,
234 i,
235 crdt_mode,
236 depth + 1,
237 )?);
238 }
239 Ok(Value::Array(vec))
240 }
241 DataType::Map(_, _) => {
242 let list_arr = col
243 .as_any()
244 .downcast_ref::<ListArray>()
245 .ok_or_else(|| anyhow!("Invalid map (list) col"))?;
246 if list_arr.is_null(row) {
247 return Ok(Value::Null);
248 }
249 let struct_arr = list_arr.value(row);
256 let uni_map = super::arrow_convert::try_reconstruct_map(&struct_arr)
257 .ok_or_else(|| anyhow!("Invalid struct array inner for map"))?;
258 let mut map = serde_json::Map::with_capacity(uni_map.len());
259 for (k, v) in uni_map {
260 map.insert(
261 k,
262 serde_json::to_value(&v).unwrap_or(serde_json::Value::Null),
263 );
264 }
265 Ok(Value::Object(map))
266 }
267 DataType::Date => {
268 let arr = col
269 .as_any()
270 .downcast_ref::<Date32Array>()
271 .ok_or_else(|| anyhow!("Invalid date32 col"))?;
272 if arr.is_null(row) {
273 return Ok(Value::Null);
274 }
275 let days = arr.value(row);
276 let epoch = chrono::NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
277 if let Some(date) = epoch.checked_add_signed(chrono::Duration::days(days as i64)) {
278 Ok(Value::String(date.format("%Y-%m-%d").to_string()))
279 } else {
280 Ok(Value::Null)
281 }
282 }
283 DataType::Time => {
284 if let Some(struct_arr) = col.as_any().downcast_ref::<StructArray>()
286 && let (Some(nanos_col), Some(offset_col)) = (
287 struct_arr.column_by_name("nanos_since_midnight"),
288 struct_arr.column_by_name("offset_seconds"),
289 )
290 && let (Some(nanos_arr), Some(offset_arr)) = (
291 nanos_col.as_any().downcast_ref::<Time64NanosecondArray>(),
292 offset_col.as_any().downcast_ref::<Int32Array>(),
293 )
294 {
295 if nanos_arr.is_null(row) {
296 return Ok(Value::Null);
297 }
298 let tv = if offset_arr.is_null(row) {
299 TemporalValue::LocalTime {
300 nanos_since_midnight: nanos_arr.value(row),
301 }
302 } else {
303 TemporalValue::Time {
304 nanos_since_midnight: nanos_arr.value(row),
305 offset_seconds: offset_arr.value(row),
306 }
307 };
308 return Ok(Value::String(tv.to_string()));
309 }
310
311 let arr = col
313 .as_any()
314 .downcast_ref::<Time64NanosecondArray>()
315 .ok_or_else(|| anyhow!("Invalid time64 col"))?;
316 if arr.is_null(row) {
317 return Ok(Value::Null);
318 }
319 let tv = TemporalValue::Time {
320 nanos_since_midnight: arr.value(row),
321 offset_seconds: 0,
322 };
323 Ok(Value::String(tv.to_string()))
324 }
325 DataType::Duration => {
326 let arr = col
328 .as_any()
329 .downcast_ref::<LargeBinaryArray>()
330 .ok_or_else(|| anyhow!("Invalid duration col (expected LargeBinary)"))?;
331 if arr.is_null(row) {
332 return Ok(Value::Null);
333 }
334 let bytes = arr.value(row);
335 let uni_val = uni_common::cypher_value_codec::decode(bytes)
336 .map_err(|e| anyhow!("Failed to decode duration: {}", e))?;
337 if let uni_common::Value::Temporal(uni_common::TemporalValue::Duration {
339 months,
340 days,
341 nanos,
342 }) = &uni_val
343 {
344 let tv = TemporalValue::Duration {
345 months: *months,
346 days: *days,
347 nanos: *nanos,
348 };
349 Ok(Value::String(tv.to_string()))
350 } else {
351 Ok(serde_json::json!(uni_val.to_string()))
352 }
353 }
354 DataType::DateTime | DataType::Timestamp => {
355 if let Some(struct_arr) = col.as_any().downcast_ref::<StructArray>()
357 && let (Some(nanos_col), Some(offset_col), Some(tz_col)) = (
358 struct_arr.column_by_name("nanos_since_epoch"),
359 struct_arr.column_by_name("offset_seconds"),
360 struct_arr.column_by_name("timezone_name"),
361 )
362 && let (Some(nanos_arr), Some(offset_arr), Some(tz_arr)) = (
363 nanos_col
364 .as_any()
365 .downcast_ref::<TimestampNanosecondArray>(),
366 offset_col.as_any().downcast_ref::<Int32Array>(),
367 tz_col.as_any().downcast_ref::<StringArray>(),
368 )
369 {
370 if nanos_arr.is_null(row) {
371 return Ok(Value::Null);
372 }
373 let tv = if offset_arr.is_null(row) {
374 TemporalValue::LocalDateTime {
375 nanos_since_epoch: nanos_arr.value(row),
376 }
377 } else {
378 let timezone_name =
379 (!tz_arr.is_null(row)).then(|| tz_arr.value(row).to_string());
380 TemporalValue::DateTime {
381 nanos_since_epoch: nanos_arr.value(row),
382 offset_seconds: offset_arr.value(row),
383 timezone_name,
384 }
385 };
386 return Ok(Value::String(tv.to_string()));
387 }
388
389 let arr = col
391 .as_any()
392 .downcast_ref::<TimestampNanosecondArray>()
393 .ok_or_else(|| anyhow!("Invalid timestamp col"))?;
394 if arr.is_null(row) {
395 return Ok(Value::Null);
396 }
397 let tv = TemporalValue::DateTime {
398 nanos_since_epoch: arr.value(row),
399 offset_seconds: 0,
400 timezone_name: arr.timezone().map(|s| s.to_string()),
401 };
402 Ok(Value::String(tv.to_string()))
403 }
404 DataType::Point(_) => {
409 let v = super::arrow_convert::arrow_to_value(col, row, Some(data_type));
410 Ok(serde_json::to_value(&v).unwrap_or(Value::Null))
411 }
412 _ => Ok(Value::Null),
413 }
414}
415
416pub fn decode_column_value(
422 col: &dyn Array,
423 data_type: &DataType,
424 row: usize,
425 crdt_mode: CrdtDecodeMode,
426) -> anyhow::Result<uni_common::Value> {
427 match data_type {
428 DataType::DateTime
429 | DataType::Timestamp
430 | DataType::Date
431 | DataType::Time
432 | DataType::Btic
433 | DataType::Bytes
434 | DataType::SparseVector { .. }
438 | DataType::BinaryVector { .. }
442 | DataType::Point(_)
446 | DataType::Map(_, _) => Ok(super::arrow_convert::arrow_to_value(
451 col,
452 row,
453 Some(data_type),
454 )),
455 _ => value_from_column(col, data_type, row, crdt_mode).map(uni_common::Value::from),
456 }
457}
458
459#[cfg(test)]
460mod tests {
461 use super::*;
462 use arrow_array::builder::{Int64Builder, StringBuilder};
463
464 #[test]
465 fn test_decode_string() {
466 let mut builder = StringBuilder::new();
467 builder.append_value("hello");
468 builder.append_value("world");
469 let array = builder.finish();
470
471 let val = value_from_column(&array, &DataType::String, 0, CrdtDecodeMode::Strict).unwrap();
472 assert_eq!(val, Value::String("hello".to_string()));
473
474 let val = value_from_column(&array, &DataType::String, 1, CrdtDecodeMode::Strict).unwrap();
475 assert_eq!(val, Value::String("world".to_string()));
476 }
477
478 #[test]
479 fn test_decode_int64() {
480 let mut builder = Int64Builder::new();
481 builder.append_value(42);
482 builder.append_value(-100);
483 let array = builder.finish();
484
485 let val = value_from_column(&array, &DataType::Int64, 0, CrdtDecodeMode::Strict).unwrap();
486 assert_eq!(val, serde_json::json!(42));
487
488 let val = value_from_column(&array, &DataType::Int64, 1, CrdtDecodeMode::Strict).unwrap();
489 assert_eq!(val, serde_json::json!(-100));
490 }
491
492 #[test]
493 fn test_decode_json() {
494 use arrow_array::builder::LargeBinaryBuilder;
495
496 let mut builder = LargeBinaryBuilder::new();
498
499 let obj_cv = {
500 let val: uni_common::Value = serde_json::json!({"key": "value"}).into();
501 uni_common::cypher_value_codec::encode(&val)
502 };
503 builder.append_value(&obj_cv);
504
505 let null_cv = uni_common::cypher_value_codec::encode(&uni_common::Value::Null);
506 builder.append_value(&null_cv);
507
508 let text_cv = uni_common::cypher_value_codec::encode(&uni_common::Value::String(
509 "plain text".to_string(),
510 ));
511 builder.append_value(&text_cv);
512
513 let array = builder.finish();
514
515 let val =
516 value_from_column(&array, &DataType::CypherValue, 0, CrdtDecodeMode::Strict).unwrap();
517 assert_eq!(val, serde_json::json!({"key": "value"}));
518
519 let val =
520 value_from_column(&array, &DataType::CypherValue, 1, CrdtDecodeMode::Strict).unwrap();
521 assert_eq!(val, Value::Null);
522
523 let val =
524 value_from_column(&array, &DataType::CypherValue, 2, CrdtDecodeMode::Strict).unwrap();
525 assert_eq!(val, Value::String("plain text".to_string()));
526 }
527
528 #[test]
529 fn test_decode_bool() {
530 use arrow_array::builder::BooleanBuilder;
531 let mut builder = BooleanBuilder::new();
532 builder.append_value(true);
533 builder.append_value(false);
534 let array = builder.finish();
535
536 let val = value_from_column(&array, &DataType::Bool, 0, CrdtDecodeMode::Strict).unwrap();
537 assert_eq!(val, serde_json::json!(true));
538
539 let val = value_from_column(&array, &DataType::Bool, 1, CrdtDecodeMode::Strict).unwrap();
540 assert_eq!(val, serde_json::json!(false));
541 }
542
543 #[test]
544 fn test_decode_float64() {
545 use arrow_array::builder::Float64Builder;
546 let mut builder = Float64Builder::new();
547 builder.append_value(3.25);
548 builder.append_value(-0.5);
549 let array = builder.finish();
550
551 let val = value_from_column(&array, &DataType::Float64, 0, CrdtDecodeMode::Strict).unwrap();
552 assert_eq!(val, serde_json::json!(3.25));
553
554 let val = value_from_column(&array, &DataType::Float64, 1, CrdtDecodeMode::Strict).unwrap();
555 assert_eq!(val, serde_json::json!(-0.5));
556 }
557
558 #[test]
559 fn test_decode_int32() {
560 use arrow_array::builder::Int32Builder;
561 let mut builder = Int32Builder::new();
562 builder.append_value(42);
563 builder.append_value(-1);
564 let array = builder.finish();
565
566 let val = value_from_column(&array, &DataType::Int32, 0, CrdtDecodeMode::Strict).unwrap();
567 assert_eq!(val, serde_json::json!(42));
568
569 let val = value_from_column(&array, &DataType::Int32, 1, CrdtDecodeMode::Strict).unwrap();
570 assert_eq!(val, serde_json::json!(-1));
571 }
572
573 #[test]
574 fn test_decode_float32() {
575 use arrow_array::builder::Float32Builder;
576 let mut builder = Float32Builder::new();
577 builder.append_value(1.5);
578 let array = builder.finish();
579
580 let val = value_from_column(&array, &DataType::Float32, 0, CrdtDecodeMode::Strict).unwrap();
581 let f = val.as_f64().unwrap();
583 assert!((f - 1.5).abs() < 0.001);
584 }
585
586 #[test]
587 fn test_decode_vector() {
588 use arrow_array::builder::{FixedSizeListBuilder, Float32Builder};
589 let values_builder = Float32Builder::new();
590 let mut builder = FixedSizeListBuilder::new(values_builder, 3);
591 builder.values().append_value(1.0);
592 builder.values().append_value(2.0);
593 builder.values().append_value(3.0);
594 builder.append(true);
595 let array = builder.finish();
596
597 let val = value_from_column(
598 &array,
599 &DataType::Vector { dimensions: 3 },
600 0,
601 CrdtDecodeMode::Strict,
602 )
603 .unwrap();
604 assert_eq!(val, serde_json::json!([1.0, 2.0, 3.0]));
605 }
606
607 #[test]
608 fn test_decode_date() {
609 use arrow_array::builder::Date32Builder;
610 let mut builder = Date32Builder::new();
611 builder.append_value(18628);
613 let array = builder.finish();
614
615 let val = value_from_column(&array, &DataType::Date, 0, CrdtDecodeMode::Strict).unwrap();
616 assert_eq!(val, Value::String("2021-01-01".to_string()));
617 }
618
619 #[test]
620 fn test_decode_date_null() {
621 use arrow_array::builder::Date32Builder;
622 let mut builder = Date32Builder::new();
623 builder.append_null();
624 let array = builder.finish();
625
626 let val = value_from_column(&array, &DataType::Date, 0, CrdtDecodeMode::Strict).unwrap();
627 assert_eq!(val, Value::Null);
628 }
629
630 #[test]
631 fn test_decode_list_of_strings() {
632 use arrow_array::builder::{ListBuilder, StringBuilder};
633 let values_builder = StringBuilder::new();
634 let mut builder = ListBuilder::new(values_builder);
635 builder.values().append_value("a");
636 builder.values().append_value("b");
637 builder.values().append_value("c");
638 builder.append(true);
639 let array = builder.finish();
640
641 let val = value_from_column(
642 &array,
643 &DataType::List(Box::new(DataType::String)),
644 0,
645 CrdtDecodeMode::Strict,
646 )
647 .unwrap();
648 assert_eq!(val, serde_json::json!(["a", "b", "c"]));
649 }
650
651 #[test]
652 fn test_decode_list_of_ints() {
653 use arrow_array::builder::{Int64Builder, ListBuilder};
654 let values_builder = Int64Builder::new();
655 let mut builder = ListBuilder::new(values_builder);
656 builder.values().append_value(1);
657 builder.values().append_value(2);
658 builder.values().append_value(3);
659 builder.append(true);
660 let array = builder.finish();
661
662 let val = value_from_column(
663 &array,
664 &DataType::List(Box::new(DataType::Int64)),
665 0,
666 CrdtDecodeMode::Strict,
667 )
668 .unwrap();
669 assert_eq!(val, serde_json::json!([1, 2, 3]));
670 }
671
672 #[test]
673 fn test_decode_list_null() {
674 use arrow_array::builder::{Int64Builder, ListBuilder};
675 let values_builder = Int64Builder::new();
676 let mut builder = ListBuilder::new(values_builder);
677 builder.append_null();
678 let array = builder.finish();
679
680 let val = value_from_column(
681 &array,
682 &DataType::List(Box::new(DataType::Int64)),
683 0,
684 CrdtDecodeMode::Strict,
685 )
686 .unwrap();
687 assert_eq!(val, Value::Null);
688 }
689
690 #[test]
691 fn test_decode_column_value_non_struct_point_is_null() {
692 use uni_common::core::schema::PointType;
695 let mut builder = StringBuilder::new();
696 builder.append_value("test");
697 let array = builder.finish();
698
699 let val = decode_column_value(
700 &array,
701 &DataType::Point(PointType::Geographic),
702 0,
703 CrdtDecodeMode::Strict,
704 )
705 .unwrap();
706 assert_eq!(val, uni_common::Value::Null);
707 }
708
709 #[test]
710 fn test_point_struct_roundtrip() {
711 use std::collections::HashMap;
715 use uni_common::core::schema::PointType;
716
717 let point = uni_common::Value::Map(HashMap::from([
718 (
719 "type".to_string(),
720 uni_common::Value::String("Point".into()),
721 ),
722 ("crs".to_string(), uni_common::Value::String("WGS84".into())),
723 ("latitude".to_string(), uni_common::Value::Float(51.5)),
724 ("longitude".to_string(), uni_common::Value::Float(-0.12)),
725 ]));
726
727 let arr = crate::storage::arrow_convert::values_to_point_struct_array(
728 &[point.clone(), uni_common::Value::Null],
729 PointType::Geographic,
730 );
731
732 let decoded = decode_column_value(
733 &arr,
734 &DataType::Point(PointType::Geographic),
735 0,
736 CrdtDecodeMode::Strict,
737 )
738 .unwrap();
739 assert_eq!(decoded, point);
740
741 let decoded_null = decode_column_value(
743 &arr,
744 &DataType::Point(PointType::Geographic),
745 1,
746 CrdtDecodeMode::Strict,
747 )
748 .unwrap();
749 assert_eq!(decoded_null, uni_common::Value::Null);
750 }
751}