1use arrow_schema::ArrowError;
20use base64::{Engine as _, engine::general_purpose};
21use chrono::Timelike;
22use parquet_variant::{Variant, VariantList, VariantObject};
23use serde_json::Value;
24use std::io::Write;
25
26pub trait VariantToJson {
28 fn to_json(&self, buffer: &mut impl Write) -> Result<(), ArrowError>;
80
81 fn to_json_string(&self) -> Result<String, ArrowError>;
137
138 fn to_json_value(&self) -> Result<Value, ArrowError>;
166}
167
168impl<'m, 'v> VariantToJson for Variant<'m, 'v> {
169 fn to_json(&self, buffer: &mut impl Write) -> Result<(), ArrowError> {
170 match self {
171 Variant::Null => write!(buffer, "null")?,
172 Variant::BooleanTrue => write!(buffer, "true")?,
173 Variant::BooleanFalse => write!(buffer, "false")?,
174 Variant::Int8(i) => write!(buffer, "{i}")?,
175 Variant::Int16(i) => write!(buffer, "{i}")?,
176 Variant::Int32(i) => write!(buffer, "{i}")?,
177 Variant::Int64(i) => write!(buffer, "{i}")?,
178 Variant::Float(f) => write!(buffer, "{f}")?,
179 Variant::Double(f) => write!(buffer, "{f}")?,
180 Variant::Decimal4(decimal) => write!(buffer, "{decimal}")?,
181 Variant::Decimal8(decimal) => write!(buffer, "{decimal}")?,
182 Variant::Decimal16(decimal) => write!(buffer, "{decimal}")?,
183 Variant::Date(date) => write!(buffer, "\"{}\"", format_date_string(date))?,
184 Variant::TimestampMicros(ts) | Variant::TimestampNanos(ts) => {
185 write!(buffer, "\"{}\"", ts.to_rfc3339())?
186 }
187 Variant::TimestampNtzMicros(ts) => {
188 write!(buffer, "\"{}\"", format_timestamp_ntz_string(ts, 6))?
189 }
190 Variant::TimestampNtzNanos(ts) => {
191 write!(buffer, "\"{}\"", format_timestamp_ntz_string(ts, 9))?
192 }
193 Variant::Time(time) => write!(buffer, "\"{}\"", format_time_ntz_str(time))?,
194 Variant::Binary(bytes) => {
195 let base64_str = format_binary_base64(bytes);
197 let json_str = serde_json::to_string(&base64_str).map_err(|e| {
198 ArrowError::InvalidArgumentError(format!("JSON encoding error: {e}"))
199 })?;
200 write!(buffer, "{json_str}")?
201 }
202 Variant::String(s) => {
203 let json_str = serde_json::to_string(s).map_err(|e| {
205 ArrowError::InvalidArgumentError(format!("JSON encoding error: {e}"))
206 })?;
207 write!(buffer, "{json_str}")?
208 }
209 Variant::ShortString(s) => {
210 let json_str = serde_json::to_string(s.as_str()).map_err(|e| {
212 ArrowError::InvalidArgumentError(format!("JSON encoding error: {e}"))
213 })?;
214 write!(buffer, "{json_str}")?
215 }
216 Variant::Uuid(uuid) => {
217 write!(buffer, "\"{uuid}\"")?;
218 }
219 Variant::Object(obj) => {
220 convert_object_to_json(buffer, obj)?;
221 }
222 Variant::List(arr) => {
223 convert_array_to_json(buffer, arr)?;
224 }
225 }
226 Ok(())
227 }
228
229 fn to_json_string(&self) -> Result<String, ArrowError> {
230 let mut buffer = Vec::new();
231 self.to_json(&mut buffer)?;
232 String::from_utf8(buffer)
233 .map_err(|e| ArrowError::InvalidArgumentError(format!("UTF-8 conversion error: {e}")))
234 }
235
236 fn to_json_value(&self) -> Result<Value, ArrowError> {
237 match self {
238 Variant::Null => Ok(Value::Null),
239 Variant::BooleanTrue => Ok(Value::Bool(true)),
240 Variant::BooleanFalse => Ok(Value::Bool(false)),
241 Variant::Int8(i) => Ok(Value::Number((*i).into())),
242 Variant::Int16(i) => Ok(Value::Number((*i).into())),
243 Variant::Int32(i) => Ok(Value::Number((*i).into())),
244 Variant::Int64(i) => Ok(Value::Number((*i).into())),
245 Variant::Float(f) => serde_json::Number::from_f64((*f).into())
246 .map(Value::Number)
247 .ok_or_else(|| ArrowError::InvalidArgumentError("Invalid float value".to_string())),
248 Variant::Double(f) => serde_json::Number::from_f64(*f)
249 .map(Value::Number)
250 .ok_or_else(|| {
251 ArrowError::InvalidArgumentError("Invalid double value".to_string())
252 }),
253 Variant::Decimal4(decimal4) => {
254 let scale = decimal4.scale();
255 let integer = decimal4.integer();
256
257 let integer = if scale == 0 {
258 integer
259 } else {
260 let divisor = 10_i32.pow(scale as u32);
261 if integer % divisor != 0 {
262 return Ok(Value::from(integer as f64 / divisor as f64));
264 }
265 integer / divisor
266 };
267 Ok(Value::from(integer))
268 }
269 Variant::Decimal8(decimal8) => {
270 let scale = decimal8.scale();
271 let integer = decimal8.integer();
272
273 let integer = if scale == 0 {
274 integer
275 } else {
276 let divisor = 10_i64.pow(scale as u32);
277 if integer % divisor != 0 {
278 return Ok(Value::from(integer as f64 / divisor as f64));
280 }
281 integer / divisor
282 };
283 Ok(Value::from(integer))
284 }
285 Variant::Decimal16(decimal16) => {
286 let scale = decimal16.scale();
287 let integer = decimal16.integer();
288
289 let integer = if scale == 0 {
290 integer
291 } else {
292 let divisor = 10_i128.pow(scale as u32);
293 if integer % divisor != 0 {
294 return Ok(Value::from(integer as f64 / divisor as f64));
296 }
297 integer / divisor
298 };
299 let value = i64::try_from(integer)
302 .map(Value::from)
303 .or_else(|_| u64::try_from(integer).map(Value::from))
304 .unwrap_or_else(|_| Value::from(integer as f64));
305 Ok(value)
306 }
307 Variant::Date(date) => Ok(Value::String(format_date_string(date))),
308 Variant::TimestampMicros(ts) | Variant::TimestampNanos(ts) => {
309 Ok(Value::String(ts.to_rfc3339()))
310 }
311 Variant::TimestampNtzMicros(ts) => {
312 Ok(Value::String(format_timestamp_ntz_string(ts, 6)))
313 }
314 Variant::TimestampNtzNanos(ts) => Ok(Value::String(format_timestamp_ntz_string(ts, 9))),
315 Variant::Time(time) => Ok(Value::String(format_time_ntz_str(time))),
316 Variant::Binary(bytes) => Ok(Value::String(format_binary_base64(bytes))),
317 Variant::String(s) => Ok(Value::String(s.to_string())),
318 Variant::ShortString(s) => Ok(Value::String(s.to_string())),
319 Variant::Uuid(uuid) => Ok(Value::String(uuid.to_string())),
320 Variant::Object(obj) => {
321 let map = obj
322 .iter()
323 .map(|(k, v)| v.to_json_value().map(|json_val| (k.to_string(), json_val)))
324 .collect::<Result<_, _>>()?;
325 Ok(Value::Object(map))
326 }
327 Variant::List(arr) => {
328 let vec = arr
329 .iter()
330 .map(|element| element.to_json_value())
331 .collect::<Result<_, _>>()?;
332 Ok(Value::Array(vec))
333 }
334 }
335 }
336}
337
338const DATE_FORMAT: &str = "%Y-%m-%d";
340
341fn format_date_string(date: &chrono::NaiveDate) -> String {
343 date.format(DATE_FORMAT).to_string()
344}
345
346fn format_timestamp_ntz_string(ts: &chrono::NaiveDateTime, precision: usize) -> String {
347 let format_str = format!(
348 "{}",
349 ts.format(&format!("%Y-%m-%dT%H:%M:%S%.{}f", precision))
350 );
351 ts.format(format_str.as_str()).to_string()
352}
353
354fn format_binary_base64(bytes: &[u8]) -> String {
355 general_purpose::STANDARD.encode(bytes)
356}
357
358fn format_time_ntz_str(time: &chrono::NaiveTime) -> String {
359 let base = time.format("%H:%M:%S").to_string();
360 let micros = time.nanosecond() / 1000;
361 match micros {
362 0 => format!("{}.{}", base, 0),
363 _ => {
364 let micros_str = format!("{:06}", micros);
365 let micros_str_trimmed = micros_str.trim_end_matches('0');
366 format!("{}.{}", base, micros_str_trimmed)
367 }
368 }
369}
370
371fn convert_object_to_json(buffer: &mut impl Write, obj: &VariantObject) -> Result<(), ArrowError> {
373 write!(buffer, "{{")?;
374
375 let mut first = true;
377
378 for (key, value) in obj.iter() {
379 if !first {
380 write!(buffer, ",")?;
381 }
382 first = false;
383
384 let json_key = serde_json::to_string(key).map_err(|e| {
386 ArrowError::InvalidArgumentError(format!("JSON key encoding error: {e}"))
387 })?;
388 write!(buffer, "{json_key}:")?;
389
390 value.to_json(buffer)?;
392 }
393
394 write!(buffer, "}}")?;
395 Ok(())
396}
397
398fn convert_array_to_json(buffer: &mut impl Write, arr: &VariantList) -> Result<(), ArrowError> {
400 write!(buffer, "[")?;
401
402 let mut first = true;
403 for element in arr.iter() {
404 if !first {
405 write!(buffer, ",")?;
406 }
407 first = false;
408
409 element.to_json(buffer)?;
410 }
411
412 write!(buffer, "]")?;
413 Ok(())
414}
415
416#[cfg(test)]
417mod tests {
418 use super::*;
419 use chrono::{DateTime, NaiveDate, NaiveTime, Utc};
420 use parquet_variant::{VariantDecimal4, VariantDecimal8, VariantDecimal16};
421
422 #[test]
423 fn test_decimal_edge_cases() -> Result<(), ArrowError> {
424 let negative_variant = Variant::from(VariantDecimal4::try_new(-12345, 3)?);
426 let negative_json = negative_variant.to_json_string()?;
427 assert_eq!(negative_json, "-12.345");
428
429 let large_scale_variant = Variant::from(VariantDecimal8::try_new(123456789, 6)?);
431 let large_scale_json = large_scale_variant.to_json_string()?;
432 assert_eq!(large_scale_json, "123.456789");
433
434 Ok(())
435 }
436
437 #[test]
438 fn test_decimal16_to_json() -> Result<(), ArrowError> {
439 let variant = Variant::from(VariantDecimal16::try_new(123456789012345, 4)?);
440 let json = variant.to_json_string()?;
441 assert_eq!(json, "12345678901.2345");
442
443 let json_value = variant.to_json_value()?;
444 assert!(matches!(json_value, Value::Number(_)));
445
446 let large_variant = Variant::from(VariantDecimal16::try_new(999999999999999999, 2)?);
448 let large_json = large_variant.to_json_string()?;
449 assert!(
451 large_json.starts_with("9999999999999999")
452 || large_json.starts_with("10000000000000000")
453 );
454 Ok(())
455 }
456
457 #[test]
458 fn test_date_to_json() -> Result<(), ArrowError> {
459 let date = NaiveDate::from_ymd_opt(2023, 12, 25).unwrap();
460 let variant = Variant::Date(date);
461 let json = variant.to_json_string()?;
462 assert_eq!(json, "\"2023-12-25\"");
463
464 let json_value = variant.to_json_value()?;
465 assert_eq!(json_value, Value::String("2023-12-25".to_string()));
466
467 let leap_date = NaiveDate::from_ymd_opt(2024, 2, 29).unwrap();
469 let leap_variant = Variant::Date(leap_date);
470 let leap_json = leap_variant.to_json_string()?;
471 assert_eq!(leap_json, "\"2024-02-29\"");
472 Ok(())
473 }
474
475 #[test]
476 fn test_timestamp_micros_to_json() -> Result<(), ArrowError> {
477 let timestamp = DateTime::parse_from_rfc3339("2023-12-25T10:30:45Z")
478 .unwrap()
479 .with_timezone(&Utc);
480 let variant = Variant::TimestampMicros(timestamp);
481 let json = variant.to_json_string()?;
482 assert!(json.contains("2023-12-25T10:30:45"));
483 assert!(json.starts_with('"') && json.ends_with('"'));
484
485 let json_value = variant.to_json_value()?;
486 assert!(matches!(json_value, Value::String(_)));
487 Ok(())
488 }
489
490 #[test]
491 fn test_timestamp_ntz_micros_to_json() -> Result<(), ArrowError> {
492 let naive_timestamp = DateTime::from_timestamp(1703505045, 123456)
493 .unwrap()
494 .naive_utc();
495 let variant = Variant::TimestampNtzMicros(naive_timestamp);
496 let json = variant.to_json_string()?;
497 assert!(json.contains("2023-12-25"));
498 assert!(json.starts_with('"') && json.ends_with('"'));
499
500 let json_value = variant.to_json_value()?;
501 assert!(matches!(json_value, Value::String(_)));
502 Ok(())
503 }
504
505 #[test]
506 fn test_time_to_json() -> Result<(), ArrowError> {
507 let naive_time = NaiveTime::from_num_seconds_from_midnight_opt(12345, 123460708).unwrap();
508 let variant = Variant::Time(naive_time);
509 let json = variant.to_json_string()?;
510 assert_eq!("\"03:25:45.12346\"", json);
511
512 let expected = [
513 (10, "00:00:00.00001"),
514 (10010, "00:00:00.01001"),
515 (100000, "00:00:00.1"),
516 (123450, "00:00:00.12345"),
517 ];
518
519 for (micros, expected_json) in expected {
520 let naive_time =
521 NaiveTime::from_num_seconds_from_midnight_opt(0, micros * 1000).unwrap();
522 let variant = Variant::Time(naive_time);
523 let json = variant.to_json_string()?;
524 assert_eq!(format!("\"{expected_json}\""), json);
525 }
526
527 let json_value = variant.to_json_value()?;
528 assert!(matches!(json_value, Value::String(_)));
529 Ok(())
530 }
531
532 #[test]
533 fn test_timestamp_nanos_to_json() -> Result<(), ArrowError> {
534 let timestamp = DateTime::parse_from_rfc3339("2023-12-25T10:30:45.123456789Z")
535 .unwrap()
536 .with_timezone(&Utc);
537 let variant = Variant::TimestampNanos(timestamp);
538 let json = variant.to_json_string()?;
539 assert_eq!(json, "\"2023-12-25T10:30:45.123456789+00:00\"");
540
541 let json_value = variant.to_json_value()?;
542 assert!(matches!(json_value, Value::String(_)));
543 Ok(())
544 }
545
546 #[test]
547 fn test_timestamp_ntz_nanos_to_json() -> Result<(), ArrowError> {
548 let naive_timestamp = DateTime::from_timestamp(1703505045, 123456789)
549 .unwrap()
550 .naive_utc();
551 let variant = Variant::TimestampNtzNanos(naive_timestamp);
552 let json = variant.to_json_string()?;
553 assert_eq!(json, "\"2023-12-25T11:50:45.123456789\"");
554
555 let json_value = variant.to_json_value()?;
556 assert!(matches!(json_value, Value::String(_)));
557 Ok(())
558 }
559
560 #[test]
561 fn test_binary_to_json() -> Result<(), ArrowError> {
562 let binary_data = b"Hello, World!";
563 let variant = Variant::Binary(binary_data);
564 let json = variant.to_json_string()?;
565
566 assert!(json.starts_with('"') && json.ends_with('"'));
568 assert!(json.len() > 2); let json_value = variant.to_json_value()?;
571 assert!(matches!(json_value, Value::String(_)));
572
573 let empty_variant = Variant::Binary(b"");
575 let empty_json = empty_variant.to_json_string()?;
576 assert_eq!(empty_json, "\"\"");
577
578 let special_variant = Variant::Binary(&[0, 255, 128, 64]);
580 let special_json = special_variant.to_json_string()?;
581 assert!(special_json.starts_with('"') && special_json.ends_with('"'));
582 Ok(())
583 }
584
585 #[test]
586 fn test_string_to_json() -> Result<(), ArrowError> {
587 let variant = Variant::from("hello world");
588 let json = variant.to_json_string()?;
589 assert_eq!(json, "\"hello world\"");
590
591 let json_value = variant.to_json_value()?;
592 assert_eq!(json_value, Value::String("hello world".to_string()));
593 Ok(())
594 }
595
596 #[test]
597 fn test_short_string_to_json() -> Result<(), ArrowError> {
598 use parquet_variant::ShortString;
599 let short_string = ShortString::try_new("short")?;
600 let variant = Variant::ShortString(short_string);
601 let json = variant.to_json_string()?;
602 assert_eq!(json, "\"short\"");
603
604 let json_value = variant.to_json_value()?;
605 assert_eq!(json_value, Value::String("short".to_string()));
606 Ok(())
607 }
608
609 #[test]
610 fn test_uuid_to_json() -> Result<(), ArrowError> {
611 let uuid = uuid::Uuid::parse_str("123e4567-e89b-12d3-a456-426614174000").unwrap();
612 let variant = Variant::Uuid(uuid);
613 let json = variant.to_json_string()?;
614 assert_eq!(json, "\"123e4567-e89b-12d3-a456-426614174000\"");
615
616 let json_value = variant.to_json_value()?;
617 assert_eq!(
618 json_value,
619 Value::String("123e4567-e89b-12d3-a456-426614174000".to_string())
620 );
621 Ok(())
622 }
623
624 #[test]
625 fn test_string_escaping() -> Result<(), ArrowError> {
626 let variant = Variant::from("hello\nworld\t\"quoted\"");
627 let json = variant.to_json_string()?;
628 assert_eq!(json, "\"hello\\nworld\\t\\\"quoted\\\"\"");
629
630 let json_value = variant.to_json_value()?;
631 assert_eq!(
632 json_value,
633 Value::String("hello\nworld\t\"quoted\"".to_string())
634 );
635 Ok(())
636 }
637
638 #[test]
639 fn test_json_buffer_writing() -> Result<(), ArrowError> {
640 let variant = Variant::Int8(123);
641 let mut buffer = Vec::new();
642 variant.to_json(&mut buffer)?;
643
644 let result = String::from_utf8(buffer)
645 .map_err(|e| ArrowError::InvalidArgumentError(e.to_string()))?;
646 assert_eq!(result, "123");
647 Ok(())
648 }
649
650 struct JsonTest {
652 variant: Variant<'static, 'static>,
653 expected_json: &'static str,
654 expected_value: Value,
655 }
656
657 impl JsonTest {
658 fn run(self) {
659 let json_string = self
660 .variant
661 .to_json_string()
662 .expect("variant_to_json_string should succeed");
663 assert_eq!(
664 json_string, self.expected_json,
665 "JSON string mismatch for variant: {:?}",
666 self.variant
667 );
668
669 let json_value = self
670 .variant
671 .to_json_value()
672 .expect("variant_to_json_value should succeed");
673
674 match (&json_value, &self.expected_value) {
676 (Value::Number(actual), Value::Number(expected)) => {
677 let actual_f64 = actual.as_f64().unwrap_or(0.0);
678 let expected_f64 = expected.as_f64().unwrap_or(0.0);
679 assert!(
680 (actual_f64 - expected_f64).abs() < f64::EPSILON,
681 "JSON value mismatch for variant: {:?}, got {}, expected {}",
682 self.variant,
683 actual_f64,
684 expected_f64
685 );
686 }
687 _ => {
688 assert_eq!(
689 json_value, self.expected_value,
690 "JSON value mismatch for variant: {:?}",
691 self.variant
692 );
693 }
694 }
695
696 let parsed: Value =
698 serde_json::from_str(&json_string).expect("Generated JSON should be valid");
699 match (&parsed, &self.expected_value) {
701 (Value::Number(actual), Value::Number(expected)) => {
702 let actual_f64 = actual.as_f64().unwrap_or(0.0);
703 let expected_f64 = expected.as_f64().unwrap_or(0.0);
704 assert!(
705 (actual_f64 - expected_f64).abs() < f64::EPSILON,
706 "Parsed JSON mismatch for variant: {:?}, got {}, expected {}",
707 self.variant,
708 actual_f64,
709 expected_f64
710 );
711 }
712 _ => {
713 assert_eq!(
714 parsed, self.expected_value,
715 "Parsed JSON mismatch for variant: {:?}",
716 self.variant
717 );
718 }
719 }
720 }
721 }
722
723 #[test]
724 fn test_primitive_json_conversion() {
725 use parquet_variant::ShortString;
726
727 JsonTest {
729 variant: Variant::Null,
730 expected_json: "null",
731 expected_value: Value::Null,
732 }
733 .run();
734
735 JsonTest {
737 variant: Variant::BooleanTrue,
738 expected_json: "true",
739 expected_value: Value::Bool(true),
740 }
741 .run();
742
743 JsonTest {
744 variant: Variant::BooleanFalse,
745 expected_json: "false",
746 expected_value: Value::Bool(false),
747 }
748 .run();
749
750 JsonTest {
752 variant: Variant::Int8(42),
753 expected_json: "42",
754 expected_value: Value::Number(42.into()),
755 }
756 .run();
757
758 JsonTest {
759 variant: Variant::Int8(-128),
760 expected_json: "-128",
761 expected_value: Value::Number((-128).into()),
762 }
763 .run();
764
765 JsonTest {
766 variant: Variant::Int16(32767),
767 expected_json: "32767",
768 expected_value: Value::Number(32767.into()),
769 }
770 .run();
771
772 JsonTest {
773 variant: Variant::Int16(-32768),
774 expected_json: "-32768",
775 expected_value: Value::Number((-32768).into()),
776 }
777 .run();
778
779 JsonTest {
780 variant: Variant::Int32(2147483647),
781 expected_json: "2147483647",
782 expected_value: Value::Number(2147483647.into()),
783 }
784 .run();
785
786 JsonTest {
787 variant: Variant::Int32(-2147483648),
788 expected_json: "-2147483648",
789 expected_value: Value::Number((-2147483648).into()),
790 }
791 .run();
792
793 JsonTest {
794 variant: Variant::Int64(9223372036854775807),
795 expected_json: "9223372036854775807",
796 expected_value: Value::Number(9223372036854775807i64.into()),
797 }
798 .run();
799
800 JsonTest {
801 variant: Variant::Int64(-9223372036854775808),
802 expected_json: "-9223372036854775808",
803 expected_value: Value::Number((-9223372036854775808i64).into()),
804 }
805 .run();
806
807 JsonTest {
809 variant: Variant::Float(3.5),
810 expected_json: "3.5",
811 expected_value: serde_json::Number::from_f64(3.5)
812 .map(Value::Number)
813 .unwrap(),
814 }
815 .run();
816
817 JsonTest {
818 variant: Variant::Float(0.0),
819 expected_json: "0",
820 expected_value: Value::Number(0.into()), }
822 .run();
823
824 JsonTest {
825 variant: Variant::Float(-1.5),
826 expected_json: "-1.5",
827 expected_value: serde_json::Number::from_f64(-1.5)
828 .map(Value::Number)
829 .unwrap(),
830 }
831 .run();
832
833 JsonTest {
834 variant: Variant::Double(std::f64::consts::E),
835 expected_json: "2.718281828459045",
836 expected_value: serde_json::Number::from_f64(std::f64::consts::E)
837 .map(Value::Number)
838 .unwrap(),
839 }
840 .run();
841
842 JsonTest {
844 variant: Variant::from(VariantDecimal4::try_new(12345, 2).unwrap()),
845 expected_json: "123.45",
846 expected_value: serde_json::Number::from_f64(123.45)
847 .map(Value::Number)
848 .unwrap(),
849 }
850 .run();
851
852 JsonTest {
853 variant: Variant::from(VariantDecimal4::try_new(42, 0).unwrap()),
854 expected_json: "42",
855 expected_value: serde_json::Number::from_f64(42.0)
856 .map(Value::Number)
857 .unwrap(),
858 }
859 .run();
860
861 JsonTest {
862 variant: Variant::from(VariantDecimal8::try_new(1234567890, 3).unwrap()),
863 expected_json: "1234567.89",
864 expected_value: serde_json::Number::from_f64(1234567.89)
865 .map(Value::Number)
866 .unwrap(),
867 }
868 .run();
869
870 JsonTest {
871 variant: Variant::from(VariantDecimal16::try_new(123456789012345, 4).unwrap()),
872 expected_json: "12345678901.2345",
873 expected_value: serde_json::Number::from_f64(12345678901.2345)
874 .map(Value::Number)
875 .unwrap(),
876 }
877 .run();
878
879 JsonTest {
881 variant: Variant::from("hello world"),
882 expected_json: "\"hello world\"",
883 expected_value: Value::String("hello world".to_string()),
884 }
885 .run();
886
887 JsonTest {
888 variant: Variant::from(""),
889 expected_json: "\"\"",
890 expected_value: Value::String("".to_string()),
891 }
892 .run();
893
894 JsonTest {
895 variant: Variant::ShortString(ShortString::try_new("test").unwrap()),
896 expected_json: "\"test\"",
897 expected_value: Value::String("test".to_string()),
898 }
899 .run();
900
901 JsonTest {
903 variant: Variant::Date(NaiveDate::from_ymd_opt(2023, 12, 25).unwrap()),
904 expected_json: "\"2023-12-25\"",
905 expected_value: Value::String("2023-12-25".to_string()),
906 }
907 .run();
908
909 JsonTest {
911 variant: Variant::Binary(b"test"),
912 expected_json: "\"dGVzdA==\"", expected_value: Value::String("dGVzdA==".to_string()),
914 }
915 .run();
916
917 JsonTest {
918 variant: Variant::Binary(b""),
919 expected_json: "\"\"", expected_value: Value::String("".to_string()),
921 }
922 .run();
923
924 JsonTest {
925 variant: Variant::Binary(b"binary data"),
926 expected_json: "\"YmluYXJ5IGRhdGE=\"", expected_value: Value::String("YmluYXJ5IGRhdGE=".to_string()),
928 }
929 .run();
930 }
931
932 #[test]
933 fn test_string_escaping_comprehensive() {
934 JsonTest {
936 variant: Variant::from("line1\nline2\ttab\"quote\"\\backslash"),
937 expected_json: "\"line1\\nline2\\ttab\\\"quote\\\"\\\\backslash\"",
938 expected_value: Value::String("line1\nline2\ttab\"quote\"\\backslash".to_string()),
939 }
940 .run();
941
942 JsonTest {
943 variant: Variant::from("Hello δΈη π"),
944 expected_json: "\"Hello δΈη π\"",
945 expected_value: Value::String("Hello δΈη π".to_string()),
946 }
947 .run();
948 }
949
950 #[test]
951 fn test_buffer_writing_variants() -> Result<(), ArrowError> {
952 let variant = Variant::from("test buffer writing");
953
954 let mut buffer = Vec::new();
956 variant.to_json(&mut buffer)?;
957 let result = String::from_utf8(buffer)
958 .map_err(|e| ArrowError::InvalidArgumentError(e.to_string()))?;
959 assert_eq!(result, "\"test buffer writing\"");
960
961 let mut buffer = vec![];
963 variant.to_json(&mut buffer)?;
964 let result = String::from_utf8(buffer)
965 .map_err(|e| ArrowError::InvalidArgumentError(e.to_string()))?;
966 assert_eq!(result, "\"test buffer writing\"");
967
968 Ok(())
969 }
970
971 #[test]
972 fn test_simple_object_to_json() -> Result<(), ArrowError> {
973 use parquet_variant::VariantBuilder;
974
975 let mut builder = VariantBuilder::new();
977
978 builder
979 .new_object()
980 .with_field("name", "Alice")
981 .with_field("age", 30i32)
982 .with_field("active", true)
983 .with_field("score", 95.5f64)
984 .finish();
985
986 let (metadata, value) = builder.finish();
987 let variant = Variant::try_new(&metadata, &value)?;
988 let json = variant.to_json_string()?;
989
990 let parsed: Value = serde_json::from_str(&json).unwrap();
992 let obj = parsed.as_object().expect("expected JSON object");
993 assert_eq!(obj.get("name"), Some(&Value::String("Alice".to_string())));
994 assert_eq!(obj.get("age"), Some(&Value::Number(30.into())));
995 assert_eq!(obj.get("active"), Some(&Value::Bool(true)));
996 assert!(matches!(obj.get("score"), Some(Value::Number(_))));
997 assert_eq!(obj.len(), 4);
998
999 let json_value = variant.to_json_value()?;
1001 assert!(matches!(json_value, Value::Object(_)));
1002
1003 Ok(())
1004 }
1005
1006 #[test]
1007 fn test_empty_object_to_json() -> Result<(), ArrowError> {
1008 use parquet_variant::VariantBuilder;
1009
1010 let mut builder = VariantBuilder::new();
1011
1012 {
1013 let obj = builder.new_object();
1014 obj.finish();
1015 }
1016
1017 let (metadata, value) = builder.finish();
1018 let variant = Variant::try_new(&metadata, &value)?;
1019 let json = variant.to_json_string()?;
1020 assert_eq!(json, "{}");
1021
1022 let json_value = variant.to_json_value()?;
1023 assert_eq!(json_value, Value::Object(serde_json::Map::new()));
1024
1025 Ok(())
1026 }
1027
1028 #[test]
1029 fn test_object_with_special_characters_to_json() -> Result<(), ArrowError> {
1030 use parquet_variant::VariantBuilder;
1031
1032 let mut builder = VariantBuilder::new();
1033
1034 builder
1035 .new_object()
1036 .with_field("message", "Hello \"World\"\nWith\tTabs")
1037 .with_field("path", "C:\\Users\\Alice\\Documents")
1038 .with_field("unicode", "π Smiley")
1039 .finish();
1040
1041 let (metadata, value) = builder.finish();
1042 let variant = Variant::try_new(&metadata, &value)?;
1043 let json = variant.to_json_string()?;
1044
1045 assert!(json.contains("Hello \\\"World\\\"\\nWith\\tTabs"));
1047 assert!(json.contains("C:\\\\Users\\\\Alice\\\\Documents"));
1048 assert!(json.contains("π Smiley"));
1049
1050 let parsed: Value = serde_json::from_str(&json).unwrap();
1052 assert!(matches!(parsed, Value::Object(_)));
1053
1054 Ok(())
1055 }
1056
1057 #[test]
1058 fn test_simple_list_to_json() -> Result<(), ArrowError> {
1059 use parquet_variant::VariantBuilder;
1060
1061 let mut builder = VariantBuilder::new();
1062
1063 builder
1064 .new_list()
1065 .with_value(1i32)
1066 .with_value(2i32)
1067 .with_value(3i32)
1068 .with_value(4i32)
1069 .with_value(5i32)
1070 .finish();
1071
1072 let (metadata, value) = builder.finish();
1073 let variant = Variant::try_new(&metadata, &value)?;
1074 let json = variant.to_json_string()?;
1075 assert_eq!(json, "[1,2,3,4,5]");
1076
1077 let json_value = variant.to_json_value()?;
1078 let arr = json_value.as_array().expect("expected JSON array");
1079 assert_eq!(arr.len(), 5);
1080 assert_eq!(arr[0], Value::Number(1.into()));
1081 assert_eq!(arr[4], Value::Number(5.into()));
1082
1083 Ok(())
1084 }
1085
1086 #[test]
1087 fn test_empty_list_to_json() -> Result<(), ArrowError> {
1088 use parquet_variant::VariantBuilder;
1089
1090 let mut builder = VariantBuilder::new();
1091
1092 {
1093 let list = builder.new_list();
1094 list.finish();
1095 }
1096
1097 let (metadata, value) = builder.finish();
1098 let variant = Variant::try_new(&metadata, &value)?;
1099 let json = variant.to_json_string()?;
1100 assert_eq!(json, "[]");
1101
1102 let json_value = variant.to_json_value()?;
1103 assert_eq!(json_value, Value::Array(vec![]));
1104
1105 Ok(())
1106 }
1107
1108 #[test]
1109 fn test_mixed_type_list_to_json() -> Result<(), ArrowError> {
1110 use parquet_variant::VariantBuilder;
1111
1112 let mut builder = VariantBuilder::new();
1113
1114 builder
1115 .new_list()
1116 .with_value("hello")
1117 .with_value(42i32)
1118 .with_value(true)
1119 .with_value(()) .with_value(std::f64::consts::PI)
1121 .finish();
1122
1123 let (metadata, value) = builder.finish();
1124 let variant = Variant::try_new(&metadata, &value)?;
1125 let json = variant.to_json_string()?;
1126
1127 let parsed: Value = serde_json::from_str(&json).unwrap();
1128 let arr = parsed.as_array().expect("expected JSON array");
1129 assert_eq!(arr.len(), 5);
1130 assert_eq!(arr[0], Value::String("hello".to_string()));
1131 assert_eq!(arr[1], Value::Number(42.into()));
1132 assert_eq!(arr[2], Value::Bool(true));
1133 assert_eq!(arr[3], Value::Null);
1134 assert!(matches!(arr[4], Value::Number(_)));
1135
1136 Ok(())
1137 }
1138
1139 #[test]
1140 fn test_object_field_ordering_in_json() -> Result<(), ArrowError> {
1141 use parquet_variant::VariantBuilder;
1142
1143 let mut builder = VariantBuilder::new();
1144
1145 {
1146 let mut obj = builder.new_object();
1147 obj.insert("zebra", "last");
1149 obj.insert("alpha", "first");
1150 obj.insert("beta", "second");
1151 obj.finish();
1152 }
1153
1154 let (metadata, value) = builder.finish();
1155 let variant = Variant::try_new(&metadata, &value)?;
1156 let json = variant.to_json_string()?;
1157
1158 let parsed: Value = serde_json::from_str(&json).unwrap();
1160 let obj = parsed.as_object().expect("expected JSON object");
1161 assert_eq!(obj.len(), 3);
1162 assert_eq!(obj.get("alpha"), Some(&Value::String("first".to_string())));
1163 assert_eq!(obj.get("beta"), Some(&Value::String("second".to_string())));
1164 assert_eq!(obj.get("zebra"), Some(&Value::String("last".to_string())));
1165
1166 Ok(())
1167 }
1168
1169 #[test]
1170 fn test_list_with_various_primitive_types_to_json() -> Result<(), ArrowError> {
1171 use parquet_variant::VariantBuilder;
1172
1173 let mut builder = VariantBuilder::new();
1174
1175 builder
1176 .new_list()
1177 .with_value("string_value")
1178 .with_value(42i32)
1179 .with_value(true)
1180 .with_value(std::f64::consts::PI)
1181 .with_value(false)
1182 .with_value(()) .with_value(100i64)
1184 .finish();
1185
1186 let (metadata, value) = builder.finish();
1187 let variant = Variant::try_new(&metadata, &value)?;
1188 let json = variant.to_json_string()?;
1189
1190 let parsed: Value = serde_json::from_str(&json).unwrap();
1191 let arr = parsed.as_array().expect("expected JSON array");
1192 assert_eq!(arr.len(), 7);
1193 assert_eq!(arr[0], Value::String("string_value".to_string()));
1194 assert_eq!(arr[1], Value::Number(42.into()));
1195 assert_eq!(arr[2], Value::Bool(true));
1196 assert!(matches!(arr[3], Value::Number(_))); assert_eq!(arr[4], Value::Bool(false));
1198 assert_eq!(arr[5], Value::Null);
1199 assert_eq!(arr[6], Value::Number(100.into()));
1200
1201 Ok(())
1202 }
1203
1204 #[test]
1205 fn test_object_with_various_primitive_types_to_json() -> Result<(), ArrowError> {
1206 use parquet_variant::VariantBuilder;
1207
1208 let mut builder = VariantBuilder::new();
1209
1210 {
1211 let mut obj = builder.new_object();
1212 obj.insert("string_field", "test_string");
1213 obj.insert("int_field", 123i32);
1214 obj.insert("bool_field", true);
1215 obj.insert("float_field", 2.71f64);
1216 obj.insert("null_field", ());
1217 obj.insert("long_field", 999i64);
1218 obj.finish();
1219 }
1220
1221 let (metadata, value) = builder.finish();
1222 let variant = Variant::try_new(&metadata, &value)?;
1223 let json = variant.to_json_string()?;
1224
1225 let parsed: Value = serde_json::from_str(&json).unwrap();
1226 let obj = parsed.as_object().expect("expected JSON object");
1227 assert_eq!(obj.len(), 6);
1228 assert_eq!(
1229 obj.get("string_field"),
1230 Some(&Value::String("test_string".to_string()))
1231 );
1232 assert_eq!(obj.get("int_field"), Some(&Value::Number(123.into())));
1233 assert_eq!(obj.get("bool_field"), Some(&Value::Bool(true)));
1234 assert!(matches!(obj.get("float_field"), Some(Value::Number(_))));
1235 assert_eq!(obj.get("null_field"), Some(&Value::Null));
1236 assert_eq!(obj.get("long_field"), Some(&Value::Number(999.into())));
1237
1238 Ok(())
1239 }
1240
1241 #[test]
1242 fn test_decimal_precision_behavior() -> Result<(), ArrowError> {
1243 let high_precision_decimal8 = Variant::from(VariantDecimal8::try_new(
1246 9007199254740993, 6,
1248 )?);
1249
1250 let json_string = high_precision_decimal8.to_json_string()?;
1251 let json_value = high_precision_decimal8.to_json_value()?;
1252
1253 let parsed: Value = serde_json::from_str(&json_string).unwrap();
1256 assert_eq!(parsed, json_value);
1257
1258 let exact_decimal = Variant::from(VariantDecimal8::try_new(
1260 1234567890000, 6,
1262 )?);
1263
1264 let json_string_exact = exact_decimal.to_json_string()?;
1265 assert_eq!(json_string_exact, "1234567.89");
1266
1267 let integer_decimal = Variant::from(VariantDecimal8::try_new(
1269 42000000, 6,
1271 )?);
1272
1273 let json_string_integer = integer_decimal.to_json_string()?;
1274 assert_eq!(json_string_integer, "42");
1275
1276 Ok(())
1277 }
1278
1279 #[test]
1280 fn test_float_nan_inf_handling() -> Result<(), ArrowError> {
1281 let nan_variant = Variant::Float(f32::NAN);
1283 let nan_result = nan_variant.to_json_value();
1284 assert!(nan_result.is_err());
1285 assert!(
1286 nan_result
1287 .unwrap_err()
1288 .to_string()
1289 .contains("Invalid float value")
1290 );
1291
1292 let pos_inf_variant = Variant::Float(f32::INFINITY);
1294 let pos_inf_result = pos_inf_variant.to_json_value();
1295 assert!(pos_inf_result.is_err());
1296 assert!(
1297 pos_inf_result
1298 .unwrap_err()
1299 .to_string()
1300 .contains("Invalid float value")
1301 );
1302
1303 let neg_inf_variant = Variant::Float(f32::NEG_INFINITY);
1305 let neg_inf_result = neg_inf_variant.to_json_value();
1306 assert!(neg_inf_result.is_err());
1307 assert!(
1308 neg_inf_result
1309 .unwrap_err()
1310 .to_string()
1311 .contains("Invalid float value")
1312 );
1313
1314 let nan_double_variant = Variant::Double(f64::NAN);
1316 let nan_double_result = nan_double_variant.to_json_value();
1317 assert!(nan_double_result.is_err());
1318 assert!(
1319 nan_double_result
1320 .unwrap_err()
1321 .to_string()
1322 .contains("Invalid double value")
1323 );
1324
1325 let pos_inf_double_variant = Variant::Double(f64::INFINITY);
1326 let pos_inf_double_result = pos_inf_double_variant.to_json_value();
1327 assert!(pos_inf_double_result.is_err());
1328 assert!(
1329 pos_inf_double_result
1330 .unwrap_err()
1331 .to_string()
1332 .contains("Invalid double value")
1333 );
1334
1335 let neg_inf_double_variant = Variant::Double(f64::NEG_INFINITY);
1336 let neg_inf_double_result = neg_inf_double_variant.to_json_value();
1337 assert!(neg_inf_double_result.is_err());
1338 assert!(
1339 neg_inf_double_result
1340 .unwrap_err()
1341 .to_string()
1342 .contains("Invalid double value")
1343 );
1344
1345 let normal_float = Variant::Float(std::f32::consts::PI);
1347 let normal_result = normal_float.to_json_value()?;
1348 assert!(matches!(normal_result, Value::Number(_)));
1349
1350 let normal_double = Variant::Double(std::f64::consts::E);
1351 let normal_double_result = normal_double.to_json_value()?;
1352 assert!(matches!(normal_double_result, Value::Number(_)));
1353
1354 Ok(())
1355 }
1356}