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 VariantToJson for Variant<'_, '_> {
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!("{}", ts.format(&format!("%Y-%m-%dT%H:%M:%S%.{precision}f")));
348 ts.format(format_str.as_str()).to_string()
349}
350
351fn format_binary_base64(bytes: &[u8]) -> String {
352 general_purpose::STANDARD.encode(bytes)
353}
354
355fn format_time_ntz_str(time: &chrono::NaiveTime) -> String {
356 let base = time.format("%H:%M:%S").to_string();
357 let micros = time.nanosecond() / 1000;
358 match micros {
359 0 => format!("{}.{}", base, 0),
360 _ => {
361 let micros_str = format!("{micros:06}");
362 let micros_str_trimmed = micros_str.trim_end_matches('0');
363 format!("{base}.{micros_str_trimmed}")
364 }
365 }
366}
367
368fn convert_object_to_json(buffer: &mut impl Write, obj: &VariantObject) -> Result<(), ArrowError> {
370 write!(buffer, "{{")?;
371
372 let mut first = true;
374
375 for (key, value) in obj.iter() {
376 if !first {
377 write!(buffer, ",")?;
378 }
379 first = false;
380
381 let json_key = serde_json::to_string(key).map_err(|e| {
383 ArrowError::InvalidArgumentError(format!("JSON key encoding error: {e}"))
384 })?;
385 write!(buffer, "{json_key}:")?;
386
387 value.to_json(buffer)?;
389 }
390
391 write!(buffer, "}}")?;
392 Ok(())
393}
394
395fn convert_array_to_json(buffer: &mut impl Write, arr: &VariantList) -> Result<(), ArrowError> {
397 write!(buffer, "[")?;
398
399 let mut first = true;
400 for element in arr.iter() {
401 if !first {
402 write!(buffer, ",")?;
403 }
404 first = false;
405
406 element.to_json(buffer)?;
407 }
408
409 write!(buffer, "]")?;
410 Ok(())
411}
412
413#[cfg(test)]
414mod tests {
415 use super::*;
416 use chrono::{DateTime, NaiveDate, NaiveTime, Utc};
417 use parquet_variant::{VariantDecimal4, VariantDecimal8, VariantDecimal16};
418
419 #[test]
420 fn test_decimal_edge_cases() -> Result<(), ArrowError> {
421 let negative_variant = Variant::from(VariantDecimal4::try_new(-12345, 3)?);
423 let negative_json = negative_variant.to_json_string()?;
424 assert_eq!(negative_json, "-12.345");
425
426 let large_scale_variant = Variant::from(VariantDecimal8::try_new(123456789, 6)?);
428 let large_scale_json = large_scale_variant.to_json_string()?;
429 assert_eq!(large_scale_json, "123.456789");
430
431 Ok(())
432 }
433
434 #[test]
435 fn test_decimal16_to_json() -> Result<(), ArrowError> {
436 let variant = Variant::from(VariantDecimal16::try_new(123456789012345, 4)?);
437 let json = variant.to_json_string()?;
438 assert_eq!(json, "12345678901.2345");
439
440 let json_value = variant.to_json_value()?;
441 assert!(matches!(json_value, Value::Number(_)));
442
443 let large_variant = Variant::from(VariantDecimal16::try_new(999999999999999999, 2)?);
445 let large_json = large_variant.to_json_string()?;
446 assert!(
448 large_json.starts_with("9999999999999999")
449 || large_json.starts_with("10000000000000000")
450 );
451 Ok(())
452 }
453
454 #[test]
455 fn test_date_to_json() -> Result<(), ArrowError> {
456 let date = NaiveDate::from_ymd_opt(2023, 12, 25).unwrap();
457 let variant = Variant::Date(date);
458 let json = variant.to_json_string()?;
459 assert_eq!(json, "\"2023-12-25\"");
460
461 let json_value = variant.to_json_value()?;
462 assert_eq!(json_value, Value::String("2023-12-25".to_string()));
463
464 let leap_date = NaiveDate::from_ymd_opt(2024, 2, 29).unwrap();
466 let leap_variant = Variant::Date(leap_date);
467 let leap_json = leap_variant.to_json_string()?;
468 assert_eq!(leap_json, "\"2024-02-29\"");
469 Ok(())
470 }
471
472 #[test]
473 fn test_timestamp_micros_to_json() -> Result<(), ArrowError> {
474 let timestamp = DateTime::parse_from_rfc3339("2023-12-25T10:30:45Z")
475 .unwrap()
476 .with_timezone(&Utc);
477 let variant = Variant::TimestampMicros(timestamp);
478 let json = variant.to_json_string()?;
479 assert!(json.contains("2023-12-25T10:30:45"));
480 assert!(json.starts_with('"') && json.ends_with('"'));
481
482 let json_value = variant.to_json_value()?;
483 assert!(matches!(json_value, Value::String(_)));
484 Ok(())
485 }
486
487 #[test]
488 fn test_timestamp_ntz_micros_to_json() -> Result<(), ArrowError> {
489 let naive_timestamp = DateTime::from_timestamp(1703505045, 123456)
490 .unwrap()
491 .naive_utc();
492 let variant = Variant::TimestampNtzMicros(naive_timestamp);
493 let json = variant.to_json_string()?;
494 assert!(json.contains("2023-12-25"));
495 assert!(json.starts_with('"') && json.ends_with('"'));
496
497 let json_value = variant.to_json_value()?;
498 assert!(matches!(json_value, Value::String(_)));
499 Ok(())
500 }
501
502 #[test]
503 fn test_time_to_json() -> Result<(), ArrowError> {
504 let naive_time = NaiveTime::from_num_seconds_from_midnight_opt(12345, 123460708).unwrap();
505 let variant = Variant::Time(naive_time);
506 let json = variant.to_json_string()?;
507 assert_eq!("\"03:25:45.12346\"", json);
508
509 let expected = [
510 (10, "00:00:00.00001"),
511 (10010, "00:00:00.01001"),
512 (100000, "00:00:00.1"),
513 (123450, "00:00:00.12345"),
514 ];
515
516 for (micros, expected_json) in expected {
517 let naive_time =
518 NaiveTime::from_num_seconds_from_midnight_opt(0, micros * 1000).unwrap();
519 let variant = Variant::Time(naive_time);
520 let json = variant.to_json_string()?;
521 assert_eq!(format!("\"{expected_json}\""), json);
522 }
523
524 let json_value = variant.to_json_value()?;
525 assert!(matches!(json_value, Value::String(_)));
526 Ok(())
527 }
528
529 #[test]
530 fn test_timestamp_nanos_to_json() -> Result<(), ArrowError> {
531 let timestamp = DateTime::parse_from_rfc3339("2023-12-25T10:30:45.123456789Z")
532 .unwrap()
533 .with_timezone(&Utc);
534 let variant = Variant::TimestampNanos(timestamp);
535 let json = variant.to_json_string()?;
536 assert_eq!(json, "\"2023-12-25T10:30:45.123456789+00:00\"");
537
538 let json_value = variant.to_json_value()?;
539 assert!(matches!(json_value, Value::String(_)));
540 Ok(())
541 }
542
543 #[test]
544 fn test_timestamp_ntz_nanos_to_json() -> Result<(), ArrowError> {
545 let naive_timestamp = DateTime::from_timestamp(1703505045, 123456789)
546 .unwrap()
547 .naive_utc();
548 let variant = Variant::TimestampNtzNanos(naive_timestamp);
549 let json = variant.to_json_string()?;
550 assert_eq!(json, "\"2023-12-25T11:50:45.123456789\"");
551
552 let json_value = variant.to_json_value()?;
553 assert!(matches!(json_value, Value::String(_)));
554 Ok(())
555 }
556
557 #[test]
558 fn test_binary_to_json() -> Result<(), ArrowError> {
559 let binary_data = b"Hello, World!";
560 let variant = Variant::Binary(binary_data);
561 let json = variant.to_json_string()?;
562
563 assert!(json.starts_with('"') && json.ends_with('"'));
565 assert!(json.len() > 2); let json_value = variant.to_json_value()?;
568 assert!(matches!(json_value, Value::String(_)));
569
570 let empty_variant = Variant::Binary(b"");
572 let empty_json = empty_variant.to_json_string()?;
573 assert_eq!(empty_json, "\"\"");
574
575 let special_variant = Variant::Binary(&[0, 255, 128, 64]);
577 let special_json = special_variant.to_json_string()?;
578 assert!(special_json.starts_with('"') && special_json.ends_with('"'));
579 Ok(())
580 }
581
582 #[test]
583 fn test_string_to_json() -> Result<(), ArrowError> {
584 let variant = Variant::from("hello world");
585 let json = variant.to_json_string()?;
586 assert_eq!(json, "\"hello world\"");
587
588 let json_value = variant.to_json_value()?;
589 assert_eq!(json_value, Value::String("hello world".to_string()));
590 Ok(())
591 }
592
593 #[test]
594 fn test_short_string_to_json() -> Result<(), ArrowError> {
595 use parquet_variant::ShortString;
596 let short_string = ShortString::try_new("short")?;
597 let variant = Variant::ShortString(short_string);
598 let json = variant.to_json_string()?;
599 assert_eq!(json, "\"short\"");
600
601 let json_value = variant.to_json_value()?;
602 assert_eq!(json_value, Value::String("short".to_string()));
603 Ok(())
604 }
605
606 #[test]
607 fn test_uuid_to_json() -> Result<(), ArrowError> {
608 let uuid = uuid::Uuid::parse_str("123e4567-e89b-12d3-a456-426614174000").unwrap();
609 let variant = Variant::Uuid(uuid);
610 let json = variant.to_json_string()?;
611 assert_eq!(json, "\"123e4567-e89b-12d3-a456-426614174000\"");
612
613 let json_value = variant.to_json_value()?;
614 assert_eq!(
615 json_value,
616 Value::String("123e4567-e89b-12d3-a456-426614174000".to_string())
617 );
618 Ok(())
619 }
620
621 #[test]
622 fn test_string_escaping() -> Result<(), ArrowError> {
623 let variant = Variant::from("hello\nworld\t\"quoted\"");
624 let json = variant.to_json_string()?;
625 assert_eq!(json, "\"hello\\nworld\\t\\\"quoted\\\"\"");
626
627 let json_value = variant.to_json_value()?;
628 assert_eq!(
629 json_value,
630 Value::String("hello\nworld\t\"quoted\"".to_string())
631 );
632 Ok(())
633 }
634
635 #[test]
636 fn test_json_buffer_writing() -> Result<(), ArrowError> {
637 let variant = Variant::Int8(123);
638 let mut buffer = Vec::new();
639 variant.to_json(&mut buffer)?;
640
641 let result = String::from_utf8(buffer)
642 .map_err(|e| ArrowError::InvalidArgumentError(e.to_string()))?;
643 assert_eq!(result, "123");
644 Ok(())
645 }
646
647 struct JsonTest {
649 variant: Variant<'static, 'static>,
650 expected_json: &'static str,
651 expected_value: Value,
652 }
653
654 impl JsonTest {
655 fn run(self) {
656 let json_string = self
657 .variant
658 .to_json_string()
659 .expect("variant_to_json_string should succeed");
660 assert_eq!(
661 json_string, self.expected_json,
662 "JSON string mismatch for variant: {:?}",
663 self.variant
664 );
665
666 let json_value = self
667 .variant
668 .to_json_value()
669 .expect("variant_to_json_value should succeed");
670
671 match (&json_value, &self.expected_value) {
673 (Value::Number(actual), Value::Number(expected)) => {
674 let actual_f64 = actual.as_f64().unwrap_or(0.0);
675 let expected_f64 = expected.as_f64().unwrap_or(0.0);
676 assert!(
677 (actual_f64 - expected_f64).abs() < f64::EPSILON,
678 "JSON value mismatch for variant: {:?}, got {}, expected {}",
679 self.variant,
680 actual_f64,
681 expected_f64
682 );
683 }
684 _ => {
685 assert_eq!(
686 json_value, self.expected_value,
687 "JSON value mismatch for variant: {:?}",
688 self.variant
689 );
690 }
691 }
692
693 let parsed: Value =
695 serde_json::from_str(&json_string).expect("Generated JSON should be valid");
696 match (&parsed, &self.expected_value) {
698 (Value::Number(actual), Value::Number(expected)) => {
699 let actual_f64 = actual.as_f64().unwrap_or(0.0);
700 let expected_f64 = expected.as_f64().unwrap_or(0.0);
701 assert!(
702 (actual_f64 - expected_f64).abs() < f64::EPSILON,
703 "Parsed JSON mismatch for variant: {:?}, got {}, expected {}",
704 self.variant,
705 actual_f64,
706 expected_f64
707 );
708 }
709 _ => {
710 assert_eq!(
711 parsed, self.expected_value,
712 "Parsed JSON mismatch for variant: {:?}",
713 self.variant
714 );
715 }
716 }
717 }
718 }
719
720 #[test]
721 fn test_primitive_json_conversion() {
722 use parquet_variant::ShortString;
723
724 JsonTest {
726 variant: Variant::Null,
727 expected_json: "null",
728 expected_value: Value::Null,
729 }
730 .run();
731
732 JsonTest {
734 variant: Variant::BooleanTrue,
735 expected_json: "true",
736 expected_value: Value::Bool(true),
737 }
738 .run();
739
740 JsonTest {
741 variant: Variant::BooleanFalse,
742 expected_json: "false",
743 expected_value: Value::Bool(false),
744 }
745 .run();
746
747 JsonTest {
749 variant: Variant::Int8(42),
750 expected_json: "42",
751 expected_value: Value::Number(42.into()),
752 }
753 .run();
754
755 JsonTest {
756 variant: Variant::Int8(-128),
757 expected_json: "-128",
758 expected_value: Value::Number((-128).into()),
759 }
760 .run();
761
762 JsonTest {
763 variant: Variant::Int16(32767),
764 expected_json: "32767",
765 expected_value: Value::Number(32767.into()),
766 }
767 .run();
768
769 JsonTest {
770 variant: Variant::Int16(-32768),
771 expected_json: "-32768",
772 expected_value: Value::Number((-32768).into()),
773 }
774 .run();
775
776 JsonTest {
777 variant: Variant::Int32(2147483647),
778 expected_json: "2147483647",
779 expected_value: Value::Number(2147483647.into()),
780 }
781 .run();
782
783 JsonTest {
784 variant: Variant::Int32(-2147483648),
785 expected_json: "-2147483648",
786 expected_value: Value::Number((-2147483648).into()),
787 }
788 .run();
789
790 JsonTest {
791 variant: Variant::Int64(9223372036854775807),
792 expected_json: "9223372036854775807",
793 expected_value: Value::Number(9223372036854775807i64.into()),
794 }
795 .run();
796
797 JsonTest {
798 variant: Variant::Int64(-9223372036854775808),
799 expected_json: "-9223372036854775808",
800 expected_value: Value::Number((-9223372036854775808i64).into()),
801 }
802 .run();
803
804 JsonTest {
806 variant: Variant::Float(3.5),
807 expected_json: "3.5",
808 expected_value: serde_json::Number::from_f64(3.5)
809 .map(Value::Number)
810 .unwrap(),
811 }
812 .run();
813
814 JsonTest {
815 variant: Variant::Float(0.0),
816 expected_json: "0",
817 expected_value: Value::Number(0.into()), }
819 .run();
820
821 JsonTest {
822 variant: Variant::Float(-1.5),
823 expected_json: "-1.5",
824 expected_value: serde_json::Number::from_f64(-1.5)
825 .map(Value::Number)
826 .unwrap(),
827 }
828 .run();
829
830 JsonTest {
831 variant: Variant::Double(std::f64::consts::E),
832 expected_json: "2.718281828459045",
833 expected_value: serde_json::Number::from_f64(std::f64::consts::E)
834 .map(Value::Number)
835 .unwrap(),
836 }
837 .run();
838
839 JsonTest {
841 variant: Variant::from(VariantDecimal4::try_new(12345, 2).unwrap()),
842 expected_json: "123.45",
843 expected_value: serde_json::Number::from_f64(123.45)
844 .map(Value::Number)
845 .unwrap(),
846 }
847 .run();
848
849 JsonTest {
850 variant: Variant::from(VariantDecimal4::try_new(42, 0).unwrap()),
851 expected_json: "42",
852 expected_value: serde_json::Number::from_f64(42.0)
853 .map(Value::Number)
854 .unwrap(),
855 }
856 .run();
857
858 JsonTest {
859 variant: Variant::from(VariantDecimal8::try_new(1234567890, 3).unwrap()),
860 expected_json: "1234567.89",
861 expected_value: serde_json::Number::from_f64(1234567.89)
862 .map(Value::Number)
863 .unwrap(),
864 }
865 .run();
866
867 JsonTest {
868 variant: Variant::from(VariantDecimal16::try_new(123456789012345, 4).unwrap()),
869 expected_json: "12345678901.2345",
870 expected_value: serde_json::Number::from_f64(12345678901.2345)
871 .map(Value::Number)
872 .unwrap(),
873 }
874 .run();
875
876 JsonTest {
878 variant: Variant::from("hello world"),
879 expected_json: "\"hello world\"",
880 expected_value: Value::String("hello world".to_string()),
881 }
882 .run();
883
884 JsonTest {
885 variant: Variant::from(""),
886 expected_json: "\"\"",
887 expected_value: Value::String(String::new()),
888 }
889 .run();
890
891 JsonTest {
892 variant: Variant::ShortString(ShortString::try_new("test").unwrap()),
893 expected_json: "\"test\"",
894 expected_value: Value::String("test".to_string()),
895 }
896 .run();
897
898 JsonTest {
900 variant: Variant::Date(NaiveDate::from_ymd_opt(2023, 12, 25).unwrap()),
901 expected_json: "\"2023-12-25\"",
902 expected_value: Value::String("2023-12-25".to_string()),
903 }
904 .run();
905
906 JsonTest {
908 variant: Variant::Binary(b"test"),
909 expected_json: "\"dGVzdA==\"", expected_value: Value::String("dGVzdA==".to_string()),
911 }
912 .run();
913
914 JsonTest {
915 variant: Variant::Binary(b""),
916 expected_json: "\"\"", expected_value: Value::String(String::new()),
918 }
919 .run();
920
921 JsonTest {
922 variant: Variant::Binary(b"binary data"),
923 expected_json: "\"YmluYXJ5IGRhdGE=\"", expected_value: Value::String("YmluYXJ5IGRhdGE=".to_string()),
925 }
926 .run();
927 }
928
929 #[test]
930 fn test_string_escaping_comprehensive() {
931 JsonTest {
933 variant: Variant::from("line1\nline2\ttab\"quote\"\\backslash"),
934 expected_json: "\"line1\\nline2\\ttab\\\"quote\\\"\\\\backslash\"",
935 expected_value: Value::String("line1\nline2\ttab\"quote\"\\backslash".to_string()),
936 }
937 .run();
938
939 JsonTest {
940 variant: Variant::from("Hello δΈη π"),
941 expected_json: "\"Hello δΈη π\"",
942 expected_value: Value::String("Hello δΈη π".to_string()),
943 }
944 .run();
945 }
946
947 #[test]
948 fn test_buffer_writing_variants() -> Result<(), ArrowError> {
949 let variant = Variant::from("test buffer writing");
950
951 let mut buffer = Vec::new();
953 variant.to_json(&mut buffer)?;
954 let result = String::from_utf8(buffer)
955 .map_err(|e| ArrowError::InvalidArgumentError(e.to_string()))?;
956 assert_eq!(result, "\"test buffer writing\"");
957
958 let mut buffer = vec![];
960 variant.to_json(&mut buffer)?;
961 let result = String::from_utf8(buffer)
962 .map_err(|e| ArrowError::InvalidArgumentError(e.to_string()))?;
963 assert_eq!(result, "\"test buffer writing\"");
964
965 Ok(())
966 }
967
968 #[test]
969 fn test_simple_object_to_json() -> Result<(), ArrowError> {
970 use parquet_variant::VariantBuilder;
971
972 let mut builder = VariantBuilder::new();
974
975 builder
976 .new_object()
977 .with_field("name", "Alice")
978 .with_field("age", 30i32)
979 .with_field("active", true)
980 .with_field("score", 95.5f64)
981 .finish();
982
983 let (metadata, value) = builder.finish();
984 let variant = Variant::try_new(&metadata, &value)?;
985 let json = variant.to_json_string()?;
986
987 let parsed: Value = serde_json::from_str(&json).unwrap();
989 let obj = parsed.as_object().expect("expected JSON object");
990 assert_eq!(obj.get("name"), Some(&Value::String("Alice".to_string())));
991 assert_eq!(obj.get("age"), Some(&Value::Number(30.into())));
992 assert_eq!(obj.get("active"), Some(&Value::Bool(true)));
993 assert!(matches!(obj.get("score"), Some(Value::Number(_))));
994 assert_eq!(obj.len(), 4);
995
996 let json_value = variant.to_json_value()?;
998 assert!(matches!(json_value, Value::Object(_)));
999
1000 Ok(())
1001 }
1002
1003 #[test]
1004 fn test_empty_object_to_json() -> Result<(), ArrowError> {
1005 use parquet_variant::VariantBuilder;
1006
1007 let mut builder = VariantBuilder::new();
1008
1009 {
1010 let obj = builder.new_object();
1011 obj.finish();
1012 }
1013
1014 let (metadata, value) = builder.finish();
1015 let variant = Variant::try_new(&metadata, &value)?;
1016 let json = variant.to_json_string()?;
1017 assert_eq!(json, "{}");
1018
1019 let json_value = variant.to_json_value()?;
1020 assert_eq!(json_value, Value::Object(serde_json::Map::new()));
1021
1022 Ok(())
1023 }
1024
1025 #[test]
1026 fn test_object_with_special_characters_to_json() -> Result<(), ArrowError> {
1027 use parquet_variant::VariantBuilder;
1028
1029 let mut builder = VariantBuilder::new();
1030
1031 builder
1032 .new_object()
1033 .with_field("message", "Hello \"World\"\nWith\tTabs")
1034 .with_field("path", "C:\\Users\\Alice\\Documents")
1035 .with_field("unicode", "π Smiley")
1036 .finish();
1037
1038 let (metadata, value) = builder.finish();
1039 let variant = Variant::try_new(&metadata, &value)?;
1040 let json = variant.to_json_string()?;
1041
1042 assert!(json.contains("Hello \\\"World\\\"\\nWith\\tTabs"));
1044 assert!(json.contains("C:\\\\Users\\\\Alice\\\\Documents"));
1045 assert!(json.contains("π Smiley"));
1046
1047 let parsed: Value = serde_json::from_str(&json).unwrap();
1049 assert!(matches!(parsed, Value::Object(_)));
1050
1051 Ok(())
1052 }
1053
1054 #[test]
1055 fn test_simple_list_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(1i32)
1063 .with_value(2i32)
1064 .with_value(3i32)
1065 .with_value(4i32)
1066 .with_value(5i32)
1067 .finish();
1068
1069 let (metadata, value) = builder.finish();
1070 let variant = Variant::try_new(&metadata, &value)?;
1071 let json = variant.to_json_string()?;
1072 assert_eq!(json, "[1,2,3,4,5]");
1073
1074 let json_value = variant.to_json_value()?;
1075 let arr = json_value.as_array().expect("expected JSON array");
1076 assert_eq!(arr.len(), 5);
1077 assert_eq!(arr[0], Value::Number(1.into()));
1078 assert_eq!(arr[4], Value::Number(5.into()));
1079
1080 Ok(())
1081 }
1082
1083 #[test]
1084 fn test_empty_list_to_json() -> Result<(), ArrowError> {
1085 use parquet_variant::VariantBuilder;
1086
1087 let mut builder = VariantBuilder::new();
1088
1089 {
1090 let list = builder.new_list();
1091 list.finish();
1092 }
1093
1094 let (metadata, value) = builder.finish();
1095 let variant = Variant::try_new(&metadata, &value)?;
1096 let json = variant.to_json_string()?;
1097 assert_eq!(json, "[]");
1098
1099 let json_value = variant.to_json_value()?;
1100 assert_eq!(json_value, Value::Array(vec![]));
1101
1102 Ok(())
1103 }
1104
1105 #[test]
1106 fn test_mixed_type_list_to_json() -> Result<(), ArrowError> {
1107 use parquet_variant::VariantBuilder;
1108
1109 let mut builder = VariantBuilder::new();
1110
1111 builder
1112 .new_list()
1113 .with_value("hello")
1114 .with_value(42i32)
1115 .with_value(true)
1116 .with_value(()) .with_value(std::f64::consts::PI)
1118 .finish();
1119
1120 let (metadata, value) = builder.finish();
1121 let variant = Variant::try_new(&metadata, &value)?;
1122 let json = variant.to_json_string()?;
1123
1124 let parsed: Value = serde_json::from_str(&json).unwrap();
1125 let arr = parsed.as_array().expect("expected JSON array");
1126 assert_eq!(arr.len(), 5);
1127 assert_eq!(arr[0], Value::String("hello".to_string()));
1128 assert_eq!(arr[1], Value::Number(42.into()));
1129 assert_eq!(arr[2], Value::Bool(true));
1130 assert_eq!(arr[3], Value::Null);
1131 assert!(matches!(arr[4], Value::Number(_)));
1132
1133 Ok(())
1134 }
1135
1136 #[test]
1137 fn test_object_field_ordering_in_json() -> Result<(), ArrowError> {
1138 use parquet_variant::VariantBuilder;
1139
1140 let mut builder = VariantBuilder::new();
1141
1142 {
1143 let mut obj = builder.new_object();
1144 obj.insert("zebra", "last");
1146 obj.insert("alpha", "first");
1147 obj.insert("beta", "second");
1148 obj.finish();
1149 }
1150
1151 let (metadata, value) = builder.finish();
1152 let variant = Variant::try_new(&metadata, &value)?;
1153 let json = variant.to_json_string()?;
1154
1155 let parsed: Value = serde_json::from_str(&json).unwrap();
1157 let obj = parsed.as_object().expect("expected JSON object");
1158 assert_eq!(obj.len(), 3);
1159 assert_eq!(obj.get("alpha"), Some(&Value::String("first".to_string())));
1160 assert_eq!(obj.get("beta"), Some(&Value::String("second".to_string())));
1161 assert_eq!(obj.get("zebra"), Some(&Value::String("last".to_string())));
1162
1163 Ok(())
1164 }
1165
1166 #[test]
1167 fn test_list_with_various_primitive_types_to_json() -> Result<(), ArrowError> {
1168 use parquet_variant::VariantBuilder;
1169
1170 let mut builder = VariantBuilder::new();
1171
1172 builder
1173 .new_list()
1174 .with_value("string_value")
1175 .with_value(42i32)
1176 .with_value(true)
1177 .with_value(std::f64::consts::PI)
1178 .with_value(false)
1179 .with_value(()) .with_value(100i64)
1181 .finish();
1182
1183 let (metadata, value) = builder.finish();
1184 let variant = Variant::try_new(&metadata, &value)?;
1185 let json = variant.to_json_string()?;
1186
1187 let parsed: Value = serde_json::from_str(&json).unwrap();
1188 let arr = parsed.as_array().expect("expected JSON array");
1189 assert_eq!(arr.len(), 7);
1190 assert_eq!(arr[0], Value::String("string_value".to_string()));
1191 assert_eq!(arr[1], Value::Number(42.into()));
1192 assert_eq!(arr[2], Value::Bool(true));
1193 assert!(matches!(arr[3], Value::Number(_))); assert_eq!(arr[4], Value::Bool(false));
1195 assert_eq!(arr[5], Value::Null);
1196 assert_eq!(arr[6], Value::Number(100.into()));
1197
1198 Ok(())
1199 }
1200
1201 #[test]
1202 fn test_object_with_various_primitive_types_to_json() -> Result<(), ArrowError> {
1203 use parquet_variant::VariantBuilder;
1204
1205 let mut builder = VariantBuilder::new();
1206
1207 {
1208 let mut obj = builder.new_object();
1209 obj.insert("string_field", "test_string");
1210 obj.insert("int_field", 123i32);
1211 obj.insert("bool_field", true);
1212 obj.insert("float_field", 2.71f64);
1213 obj.insert("null_field", ());
1214 obj.insert("long_field", 999i64);
1215 obj.finish();
1216 }
1217
1218 let (metadata, value) = builder.finish();
1219 let variant = Variant::try_new(&metadata, &value)?;
1220 let json = variant.to_json_string()?;
1221
1222 let parsed: Value = serde_json::from_str(&json).unwrap();
1223 let obj = parsed.as_object().expect("expected JSON object");
1224 assert_eq!(obj.len(), 6);
1225 assert_eq!(
1226 obj.get("string_field"),
1227 Some(&Value::String("test_string".to_string()))
1228 );
1229 assert_eq!(obj.get("int_field"), Some(&Value::Number(123.into())));
1230 assert_eq!(obj.get("bool_field"), Some(&Value::Bool(true)));
1231 assert!(matches!(obj.get("float_field"), Some(Value::Number(_))));
1232 assert_eq!(obj.get("null_field"), Some(&Value::Null));
1233 assert_eq!(obj.get("long_field"), Some(&Value::Number(999.into())));
1234
1235 Ok(())
1236 }
1237
1238 #[test]
1239 fn test_decimal_precision_behavior() -> Result<(), ArrowError> {
1240 let high_precision_decimal8 = Variant::from(VariantDecimal8::try_new(
1243 9007199254740993, 6,
1245 )?);
1246
1247 let json_string = high_precision_decimal8.to_json_string()?;
1248 let json_value = high_precision_decimal8.to_json_value()?;
1249
1250 let parsed: Value = serde_json::from_str(&json_string).unwrap();
1253 assert_eq!(parsed, json_value);
1254
1255 let exact_decimal = Variant::from(VariantDecimal8::try_new(
1257 1234567890000, 6,
1259 )?);
1260
1261 let json_string_exact = exact_decimal.to_json_string()?;
1262 assert_eq!(json_string_exact, "1234567.89");
1263
1264 let integer_decimal = Variant::from(VariantDecimal8::try_new(
1266 42000000, 6,
1268 )?);
1269
1270 let json_string_integer = integer_decimal.to_json_string()?;
1271 assert_eq!(json_string_integer, "42");
1272
1273 Ok(())
1274 }
1275
1276 #[test]
1277 fn test_float_nan_inf_handling() -> Result<(), ArrowError> {
1278 let nan_variant = Variant::Float(f32::NAN);
1280 let nan_result = nan_variant.to_json_value();
1281 assert!(nan_result.is_err());
1282 assert!(
1283 nan_result
1284 .unwrap_err()
1285 .to_string()
1286 .contains("Invalid float value")
1287 );
1288
1289 let pos_inf_variant = Variant::Float(f32::INFINITY);
1291 let pos_inf_result = pos_inf_variant.to_json_value();
1292 assert!(pos_inf_result.is_err());
1293 assert!(
1294 pos_inf_result
1295 .unwrap_err()
1296 .to_string()
1297 .contains("Invalid float value")
1298 );
1299
1300 let neg_inf_variant = Variant::Float(f32::NEG_INFINITY);
1302 let neg_inf_result = neg_inf_variant.to_json_value();
1303 assert!(neg_inf_result.is_err());
1304 assert!(
1305 neg_inf_result
1306 .unwrap_err()
1307 .to_string()
1308 .contains("Invalid float value")
1309 );
1310
1311 let nan_double_variant = Variant::Double(f64::NAN);
1313 let nan_double_result = nan_double_variant.to_json_value();
1314 assert!(nan_double_result.is_err());
1315 assert!(
1316 nan_double_result
1317 .unwrap_err()
1318 .to_string()
1319 .contains("Invalid double value")
1320 );
1321
1322 let pos_inf_double_variant = Variant::Double(f64::INFINITY);
1323 let pos_inf_double_result = pos_inf_double_variant.to_json_value();
1324 assert!(pos_inf_double_result.is_err());
1325 assert!(
1326 pos_inf_double_result
1327 .unwrap_err()
1328 .to_string()
1329 .contains("Invalid double value")
1330 );
1331
1332 let neg_inf_double_variant = Variant::Double(f64::NEG_INFINITY);
1333 let neg_inf_double_result = neg_inf_double_variant.to_json_value();
1334 assert!(neg_inf_double_result.is_err());
1335 assert!(
1336 neg_inf_double_result
1337 .unwrap_err()
1338 .to_string()
1339 .contains("Invalid double value")
1340 );
1341
1342 let normal_float = Variant::Float(std::f32::consts::PI);
1344 let normal_result = normal_float.to_json_value()?;
1345 assert!(matches!(normal_result, Value::Number(_)));
1346
1347 let normal_double = Variant::Double(std::f64::consts::E);
1348 let normal_double_result = normal_double.to_json_value()?;
1349 assert!(matches!(normal_double_result, Value::Number(_)));
1350
1351 Ok(())
1352 }
1353}