1use arrow_schema::ArrowError;
20use base64::{engine::general_purpose, Engine as _};
21use serde_json::Value;
22use std::io::Write;
23
24use parquet_variant::{Variant, VariantList, VariantObject};
25
26const DATE_FORMAT: &str = "%Y-%m-%d";
28const TIMESTAMP_NTZ_FORMAT: &str = "%Y-%m-%dT%H:%M:%S%.6f";
29
30fn format_date_string(date: &chrono::NaiveDate) -> String {
32 date.format(DATE_FORMAT).to_string()
33}
34
35fn format_timestamp_ntz_string(ts: &chrono::NaiveDateTime) -> String {
36 ts.format(TIMESTAMP_NTZ_FORMAT).to_string()
37}
38
39fn format_binary_base64(bytes: &[u8]) -> String {
40 general_purpose::STANDARD.encode(bytes)
41}
42
43pub fn variant_to_json(json_buffer: &mut impl Write, variant: &Variant) -> Result<(), ArrowError> {
95 match variant {
96 Variant::Null => write!(json_buffer, "null")?,
97 Variant::BooleanTrue => write!(json_buffer, "true")?,
98 Variant::BooleanFalse => write!(json_buffer, "false")?,
99 Variant::Int8(i) => write!(json_buffer, "{i}")?,
100 Variant::Int16(i) => write!(json_buffer, "{i}")?,
101 Variant::Int32(i) => write!(json_buffer, "{i}")?,
102 Variant::Int64(i) => write!(json_buffer, "{i}")?,
103 Variant::Float(f) => write!(json_buffer, "{f}")?,
104 Variant::Double(f) => write!(json_buffer, "{f}")?,
105 Variant::Decimal4(decimal) => write!(json_buffer, "{decimal}")?,
106 Variant::Decimal8(decimal) => write!(json_buffer, "{decimal}")?,
107 Variant::Decimal16(decimal) => write!(json_buffer, "{decimal}")?,
108 Variant::Date(date) => write!(json_buffer, "\"{}\"", format_date_string(date))?,
109 Variant::TimestampMicros(ts) => write!(json_buffer, "\"{}\"", ts.to_rfc3339())?,
110 Variant::TimestampNtzMicros(ts) => {
111 write!(json_buffer, "\"{}\"", format_timestamp_ntz_string(ts))?
112 }
113 Variant::Binary(bytes) => {
114 let base64_str = format_binary_base64(bytes);
116 let json_str = serde_json::to_string(&base64_str).map_err(|e| {
117 ArrowError::InvalidArgumentError(format!("JSON encoding error: {e}"))
118 })?;
119 write!(json_buffer, "{json_str}")?
120 }
121 Variant::String(s) => {
122 let json_str = serde_json::to_string(s).map_err(|e| {
124 ArrowError::InvalidArgumentError(format!("JSON encoding error: {e}"))
125 })?;
126 write!(json_buffer, "{json_str}")?
127 }
128 Variant::ShortString(s) => {
129 let json_str = serde_json::to_string(s.as_str()).map_err(|e| {
131 ArrowError::InvalidArgumentError(format!("JSON encoding error: {e}"))
132 })?;
133 write!(json_buffer, "{json_str}")?
134 }
135 Variant::Object(obj) => {
136 convert_object_to_json(json_buffer, obj)?;
137 }
138 Variant::List(arr) => {
139 convert_array_to_json(json_buffer, arr)?;
140 }
141 }
142 Ok(())
143}
144
145fn convert_object_to_json(buffer: &mut impl Write, obj: &VariantObject) -> Result<(), ArrowError> {
147 write!(buffer, "{{")?;
148
149 let mut first = true;
151
152 for (key, value) in obj.iter() {
153 if !first {
154 write!(buffer, ",")?;
155 }
156 first = false;
157
158 let json_key = serde_json::to_string(key).map_err(|e| {
160 ArrowError::InvalidArgumentError(format!("JSON key encoding error: {e}"))
161 })?;
162 write!(buffer, "{json_key}:")?;
163
164 variant_to_json(buffer, &value)?;
166 }
167
168 write!(buffer, "}}")?;
169 Ok(())
170}
171
172fn convert_array_to_json(buffer: &mut impl Write, arr: &VariantList) -> Result<(), ArrowError> {
174 write!(buffer, "[")?;
175
176 let mut first = true;
177 for element in arr.iter() {
178 if !first {
179 write!(buffer, ",")?;
180 }
181 first = false;
182
183 variant_to_json(buffer, &element)?;
184 }
185
186 write!(buffer, "]")?;
187 Ok(())
188}
189
190pub fn variant_to_json_string(variant: &Variant) -> Result<String, ArrowError> {
246 let mut buffer = Vec::new();
247 variant_to_json(&mut buffer, variant)?;
248 String::from_utf8(buffer)
249 .map_err(|e| ArrowError::InvalidArgumentError(format!("UTF-8 conversion error: {e}")))
250}
251
252pub fn variant_to_json_value(variant: &Variant) -> Result<Value, ArrowError> {
280 match variant {
281 Variant::Null => Ok(Value::Null),
282 Variant::BooleanTrue => Ok(Value::Bool(true)),
283 Variant::BooleanFalse => Ok(Value::Bool(false)),
284 Variant::Int8(i) => Ok(Value::Number((*i).into())),
285 Variant::Int16(i) => Ok(Value::Number((*i).into())),
286 Variant::Int32(i) => Ok(Value::Number((*i).into())),
287 Variant::Int64(i) => Ok(Value::Number((*i).into())),
288 Variant::Float(f) => serde_json::Number::from_f64((*f).into())
289 .map(Value::Number)
290 .ok_or_else(|| ArrowError::InvalidArgumentError("Invalid float value".to_string())),
291 Variant::Double(f) => serde_json::Number::from_f64(*f)
292 .map(Value::Number)
293 .ok_or_else(|| ArrowError::InvalidArgumentError("Invalid double value".to_string())),
294 Variant::Decimal4(decimal4) => {
295 let scale = decimal4.scale();
296 let integer = decimal4.integer();
297
298 let integer = if scale == 0 {
299 integer
300 } else {
301 let divisor = 10_i32.pow(scale as u32);
302 if integer % divisor != 0 {
303 return Ok(Value::from(integer as f64 / divisor as f64));
305 }
306 integer / divisor
307 };
308 Ok(Value::from(integer))
309 }
310 Variant::Decimal8(decimal8) => {
311 let scale = decimal8.scale();
312 let integer = decimal8.integer();
313
314 let integer = if scale == 0 {
315 integer
316 } else {
317 let divisor = 10_i64.pow(scale as u32);
318 if integer % divisor != 0 {
319 return Ok(Value::from(integer as f64 / divisor as f64));
321 }
322 integer / divisor
323 };
324 Ok(Value::from(integer))
325 }
326 Variant::Decimal16(decimal16) => {
327 let scale = decimal16.scale();
328 let integer = decimal16.integer();
329
330 let integer = if scale == 0 {
331 integer
332 } else {
333 let divisor = 10_i128.pow(scale as u32);
334 if integer % divisor != 0 {
335 return Ok(Value::from(integer as f64 / divisor as f64));
337 }
338 integer / divisor
339 };
340 let value = i64::try_from(integer)
343 .map(Value::from)
344 .or_else(|_| u64::try_from(integer).map(Value::from))
345 .unwrap_or_else(|_| Value::from(integer as f64));
346 Ok(value)
347 }
348 Variant::Date(date) => Ok(Value::String(format_date_string(date))),
349 Variant::TimestampMicros(ts) => Ok(Value::String(ts.to_rfc3339())),
350 Variant::TimestampNtzMicros(ts) => Ok(Value::String(format_timestamp_ntz_string(ts))),
351 Variant::Binary(bytes) => Ok(Value::String(format_binary_base64(bytes))),
352 Variant::String(s) => Ok(Value::String(s.to_string())),
353 Variant::ShortString(s) => Ok(Value::String(s.to_string())),
354 Variant::Object(obj) => {
355 let map = obj
356 .iter()
357 .map(|(k, v)| variant_to_json_value(&v).map(|json_val| (k.to_string(), json_val)))
358 .collect::<Result<_, _>>()?;
359 Ok(Value::Object(map))
360 }
361 Variant::List(arr) => {
362 let vec = arr
363 .iter()
364 .map(|element| variant_to_json_value(&element))
365 .collect::<Result<_, _>>()?;
366 Ok(Value::Array(vec))
367 }
368 }
369}
370
371#[cfg(test)]
372mod tests {
373 use super::*;
374 use chrono::{DateTime, NaiveDate, Utc};
375 use parquet_variant::{VariantDecimal16, VariantDecimal4, VariantDecimal8};
376
377 #[test]
378 fn test_decimal_edge_cases() -> Result<(), ArrowError> {
379 let negative_variant = Variant::from(VariantDecimal4::try_new(-12345, 3)?);
381 let negative_json = variant_to_json_string(&negative_variant)?;
382 assert_eq!(negative_json, "-12.345");
383
384 let large_scale_variant = Variant::from(VariantDecimal8::try_new(123456789, 6)?);
386 let large_scale_json = variant_to_json_string(&large_scale_variant)?;
387 assert_eq!(large_scale_json, "123.456789");
388
389 Ok(())
390 }
391
392 #[test]
393 fn test_decimal16_to_json() -> Result<(), ArrowError> {
394 let variant = Variant::from(VariantDecimal16::try_new(123456789012345, 4)?);
395 let json = variant_to_json_string(&variant)?;
396 assert_eq!(json, "12345678901.2345");
397
398 let json_value = variant_to_json_value(&variant)?;
399 assert!(matches!(json_value, Value::Number(_)));
400
401 let large_variant = Variant::from(VariantDecimal16::try_new(999999999999999999, 2)?);
403 let large_json = variant_to_json_string(&large_variant)?;
404 assert!(
406 large_json.starts_with("9999999999999999")
407 || large_json.starts_with("10000000000000000")
408 );
409 Ok(())
410 }
411
412 #[test]
413 fn test_date_to_json() -> Result<(), ArrowError> {
414 let date = NaiveDate::from_ymd_opt(2023, 12, 25).unwrap();
415 let variant = Variant::Date(date);
416 let json = variant_to_json_string(&variant)?;
417 assert_eq!(json, "\"2023-12-25\"");
418
419 let json_value = variant_to_json_value(&variant)?;
420 assert_eq!(json_value, Value::String("2023-12-25".to_string()));
421
422 let leap_date = NaiveDate::from_ymd_opt(2024, 2, 29).unwrap();
424 let leap_variant = Variant::Date(leap_date);
425 let leap_json = variant_to_json_string(&leap_variant)?;
426 assert_eq!(leap_json, "\"2024-02-29\"");
427 Ok(())
428 }
429
430 #[test]
431 fn test_timestamp_micros_to_json() -> Result<(), ArrowError> {
432 let timestamp = DateTime::parse_from_rfc3339("2023-12-25T10:30:45Z")
433 .unwrap()
434 .with_timezone(&Utc);
435 let variant = Variant::TimestampMicros(timestamp);
436 let json = variant_to_json_string(&variant)?;
437 assert!(json.contains("2023-12-25T10:30:45"));
438 assert!(json.starts_with('"') && json.ends_with('"'));
439
440 let json_value = variant_to_json_value(&variant)?;
441 assert!(matches!(json_value, Value::String(_)));
442 Ok(())
443 }
444
445 #[test]
446 fn test_timestamp_ntz_micros_to_json() -> Result<(), ArrowError> {
447 let naive_timestamp = DateTime::from_timestamp(1703505045, 123456)
448 .unwrap()
449 .naive_utc();
450 let variant = Variant::TimestampNtzMicros(naive_timestamp);
451 let json = variant_to_json_string(&variant)?;
452 assert!(json.contains("2023-12-25"));
453 assert!(json.starts_with('"') && json.ends_with('"'));
454
455 let json_value = variant_to_json_value(&variant)?;
456 assert!(matches!(json_value, Value::String(_)));
457 Ok(())
458 }
459
460 #[test]
461 fn test_binary_to_json() -> Result<(), ArrowError> {
462 let binary_data = b"Hello, World!";
463 let variant = Variant::Binary(binary_data);
464 let json = variant_to_json_string(&variant)?;
465
466 assert!(json.starts_with('"') && json.ends_with('"'));
468 assert!(json.len() > 2); let json_value = variant_to_json_value(&variant)?;
471 assert!(matches!(json_value, Value::String(_)));
472
473 let empty_variant = Variant::Binary(b"");
475 let empty_json = variant_to_json_string(&empty_variant)?;
476 assert_eq!(empty_json, "\"\"");
477
478 let special_variant = Variant::Binary(&[0, 255, 128, 64]);
480 let special_json = variant_to_json_string(&special_variant)?;
481 assert!(special_json.starts_with('"') && special_json.ends_with('"'));
482 Ok(())
483 }
484
485 #[test]
486 fn test_string_to_json() -> Result<(), ArrowError> {
487 let variant = Variant::from("hello world");
488 let json = variant_to_json_string(&variant)?;
489 assert_eq!(json, "\"hello world\"");
490
491 let json_value = variant_to_json_value(&variant)?;
492 assert_eq!(json_value, Value::String("hello world".to_string()));
493 Ok(())
494 }
495
496 #[test]
497 fn test_short_string_to_json() -> Result<(), ArrowError> {
498 use parquet_variant::ShortString;
499 let short_string = ShortString::try_new("short")?;
500 let variant = Variant::ShortString(short_string);
501 let json = variant_to_json_string(&variant)?;
502 assert_eq!(json, "\"short\"");
503
504 let json_value = variant_to_json_value(&variant)?;
505 assert_eq!(json_value, Value::String("short".to_string()));
506 Ok(())
507 }
508
509 #[test]
510 fn test_string_escaping() -> Result<(), ArrowError> {
511 let variant = Variant::from("hello\nworld\t\"quoted\"");
512 let json = variant_to_json_string(&variant)?;
513 assert_eq!(json, "\"hello\\nworld\\t\\\"quoted\\\"\"");
514
515 let json_value = variant_to_json_value(&variant)?;
516 assert_eq!(
517 json_value,
518 Value::String("hello\nworld\t\"quoted\"".to_string())
519 );
520 Ok(())
521 }
522
523 #[test]
524 fn test_json_buffer_writing() -> Result<(), ArrowError> {
525 let variant = Variant::Int8(123);
526 let mut buffer = Vec::new();
527 variant_to_json(&mut buffer, &variant)?;
528
529 let result = String::from_utf8(buffer)
530 .map_err(|e| ArrowError::InvalidArgumentError(e.to_string()))?;
531 assert_eq!(result, "123");
532 Ok(())
533 }
534
535 struct JsonTest {
537 variant: Variant<'static, 'static>,
538 expected_json: &'static str,
539 expected_value: Value,
540 }
541
542 impl JsonTest {
543 fn run(self) {
544 let json_string = variant_to_json_string(&self.variant)
545 .expect("variant_to_json_string should succeed");
546 assert_eq!(
547 json_string, self.expected_json,
548 "JSON string mismatch for variant: {:?}",
549 self.variant
550 );
551
552 let json_value =
553 variant_to_json_value(&self.variant).expect("variant_to_json_value should succeed");
554
555 match (&json_value, &self.expected_value) {
557 (Value::Number(actual), Value::Number(expected)) => {
558 let actual_f64 = actual.as_f64().unwrap_or(0.0);
559 let expected_f64 = expected.as_f64().unwrap_or(0.0);
560 assert!(
561 (actual_f64 - expected_f64).abs() < f64::EPSILON,
562 "JSON value mismatch for variant: {:?}, got {}, expected {}",
563 self.variant,
564 actual_f64,
565 expected_f64
566 );
567 }
568 _ => {
569 assert_eq!(
570 json_value, self.expected_value,
571 "JSON value mismatch for variant: {:?}",
572 self.variant
573 );
574 }
575 }
576
577 let parsed: Value =
579 serde_json::from_str(&json_string).expect("Generated JSON should be valid");
580 match (&parsed, &self.expected_value) {
582 (Value::Number(actual), Value::Number(expected)) => {
583 let actual_f64 = actual.as_f64().unwrap_or(0.0);
584 let expected_f64 = expected.as_f64().unwrap_or(0.0);
585 assert!(
586 (actual_f64 - expected_f64).abs() < f64::EPSILON,
587 "Parsed JSON mismatch for variant: {:?}, got {}, expected {}",
588 self.variant,
589 actual_f64,
590 expected_f64
591 );
592 }
593 _ => {
594 assert_eq!(
595 parsed, self.expected_value,
596 "Parsed JSON mismatch for variant: {:?}",
597 self.variant
598 );
599 }
600 }
601 }
602 }
603
604 #[test]
605 fn test_primitive_json_conversion() {
606 use parquet_variant::ShortString;
607
608 JsonTest {
610 variant: Variant::Null,
611 expected_json: "null",
612 expected_value: Value::Null,
613 }
614 .run();
615
616 JsonTest {
618 variant: Variant::BooleanTrue,
619 expected_json: "true",
620 expected_value: Value::Bool(true),
621 }
622 .run();
623
624 JsonTest {
625 variant: Variant::BooleanFalse,
626 expected_json: "false",
627 expected_value: Value::Bool(false),
628 }
629 .run();
630
631 JsonTest {
633 variant: Variant::Int8(42),
634 expected_json: "42",
635 expected_value: Value::Number(42.into()),
636 }
637 .run();
638
639 JsonTest {
640 variant: Variant::Int8(-128),
641 expected_json: "-128",
642 expected_value: Value::Number((-128).into()),
643 }
644 .run();
645
646 JsonTest {
647 variant: Variant::Int16(32767),
648 expected_json: "32767",
649 expected_value: Value::Number(32767.into()),
650 }
651 .run();
652
653 JsonTest {
654 variant: Variant::Int16(-32768),
655 expected_json: "-32768",
656 expected_value: Value::Number((-32768).into()),
657 }
658 .run();
659
660 JsonTest {
661 variant: Variant::Int32(2147483647),
662 expected_json: "2147483647",
663 expected_value: Value::Number(2147483647.into()),
664 }
665 .run();
666
667 JsonTest {
668 variant: Variant::Int32(-2147483648),
669 expected_json: "-2147483648",
670 expected_value: Value::Number((-2147483648).into()),
671 }
672 .run();
673
674 JsonTest {
675 variant: Variant::Int64(9223372036854775807),
676 expected_json: "9223372036854775807",
677 expected_value: Value::Number(9223372036854775807i64.into()),
678 }
679 .run();
680
681 JsonTest {
682 variant: Variant::Int64(-9223372036854775808),
683 expected_json: "-9223372036854775808",
684 expected_value: Value::Number((-9223372036854775808i64).into()),
685 }
686 .run();
687
688 JsonTest {
690 variant: Variant::Float(3.5),
691 expected_json: "3.5",
692 expected_value: serde_json::Number::from_f64(3.5)
693 .map(Value::Number)
694 .unwrap(),
695 }
696 .run();
697
698 JsonTest {
699 variant: Variant::Float(0.0),
700 expected_json: "0",
701 expected_value: Value::Number(0.into()), }
703 .run();
704
705 JsonTest {
706 variant: Variant::Float(-1.5),
707 expected_json: "-1.5",
708 expected_value: serde_json::Number::from_f64(-1.5)
709 .map(Value::Number)
710 .unwrap(),
711 }
712 .run();
713
714 JsonTest {
715 variant: Variant::Double(std::f64::consts::E),
716 expected_json: "2.718281828459045",
717 expected_value: serde_json::Number::from_f64(std::f64::consts::E)
718 .map(Value::Number)
719 .unwrap(),
720 }
721 .run();
722
723 JsonTest {
725 variant: Variant::from(VariantDecimal4::try_new(12345, 2).unwrap()),
726 expected_json: "123.45",
727 expected_value: serde_json::Number::from_f64(123.45)
728 .map(Value::Number)
729 .unwrap(),
730 }
731 .run();
732
733 JsonTest {
734 variant: Variant::from(VariantDecimal4::try_new(42, 0).unwrap()),
735 expected_json: "42",
736 expected_value: serde_json::Number::from_f64(42.0)
737 .map(Value::Number)
738 .unwrap(),
739 }
740 .run();
741
742 JsonTest {
743 variant: Variant::from(VariantDecimal8::try_new(1234567890, 3).unwrap()),
744 expected_json: "1234567.89",
745 expected_value: serde_json::Number::from_f64(1234567.89)
746 .map(Value::Number)
747 .unwrap(),
748 }
749 .run();
750
751 JsonTest {
752 variant: Variant::from(VariantDecimal16::try_new(123456789012345, 4).unwrap()),
753 expected_json: "12345678901.2345",
754 expected_value: serde_json::Number::from_f64(12345678901.2345)
755 .map(Value::Number)
756 .unwrap(),
757 }
758 .run();
759
760 JsonTest {
762 variant: Variant::from("hello world"),
763 expected_json: "\"hello world\"",
764 expected_value: Value::String("hello world".to_string()),
765 }
766 .run();
767
768 JsonTest {
769 variant: Variant::from(""),
770 expected_json: "\"\"",
771 expected_value: Value::String("".to_string()),
772 }
773 .run();
774
775 JsonTest {
776 variant: Variant::ShortString(ShortString::try_new("test").unwrap()),
777 expected_json: "\"test\"",
778 expected_value: Value::String("test".to_string()),
779 }
780 .run();
781
782 JsonTest {
784 variant: Variant::Date(NaiveDate::from_ymd_opt(2023, 12, 25).unwrap()),
785 expected_json: "\"2023-12-25\"",
786 expected_value: Value::String("2023-12-25".to_string()),
787 }
788 .run();
789
790 JsonTest {
792 variant: Variant::Binary(b"test"),
793 expected_json: "\"dGVzdA==\"", expected_value: Value::String("dGVzdA==".to_string()),
795 }
796 .run();
797
798 JsonTest {
799 variant: Variant::Binary(b""),
800 expected_json: "\"\"", expected_value: Value::String("".to_string()),
802 }
803 .run();
804
805 JsonTest {
806 variant: Variant::Binary(b"binary data"),
807 expected_json: "\"YmluYXJ5IGRhdGE=\"", expected_value: Value::String("YmluYXJ5IGRhdGE=".to_string()),
809 }
810 .run();
811 }
812
813 #[test]
814 fn test_string_escaping_comprehensive() {
815 JsonTest {
817 variant: Variant::from("line1\nline2\ttab\"quote\"\\backslash"),
818 expected_json: "\"line1\\nline2\\ttab\\\"quote\\\"\\\\backslash\"",
819 expected_value: Value::String("line1\nline2\ttab\"quote\"\\backslash".to_string()),
820 }
821 .run();
822
823 JsonTest {
824 variant: Variant::from("Hello δΈη π"),
825 expected_json: "\"Hello δΈη π\"",
826 expected_value: Value::String("Hello δΈη π".to_string()),
827 }
828 .run();
829 }
830
831 #[test]
832 fn test_buffer_writing_variants() -> Result<(), ArrowError> {
833 use crate::variant_to_json;
834
835 let variant = Variant::from("test buffer writing");
836
837 let mut buffer = Vec::new();
839 variant_to_json(&mut buffer, &variant)?;
840 let result = String::from_utf8(buffer)
841 .map_err(|e| ArrowError::InvalidArgumentError(e.to_string()))?;
842 assert_eq!(result, "\"test buffer writing\"");
843
844 let mut buffer = vec![];
846 variant_to_json(&mut buffer, &variant)?;
847 let result = String::from_utf8(buffer)
848 .map_err(|e| ArrowError::InvalidArgumentError(e.to_string()))?;
849 assert_eq!(result, "\"test buffer writing\"");
850
851 Ok(())
852 }
853
854 #[test]
855 fn test_simple_object_to_json() -> Result<(), ArrowError> {
856 use parquet_variant::VariantBuilder;
857
858 let mut builder = VariantBuilder::new();
860
861 builder
862 .new_object()
863 .with_field("name", "Alice")
864 .with_field("age", 30i32)
865 .with_field("active", true)
866 .with_field("score", 95.5f64)
867 .finish()
868 .unwrap();
869
870 let (metadata, value) = builder.finish();
871 let variant = Variant::try_new(&metadata, &value)?;
872 let json = variant_to_json_string(&variant)?;
873
874 let parsed: Value = serde_json::from_str(&json).unwrap();
876 let obj = parsed.as_object().expect("expected JSON object");
877 assert_eq!(obj.get("name"), Some(&Value::String("Alice".to_string())));
878 assert_eq!(obj.get("age"), Some(&Value::Number(30.into())));
879 assert_eq!(obj.get("active"), Some(&Value::Bool(true)));
880 assert!(matches!(obj.get("score"), Some(Value::Number(_))));
881 assert_eq!(obj.len(), 4);
882
883 let json_value = variant_to_json_value(&variant)?;
885 assert!(matches!(json_value, Value::Object(_)));
886
887 Ok(())
888 }
889
890 #[test]
891 fn test_empty_object_to_json() -> Result<(), ArrowError> {
892 use parquet_variant::VariantBuilder;
893
894 let mut builder = VariantBuilder::new();
895
896 {
897 let obj = builder.new_object();
898 obj.finish().unwrap();
899 }
900
901 let (metadata, value) = builder.finish();
902 let variant = Variant::try_new(&metadata, &value)?;
903 let json = variant_to_json_string(&variant)?;
904 assert_eq!(json, "{}");
905
906 let json_value = variant_to_json_value(&variant)?;
907 assert_eq!(json_value, Value::Object(serde_json::Map::new()));
908
909 Ok(())
910 }
911
912 #[test]
913 fn test_object_with_special_characters_to_json() -> Result<(), ArrowError> {
914 use parquet_variant::VariantBuilder;
915
916 let mut builder = VariantBuilder::new();
917
918 builder
919 .new_object()
920 .with_field("message", "Hello \"World\"\nWith\tTabs")
921 .with_field("path", "C:\\Users\\Alice\\Documents")
922 .with_field("unicode", "π Smiley")
923 .finish()
924 .unwrap();
925
926 let (metadata, value) = builder.finish();
927 let variant = Variant::try_new(&metadata, &value)?;
928 let json = variant_to_json_string(&variant)?;
929
930 assert!(json.contains("Hello \\\"World\\\"\\nWith\\tTabs"));
932 assert!(json.contains("C:\\\\Users\\\\Alice\\\\Documents"));
933 assert!(json.contains("π Smiley"));
934
935 let parsed: Value = serde_json::from_str(&json).unwrap();
937 assert!(matches!(parsed, Value::Object(_)));
938
939 Ok(())
940 }
941
942 #[test]
943 fn test_simple_list_to_json() -> Result<(), ArrowError> {
944 use parquet_variant::VariantBuilder;
945
946 let mut builder = VariantBuilder::new();
947
948 builder
949 .new_list()
950 .with_value(1i32)
951 .with_value(2i32)
952 .with_value(3i32)
953 .with_value(4i32)
954 .with_value(5i32)
955 .finish();
956
957 let (metadata, value) = builder.finish();
958 let variant = Variant::try_new(&metadata, &value)?;
959 let json = variant_to_json_string(&variant)?;
960 assert_eq!(json, "[1,2,3,4,5]");
961
962 let json_value = variant_to_json_value(&variant)?;
963 let arr = json_value.as_array().expect("expected JSON array");
964 assert_eq!(arr.len(), 5);
965 assert_eq!(arr[0], Value::Number(1.into()));
966 assert_eq!(arr[4], Value::Number(5.into()));
967
968 Ok(())
969 }
970
971 #[test]
972 fn test_empty_list_to_json() -> Result<(), ArrowError> {
973 use parquet_variant::VariantBuilder;
974
975 let mut builder = VariantBuilder::new();
976
977 {
978 let list = builder.new_list();
979 list.finish();
980 }
981
982 let (metadata, value) = builder.finish();
983 let variant = Variant::try_new(&metadata, &value)?;
984 let json = variant_to_json_string(&variant)?;
985 assert_eq!(json, "[]");
986
987 let json_value = variant_to_json_value(&variant)?;
988 assert_eq!(json_value, Value::Array(vec![]));
989
990 Ok(())
991 }
992
993 #[test]
994 fn test_mixed_type_list_to_json() -> Result<(), ArrowError> {
995 use parquet_variant::VariantBuilder;
996
997 let mut builder = VariantBuilder::new();
998
999 builder
1000 .new_list()
1001 .with_value("hello")
1002 .with_value(42i32)
1003 .with_value(true)
1004 .with_value(()) .with_value(std::f64::consts::PI)
1006 .finish();
1007
1008 let (metadata, value) = builder.finish();
1009 let variant = Variant::try_new(&metadata, &value)?;
1010 let json = variant_to_json_string(&variant)?;
1011
1012 let parsed: Value = serde_json::from_str(&json).unwrap();
1013 let arr = parsed.as_array().expect("expected JSON array");
1014 assert_eq!(arr.len(), 5);
1015 assert_eq!(arr[0], Value::String("hello".to_string()));
1016 assert_eq!(arr[1], Value::Number(42.into()));
1017 assert_eq!(arr[2], Value::Bool(true));
1018 assert_eq!(arr[3], Value::Null);
1019 assert!(matches!(arr[4], Value::Number(_)));
1020
1021 Ok(())
1022 }
1023
1024 #[test]
1025 fn test_object_field_ordering_in_json() -> Result<(), ArrowError> {
1026 use parquet_variant::VariantBuilder;
1027
1028 let mut builder = VariantBuilder::new();
1029
1030 {
1031 let mut obj = builder.new_object();
1032 obj.insert("zebra", "last");
1034 obj.insert("alpha", "first");
1035 obj.insert("beta", "second");
1036 obj.finish().unwrap();
1037 }
1038
1039 let (metadata, value) = builder.finish();
1040 let variant = Variant::try_new(&metadata, &value)?;
1041 let json = variant_to_json_string(&variant)?;
1042
1043 let parsed: Value = serde_json::from_str(&json).unwrap();
1045 let obj = parsed.as_object().expect("expected JSON object");
1046 assert_eq!(obj.len(), 3);
1047 assert_eq!(obj.get("alpha"), Some(&Value::String("first".to_string())));
1048 assert_eq!(obj.get("beta"), Some(&Value::String("second".to_string())));
1049 assert_eq!(obj.get("zebra"), Some(&Value::String("last".to_string())));
1050
1051 Ok(())
1052 }
1053
1054 #[test]
1055 fn test_list_with_various_primitive_types_to_json() -> Result<(), ArrowError> {
1056 use parquet_variant::VariantBuilder;
1057
1058 let mut builder = VariantBuilder::new();
1059
1060 builder
1061 .new_list()
1062 .with_value("string_value")
1063 .with_value(42i32)
1064 .with_value(true)
1065 .with_value(std::f64::consts::PI)
1066 .with_value(false)
1067 .with_value(()) .with_value(100i64)
1069 .finish();
1070
1071 let (metadata, value) = builder.finish();
1072 let variant = Variant::try_new(&metadata, &value)?;
1073 let json = variant_to_json_string(&variant)?;
1074
1075 let parsed: Value = serde_json::from_str(&json).unwrap();
1076 let arr = parsed.as_array().expect("expected JSON array");
1077 assert_eq!(arr.len(), 7);
1078 assert_eq!(arr[0], Value::String("string_value".to_string()));
1079 assert_eq!(arr[1], Value::Number(42.into()));
1080 assert_eq!(arr[2], Value::Bool(true));
1081 assert!(matches!(arr[3], Value::Number(_))); assert_eq!(arr[4], Value::Bool(false));
1083 assert_eq!(arr[5], Value::Null);
1084 assert_eq!(arr[6], Value::Number(100.into()));
1085
1086 Ok(())
1087 }
1088
1089 #[test]
1090 fn test_object_with_various_primitive_types_to_json() -> Result<(), ArrowError> {
1091 use parquet_variant::VariantBuilder;
1092
1093 let mut builder = VariantBuilder::new();
1094
1095 {
1096 let mut obj = builder.new_object();
1097 obj.insert("string_field", "test_string");
1098 obj.insert("int_field", 123i32);
1099 obj.insert("bool_field", true);
1100 obj.insert("float_field", 2.71f64);
1101 obj.insert("null_field", ());
1102 obj.insert("long_field", 999i64);
1103 obj.finish().unwrap();
1104 }
1105
1106 let (metadata, value) = builder.finish();
1107 let variant = Variant::try_new(&metadata, &value)?;
1108 let json = variant_to_json_string(&variant)?;
1109
1110 let parsed: Value = serde_json::from_str(&json).unwrap();
1111 let obj = parsed.as_object().expect("expected JSON object");
1112 assert_eq!(obj.len(), 6);
1113 assert_eq!(
1114 obj.get("string_field"),
1115 Some(&Value::String("test_string".to_string()))
1116 );
1117 assert_eq!(obj.get("int_field"), Some(&Value::Number(123.into())));
1118 assert_eq!(obj.get("bool_field"), Some(&Value::Bool(true)));
1119 assert!(matches!(obj.get("float_field"), Some(Value::Number(_))));
1120 assert_eq!(obj.get("null_field"), Some(&Value::Null));
1121 assert_eq!(obj.get("long_field"), Some(&Value::Number(999.into())));
1122
1123 Ok(())
1124 }
1125
1126 #[test]
1127 fn test_decimal_precision_behavior() -> Result<(), ArrowError> {
1128 let high_precision_decimal8 = Variant::from(VariantDecimal8::try_new(
1131 9007199254740993, 6,
1133 )?);
1134
1135 let json_string = variant_to_json_string(&high_precision_decimal8)?;
1136 let json_value = variant_to_json_value(&high_precision_decimal8)?;
1137
1138 let parsed: Value = serde_json::from_str(&json_string).unwrap();
1141 assert_eq!(parsed, json_value);
1142
1143 let exact_decimal = Variant::from(VariantDecimal8::try_new(
1145 1234567890000, 6,
1147 )?);
1148
1149 let json_string_exact = variant_to_json_string(&exact_decimal)?;
1150 assert_eq!(json_string_exact, "1234567.89");
1151
1152 let integer_decimal = Variant::from(VariantDecimal8::try_new(
1154 42000000, 6,
1156 )?);
1157
1158 let json_string_integer = variant_to_json_string(&integer_decimal)?;
1159 assert_eq!(json_string_integer, "42");
1160
1161 Ok(())
1162 }
1163
1164 #[test]
1165 fn test_float_nan_inf_handling() -> Result<(), ArrowError> {
1166 let nan_variant = Variant::Float(f32::NAN);
1168 let nan_result = variant_to_json_value(&nan_variant);
1169 assert!(nan_result.is_err());
1170 assert!(nan_result
1171 .unwrap_err()
1172 .to_string()
1173 .contains("Invalid float value"));
1174
1175 let pos_inf_variant = Variant::Float(f32::INFINITY);
1177 let pos_inf_result = variant_to_json_value(&pos_inf_variant);
1178 assert!(pos_inf_result.is_err());
1179 assert!(pos_inf_result
1180 .unwrap_err()
1181 .to_string()
1182 .contains("Invalid float value"));
1183
1184 let neg_inf_variant = Variant::Float(f32::NEG_INFINITY);
1186 let neg_inf_result = variant_to_json_value(&neg_inf_variant);
1187 assert!(neg_inf_result.is_err());
1188 assert!(neg_inf_result
1189 .unwrap_err()
1190 .to_string()
1191 .contains("Invalid float value"));
1192
1193 let nan_double_variant = Variant::Double(f64::NAN);
1195 let nan_double_result = variant_to_json_value(&nan_double_variant);
1196 assert!(nan_double_result.is_err());
1197 assert!(nan_double_result
1198 .unwrap_err()
1199 .to_string()
1200 .contains("Invalid double value"));
1201
1202 let pos_inf_double_variant = Variant::Double(f64::INFINITY);
1203 let pos_inf_double_result = variant_to_json_value(&pos_inf_double_variant);
1204 assert!(pos_inf_double_result.is_err());
1205 assert!(pos_inf_double_result
1206 .unwrap_err()
1207 .to_string()
1208 .contains("Invalid double value"));
1209
1210 let neg_inf_double_variant = Variant::Double(f64::NEG_INFINITY);
1211 let neg_inf_double_result = variant_to_json_value(&neg_inf_double_variant);
1212 assert!(neg_inf_double_result.is_err());
1213 assert!(neg_inf_double_result
1214 .unwrap_err()
1215 .to_string()
1216 .contains("Invalid double value"));
1217
1218 let normal_float = Variant::Float(std::f32::consts::PI);
1220 let normal_result = variant_to_json_value(&normal_float)?;
1221 assert!(matches!(normal_result, Value::Number(_)));
1222
1223 let normal_double = Variant::Double(std::f64::consts::E);
1224 let normal_double_result = variant_to_json_value(&normal_double)?;
1225 assert!(matches!(normal_double_result, Value::Number(_)));
1226
1227 Ok(())
1228 }
1229}