From 856cc472230010067897f5eca9a3194c9b89cf19 Mon Sep 17 00:00:00 2001 From: Liam Bao Date: Sat, 16 Aug 2025 12:37:28 -0400 Subject: [PATCH 1/9] [Variant] Rename `batch_json_string_to_variant` and `batch_variant_to_json_string` --- parquet-variant-json/src/from_json.rs | 25 +++++++++++++++++ parquet-variant-json/src/lib.rs | 6 ++-- parquet-variant-json/src/to_json.rs | 40 +++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/parquet-variant-json/src/from_json.rs b/parquet-variant-json/src/from_json.rs index 134bafe953a4..1300f7686a4d 100644 --- a/parquet-variant-json/src/from_json.rs +++ b/parquet-variant-json/src/from_json.rs @@ -154,6 +154,31 @@ impl VariantBuilderExt for ObjectFieldBuilder<'_, '_, '_> { } } +/// Extension trait for creating Variants from JSON +/// +/// This trait provides a convenient method for VariantBuilder to parse JSON strings. +/// +/// # Example +/// ```rust +/// use parquet_variant::VariantBuilder; +/// use parquet_variant_json::JsonToVariant; +/// +/// let mut builder = VariantBuilder::new(); +/// builder.from_json("{\"name\":\"Alice\",\"age\":30}")?; +/// let (metadata, value) = builder.finish(); +/// # Ok::<(), arrow_schema::ArrowError>(()) +/// ``` +pub trait JsonToVariant { + /// Create a Variant from a JSON string + fn from_json(&mut self, json: &str) -> Result<(), ArrowError>; +} + +impl JsonToVariant for T { + fn from_json(&mut self, json: &str) -> Result<(), ArrowError> { + json_to_variant(json, self) + } +} + #[cfg(test)] mod test { use super::*; diff --git a/parquet-variant-json/src/lib.rs b/parquet-variant-json/src/lib.rs index bb774c05c135..909264968f10 100644 --- a/parquet-variant-json/src/lib.rs +++ b/parquet-variant-json/src/lib.rs @@ -23,6 +23,8 @@ //! //! * See [`json_to_variant`] for converting a JSON string to a Variant. //! * See [`variant_to_json`] for converting a Variant to a JSON string. +//! * See [`JsonToVariant`] trait for extension methods on VariantBuilder. +//! * See [`VariantToJson`] trait for extension methods on Variants. //! //! ## 🚧 Work In Progress //! @@ -34,5 +36,5 @@ mod from_json; mod to_json; -pub use from_json::json_to_variant; -pub use to_json::{variant_to_json, variant_to_json_string, variant_to_json_value}; +pub use from_json::{json_to_variant, JsonToVariant}; +pub use to_json::{variant_to_json, variant_to_json_string, variant_to_json_value, VariantToJson}; diff --git a/parquet-variant-json/src/to_json.rs b/parquet-variant-json/src/to_json.rs index e18f3b327c8d..127efa9f18e1 100644 --- a/parquet-variant-json/src/to_json.rs +++ b/parquet-variant-json/src/to_json.rs @@ -383,6 +383,46 @@ pub fn variant_to_json_value(variant: &Variant) -> Result { } } +/// Extension trait for converting Variants to JSON +/// +/// This trait provides a convenient method for Variant to convert to JSON. +/// +/// # Example +/// ```rust +/// use parquet_variant::Variant; +/// use parquet_variant_json::VariantToJson; +/// +/// let variant = Variant::Int32(42); +/// let mut buffer = Vec::new(); +/// variant.to_json(&mut buffer)?; +/// assert_eq!(String::from_utf8(buffer)?, "42"); +/// # Ok::<(), arrow_schema::ArrowError>(()) +/// ``` +pub trait VariantToJson { + /// Write this variant as JSON to a writer + fn to_json(&self, buffer: &mut impl Write) -> Result<(), ArrowError>; + + /// Convert this variant to a JSON string + fn to_json_string(&self) -> Result; + + /// Convert this variant to a serde_json::Value + fn to_json_value(&self) -> Result; +} + +impl<'m, 'v> VariantToJson for Variant<'m, 'v> { + fn to_json(&self, buffer: &mut impl Write) -> Result<(), ArrowError> { + variant_to_json(buffer, self) + } + + fn to_json_string(&self) -> Result { + variant_to_json_string(self) + } + + fn to_json_value(&self) -> Result { + variant_to_json_value(self) + } +} + #[cfg(test)] mod tests { use super::*; From df3a13faae56ed90b2a45f85c3b87bab8b53a73b Mon Sep 17 00:00:00 2001 From: Liam Bao Date: Sat, 16 Aug 2025 12:55:55 -0400 Subject: [PATCH 2/9] Replace all the usages --- parquet-variant-compute/src/from_json.rs | 4 +- parquet-variant-compute/src/to_json.rs | 4 +- parquet-variant-json/src/from_json.rs | 24 ++-- parquet-variant-json/src/to_json.rs | 146 ++++++++++++----------- 4 files changed, 89 insertions(+), 89 deletions(-) diff --git a/parquet-variant-compute/src/from_json.rs b/parquet-variant-compute/src/from_json.rs index a101bf01cfda..41e42a64cbae 100644 --- a/parquet-variant-compute/src/from_json.rs +++ b/parquet-variant-compute/src/from_json.rs @@ -21,7 +21,7 @@ use crate::{VariantArray, VariantArrayBuilder}; use arrow::array::{Array, ArrayRef, StringArray}; use arrow_schema::ArrowError; -use parquet_variant_json::json_to_variant; +use parquet_variant_json::JsonToVariant; /// Parse a batch of JSON strings into a batch of Variants represented as /// STRUCT where nulls are preserved. The JSON strings in the input @@ -42,7 +42,7 @@ pub fn batch_json_string_to_variant(input: &ArrayRef) -> Result to a batch /// of JSON strings where nulls are preserved. The JSON strings in the input must be valid. @@ -83,7 +83,7 @@ pub fn batch_variant_to_json_string(input: &ArrayRef) -> Result JsonToVariant for T { #[cfg(test)] mod test { use super::*; - use crate::variant_to_json_string; + use crate::VariantToJson; use arrow_schema::ArrowError; use parquet_variant::{ ShortString, Variant, VariantBuilder, VariantDecimal16, VariantDecimal4, VariantDecimal8, @@ -196,7 +194,7 @@ mod test { impl JsonToVariantTest<'_> { fn run(self) -> Result<(), ArrowError> { let mut variant_builder = VariantBuilder::new(); - json_to_variant(self.json, &mut variant_builder)?; + variant_builder.from_json(self.json)?; let (metadata, value) = variant_builder.finish(); let variant = Variant::try_new(&metadata, &value)?; assert_eq!(variant, self.expected); @@ -647,10 +645,10 @@ mod test { ); // Manually verify raw JSON value size let mut variant_builder = VariantBuilder::new(); - json_to_variant(&json, &mut variant_builder)?; + variant_builder.from_json(&json)?; let (metadata, value) = variant_builder.finish(); let v = Variant::try_new(&metadata, &value)?; - let output_string = variant_to_json_string(&v)?; + let output_string = v.to_json_string()?; assert_eq!(output_string, json); // Verify metadata size = 1 + 2 + 2 * 497 + 3 * 496 assert_eq!(metadata.len(), 2485); @@ -688,10 +686,10 @@ mod test { fn test_json_to_variant_unicode() -> Result<(), ArrowError> { let json = "{\"爱\":\"अ\",\"a\":1}"; let mut variant_builder = VariantBuilder::new(); - json_to_variant(json, &mut variant_builder)?; + variant_builder.from_json(json)?; let (metadata, value) = variant_builder.finish(); let v = Variant::try_new(&metadata, &value)?; - let output_string = variant_to_json_string(&v)?; + let output_string = v.to_json_string()?; assert_eq!(output_string, "{\"a\":1,\"爱\":\"अ\"}"); let mut variant_builder = VariantBuilder::new(); let mut object_builder = variant_builder.new_object(); diff --git a/parquet-variant-json/src/to_json.rs b/parquet-variant-json/src/to_json.rs index 127efa9f18e1..2d0529893140 100644 --- a/parquet-variant-json/src/to_json.rs +++ b/parquet-variant-json/src/to_json.rs @@ -75,11 +75,11 @@ fn format_time_ntz_str(time: &chrono::NaiveTime) -> String { /// /// ```rust /// # use parquet_variant::{Variant}; -/// # use parquet_variant_json::variant_to_json; +/// # use parquet_variant_json::VariantToJson; /// # use arrow_schema::ArrowError; /// let variant = Variant::from("Hello, World!"); /// let mut buffer = Vec::new(); -/// variant_to_json(&mut buffer, &variant)?; +/// variant.to_json(&mut buffer)?; /// assert_eq!(String::from_utf8(buffer).unwrap(), "\"Hello, World!\""); /// # Ok::<(), ArrowError>(()) /// ``` @@ -87,7 +87,7 @@ fn format_time_ntz_str(time: &chrono::NaiveTime) -> String { /// # Example: Create a [`Variant::Object`] and convert to JSON /// ```rust /// # use parquet_variant::{Variant, VariantBuilder}; -/// # use parquet_variant_json::variant_to_json; +/// # use parquet_variant_json::VariantToJson; /// # use arrow_schema::ArrowError; /// let mut builder = VariantBuilder::new(); /// // Create an object builder that will write fields to the object @@ -100,7 +100,7 @@ fn format_time_ntz_str(time: &chrono::NaiveTime) -> String { /// // Create the Variant and convert to JSON /// let variant = Variant::try_new(&metadata, &value)?; /// let mut writer = Vec::new(); -/// variant_to_json(&mut writer, &variant,)?; +/// variant.to_json(&mut writer)?; /// assert_eq!(br#"{"first_name":"Jiaying","last_name":"Li"}"#, writer.as_slice()); /// # Ok::<(), ArrowError>(()) /// ``` @@ -176,7 +176,7 @@ fn convert_object_to_json(buffer: &mut impl Write, obj: &VariantObject) -> Resul write!(buffer, "{json_key}:")?; // Recursively convert the value - variant_to_json(buffer, &value)?; + value.to_json(buffer)?; } write!(buffer, "}}")?; @@ -194,7 +194,7 @@ fn convert_array_to_json(buffer: &mut impl Write, arr: &VariantList) -> Result<( } first = false; - variant_to_json(buffer, &element)?; + element.to_json(buffer)?; } write!(buffer, "]")?; @@ -220,10 +220,10 @@ fn convert_array_to_json(buffer: &mut impl Write, arr: &VariantList) -> Result<( /// /// ```rust /// # use parquet_variant::{Variant}; -/// # use parquet_variant_json::variant_to_json_string; +/// # use parquet_variant_json::VariantToJson; /// # use arrow_schema::ArrowError; /// let variant = Variant::Int32(42); -/// let json = variant_to_json_string(&variant)?; +/// let json = variant.to_json_string()?; /// assert_eq!(json, "42"); /// # Ok::<(), ArrowError>(()) /// ``` @@ -240,7 +240,7 @@ fn convert_array_to_json(buffer: &mut impl Write, arr: &VariantList) -> Result<( /// /// ```rust /// # use parquet_variant::{Variant, VariantBuilder}; -/// # use parquet_variant_json::variant_to_json_string; +/// # use parquet_variant_json::VariantToJson; /// # use arrow_schema::ArrowError; /// let mut builder = VariantBuilder::new(); /// // Create an object builder that will write fields to the object @@ -252,13 +252,13 @@ fn convert_array_to_json(buffer: &mut impl Write, arr: &VariantList) -> Result<( /// let (metadata, value) = builder.finish(); /// // Create the Variant and convert to JSON /// let variant = Variant::try_new(&metadata, &value)?; -/// let json = variant_to_json_string(&variant)?; +/// let json = variant.to_json_string()?; /// assert_eq!(r#"{"first_name":"Jiaying","last_name":"Li"}"#, json); /// # Ok::<(), ArrowError>(()) /// ``` pub fn variant_to_json_string(variant: &Variant) -> Result { let mut buffer = Vec::new(); - variant_to_json(&mut buffer, variant)?; + variant.to_json(&mut buffer)?; String::from_utf8(buffer) .map_err(|e| ArrowError::InvalidArgumentError(format!("UTF-8 conversion error: {e}"))) } @@ -282,11 +282,11 @@ pub fn variant_to_json_string(variant: &Variant) -> Result { /// /// ```rust /// # use parquet_variant::{Variant}; -/// # use parquet_variant_json::variant_to_json_value; +/// # use parquet_variant_json::VariantToJson; /// # use serde_json::Value; /// # use arrow_schema::ArrowError; /// let variant = Variant::from("hello"); -/// let json_value = variant_to_json_value(&variant)?; +/// let json_value = variant.to_json_value()?; /// assert_eq!(json_value, Value::String("hello".to_string())); /// # Ok::<(), ArrowError>(()) /// ``` @@ -369,14 +369,14 @@ pub fn variant_to_json_value(variant: &Variant) -> Result { Variant::Object(obj) => { let map = obj .iter() - .map(|(k, v)| variant_to_json_value(&v).map(|json_val| (k.to_string(), json_val))) + .map(|(k, v)| v.to_json_value().map(|json_val| (k.to_string(), json_val))) .collect::>()?; Ok(Value::Object(map)) } Variant::List(arr) => { let vec = arr .iter() - .map(|element| variant_to_json_value(&element)) + .map(|element| element.to_json_value()) .collect::>()?; Ok(Value::Array(vec)) } @@ -433,12 +433,12 @@ mod tests { fn test_decimal_edge_cases() -> Result<(), ArrowError> { // Test negative decimal let negative_variant = Variant::from(VariantDecimal4::try_new(-12345, 3)?); - let negative_json = variant_to_json_string(&negative_variant)?; + let negative_json = negative_variant.to_json_string()?; assert_eq!(negative_json, "-12.345"); // Test large scale decimal let large_scale_variant = Variant::from(VariantDecimal8::try_new(123456789, 6)?); - let large_scale_json = variant_to_json_string(&large_scale_variant)?; + let large_scale_json = large_scale_variant.to_json_string()?; assert_eq!(large_scale_json, "123.456789"); Ok(()) @@ -447,15 +447,15 @@ mod tests { #[test] fn test_decimal16_to_json() -> Result<(), ArrowError> { let variant = Variant::from(VariantDecimal16::try_new(123456789012345, 4)?); - let json = variant_to_json_string(&variant)?; + let json = variant.to_json_string()?; assert_eq!(json, "12345678901.2345"); - let json_value = variant_to_json_value(&variant)?; + let json_value = variant.to_json_value()?; assert!(matches!(json_value, Value::Number(_))); // Test very large number let large_variant = Variant::from(VariantDecimal16::try_new(999999999999999999, 2)?); - let large_json = variant_to_json_string(&large_variant)?; + let large_json = large_variant.to_json_string()?; // Due to f64 precision limits, very large numbers may lose precision assert!( large_json.starts_with("9999999999999999") @@ -468,16 +468,16 @@ mod tests { fn test_date_to_json() -> Result<(), ArrowError> { let date = NaiveDate::from_ymd_opt(2023, 12, 25).unwrap(); let variant = Variant::Date(date); - let json = variant_to_json_string(&variant)?; + let json = variant.to_json_string()?; assert_eq!(json, "\"2023-12-25\""); - let json_value = variant_to_json_value(&variant)?; + let json_value = variant.to_json_value()?; assert_eq!(json_value, Value::String("2023-12-25".to_string())); // Test leap year date let leap_date = NaiveDate::from_ymd_opt(2024, 2, 29).unwrap(); let leap_variant = Variant::Date(leap_date); - let leap_json = variant_to_json_string(&leap_variant)?; + let leap_json = leap_variant.to_json_string()?; assert_eq!(leap_json, "\"2024-02-29\""); Ok(()) } @@ -488,11 +488,11 @@ mod tests { .unwrap() .with_timezone(&Utc); let variant = Variant::TimestampMicros(timestamp); - let json = variant_to_json_string(&variant)?; + let json = variant.to_json_string()?; assert!(json.contains("2023-12-25T10:30:45")); assert!(json.starts_with('"') && json.ends_with('"')); - let json_value = variant_to_json_value(&variant)?; + let json_value = variant.to_json_value()?; assert!(matches!(json_value, Value::String(_))); Ok(()) } @@ -503,11 +503,11 @@ mod tests { .unwrap() .naive_utc(); let variant = Variant::TimestampNtzMicros(naive_timestamp); - let json = variant_to_json_string(&variant)?; + let json = variant.to_json_string()?; assert!(json.contains("2023-12-25")); assert!(json.starts_with('"') && json.ends_with('"')); - let json_value = variant_to_json_value(&variant)?; + let json_value = variant.to_json_value()?; assert!(matches!(json_value, Value::String(_))); Ok(()) } @@ -516,10 +516,10 @@ mod tests { fn test_time_to_json() -> Result<(), ArrowError> { let naive_time = NaiveTime::from_num_seconds_from_midnight_opt(12345, 123460708).unwrap(); let variant = Variant::Time(naive_time); - let json = variant_to_json_string(&variant)?; + let json = variant.to_json_string()?; assert_eq!("\"03:25:45.12346\"", json); - let json_value = variant_to_json_value(&variant)?; + let json_value = variant.to_json_value()?; assert!(matches!(json_value, Value::String(_))); Ok(()) } @@ -528,23 +528,23 @@ mod tests { fn test_binary_to_json() -> Result<(), ArrowError> { let binary_data = b"Hello, World!"; let variant = Variant::Binary(binary_data); - let json = variant_to_json_string(&variant)?; + let json = variant.to_json_string()?; // Should be base64 encoded and quoted assert!(json.starts_with('"') && json.ends_with('"')); assert!(json.len() > 2); // Should have content - let json_value = variant_to_json_value(&variant)?; + let json_value = variant.to_json_value()?; assert!(matches!(json_value, Value::String(_))); // Test empty binary let empty_variant = Variant::Binary(b""); - let empty_json = variant_to_json_string(&empty_variant)?; + let empty_json = empty_variant.to_json_string()?; assert_eq!(empty_json, "\"\""); // Test binary with special bytes let special_variant = Variant::Binary(&[0, 255, 128, 64]); - let special_json = variant_to_json_string(&special_variant)?; + let special_json = special_variant.to_json_string()?; assert!(special_json.starts_with('"') && special_json.ends_with('"')); Ok(()) } @@ -552,10 +552,10 @@ mod tests { #[test] fn test_string_to_json() -> Result<(), ArrowError> { let variant = Variant::from("hello world"); - let json = variant_to_json_string(&variant)?; + let json = variant.to_json_string()?; assert_eq!(json, "\"hello world\""); - let json_value = variant_to_json_value(&variant)?; + let json_value = variant.to_json_value()?; assert_eq!(json_value, Value::String("hello world".to_string())); Ok(()) } @@ -565,10 +565,10 @@ mod tests { use parquet_variant::ShortString; let short_string = ShortString::try_new("short")?; let variant = Variant::ShortString(short_string); - let json = variant_to_json_string(&variant)?; + let json = variant.to_json_string()?; assert_eq!(json, "\"short\""); - let json_value = variant_to_json_value(&variant)?; + let json_value = variant.to_json_value()?; assert_eq!(json_value, Value::String("short".to_string())); Ok(()) } @@ -576,10 +576,10 @@ mod tests { #[test] fn test_string_escaping() -> Result<(), ArrowError> { let variant = Variant::from("hello\nworld\t\"quoted\""); - let json = variant_to_json_string(&variant)?; + let json = variant.to_json_string()?; assert_eq!(json, "\"hello\\nworld\\t\\\"quoted\\\"\""); - let json_value = variant_to_json_value(&variant)?; + let json_value = variant.to_json_value()?; assert_eq!( json_value, Value::String("hello\nworld\t\"quoted\"".to_string()) @@ -591,7 +591,7 @@ mod tests { fn test_json_buffer_writing() -> Result<(), ArrowError> { let variant = Variant::Int8(123); let mut buffer = Vec::new(); - variant_to_json(&mut buffer, &variant)?; + variant.to_json(&mut buffer)?; let result = String::from_utf8(buffer) .map_err(|e| ArrowError::InvalidArgumentError(e.to_string()))?; @@ -608,7 +608,9 @@ mod tests { impl JsonTest { fn run(self) { - let json_string = variant_to_json_string(&self.variant) + let json_string = self + .variant + .to_json_string() .expect("variant_to_json_string should succeed"); assert_eq!( json_string, self.expected_json, @@ -616,8 +618,10 @@ mod tests { self.variant ); - let json_value = - variant_to_json_value(&self.variant).expect("variant_to_json_value should succeed"); + let json_value = self + .variant + .to_json_value() + .expect("variant_to_json_value should succeed"); // For floating point numbers, we need special comparison due to JSON number representation match (&json_value, &self.expected_value) { @@ -897,20 +901,18 @@ mod tests { #[test] fn test_buffer_writing_variants() -> Result<(), ArrowError> { - use crate::variant_to_json; - let variant = Variant::from("test buffer writing"); // Test writing to a Vec let mut buffer = Vec::new(); - variant_to_json(&mut buffer, &variant)?; + variant.to_json(&mut buffer)?; let result = String::from_utf8(buffer) .map_err(|e| ArrowError::InvalidArgumentError(e.to_string()))?; assert_eq!(result, "\"test buffer writing\""); // Test writing to vec![] let mut buffer = vec![]; - variant_to_json(&mut buffer, &variant)?; + variant.to_json(&mut buffer)?; let result = String::from_utf8(buffer) .map_err(|e| ArrowError::InvalidArgumentError(e.to_string()))?; assert_eq!(result, "\"test buffer writing\""); @@ -936,7 +938,7 @@ mod tests { let (metadata, value) = builder.finish(); let variant = Variant::try_new(&metadata, &value)?; - let json = variant_to_json_string(&variant)?; + let json = variant.to_json_string()?; // Parse the JSON to verify structure - handle JSON parsing errors manually let parsed: Value = serde_json::from_str(&json).unwrap(); @@ -948,7 +950,7 @@ mod tests { assert_eq!(obj.len(), 4); // Test variant_to_json_value as well - let json_value = variant_to_json_value(&variant)?; + let json_value = variant.to_json_value()?; assert!(matches!(json_value, Value::Object(_))); Ok(()) @@ -967,10 +969,10 @@ mod tests { let (metadata, value) = builder.finish(); let variant = Variant::try_new(&metadata, &value)?; - let json = variant_to_json_string(&variant)?; + let json = variant.to_json_string()?; assert_eq!(json, "{}"); - let json_value = variant_to_json_value(&variant)?; + let json_value = variant.to_json_value()?; assert_eq!(json_value, Value::Object(serde_json::Map::new())); Ok(()) @@ -992,7 +994,7 @@ mod tests { let (metadata, value) = builder.finish(); let variant = Variant::try_new(&metadata, &value)?; - let json = variant_to_json_string(&variant)?; + let json = variant.to_json_string()?; // Verify that special characters are properly escaped assert!(json.contains("Hello \\\"World\\\"\\nWith\\tTabs")); @@ -1023,10 +1025,10 @@ mod tests { let (metadata, value) = builder.finish(); let variant = Variant::try_new(&metadata, &value)?; - let json = variant_to_json_string(&variant)?; + let json = variant.to_json_string()?; assert_eq!(json, "[1,2,3,4,5]"); - let json_value = variant_to_json_value(&variant)?; + let json_value = variant.to_json_value()?; let arr = json_value.as_array().expect("expected JSON array"); assert_eq!(arr.len(), 5); assert_eq!(arr[0], Value::Number(1.into())); @@ -1048,10 +1050,10 @@ mod tests { let (metadata, value) = builder.finish(); let variant = Variant::try_new(&metadata, &value)?; - let json = variant_to_json_string(&variant)?; + let json = variant.to_json_string()?; assert_eq!(json, "[]"); - let json_value = variant_to_json_value(&variant)?; + let json_value = variant.to_json_value()?; assert_eq!(json_value, Value::Array(vec![])); Ok(()) @@ -1074,7 +1076,7 @@ mod tests { let (metadata, value) = builder.finish(); let variant = Variant::try_new(&metadata, &value)?; - let json = variant_to_json_string(&variant)?; + let json = variant.to_json_string()?; let parsed: Value = serde_json::from_str(&json).unwrap(); let arr = parsed.as_array().expect("expected JSON array"); @@ -1105,7 +1107,7 @@ mod tests { let (metadata, value) = builder.finish(); let variant = Variant::try_new(&metadata, &value)?; - let json = variant_to_json_string(&variant)?; + let json = variant.to_json_string()?; // Parse and verify all fields are present let parsed: Value = serde_json::from_str(&json).unwrap(); @@ -1137,7 +1139,7 @@ mod tests { let (metadata, value) = builder.finish(); let variant = Variant::try_new(&metadata, &value)?; - let json = variant_to_json_string(&variant)?; + let json = variant.to_json_string()?; let parsed: Value = serde_json::from_str(&json).unwrap(); let arr = parsed.as_array().expect("expected JSON array"); @@ -1172,7 +1174,7 @@ mod tests { let (metadata, value) = builder.finish(); let variant = Variant::try_new(&metadata, &value)?; - let json = variant_to_json_string(&variant)?; + let json = variant.to_json_string()?; let parsed: Value = serde_json::from_str(&json).unwrap(); let obj = parsed.as_object().expect("expected JSON object"); @@ -1199,8 +1201,8 @@ mod tests { 6, )?); - let json_string = variant_to_json_string(&high_precision_decimal8)?; - let json_value = variant_to_json_value(&high_precision_decimal8)?; + let json_string = high_precision_decimal8.to_json_string()?; + let json_value = high_precision_decimal8.to_json_value()?; // Due to f64 precision limits, we expect precision loss for values > 2^53 // Both functions should produce consistent results (even if not exact) @@ -1213,7 +1215,7 @@ mod tests { 6, )?); - let json_string_exact = variant_to_json_string(&exact_decimal)?; + let json_string_exact = exact_decimal.to_json_string()?; assert_eq!(json_string_exact, "1234567.89"); // Test integer case (should be exact) @@ -1222,7 +1224,7 @@ mod tests { 6, )?); - let json_string_integer = variant_to_json_string(&integer_decimal)?; + let json_string_integer = integer_decimal.to_json_string()?; assert_eq!(json_string_integer, "42"); Ok(()) @@ -1232,7 +1234,7 @@ mod tests { fn test_float_nan_inf_handling() -> Result<(), ArrowError> { // Test NaN handling - should return an error since JSON doesn't support NaN let nan_variant = Variant::Float(f32::NAN); - let nan_result = variant_to_json_value(&nan_variant); + let nan_result = nan_variant.to_json_value(); assert!(nan_result.is_err()); assert!(nan_result .unwrap_err() @@ -1241,7 +1243,7 @@ mod tests { // Test positive infinity - should return an error since JSON doesn't support Infinity let pos_inf_variant = Variant::Float(f32::INFINITY); - let pos_inf_result = variant_to_json_value(&pos_inf_variant); + let pos_inf_result = pos_inf_variant.to_json_value(); assert!(pos_inf_result.is_err()); assert!(pos_inf_result .unwrap_err() @@ -1250,7 +1252,7 @@ mod tests { // Test negative infinity - should return an error since JSON doesn't support -Infinity let neg_inf_variant = Variant::Float(f32::NEG_INFINITY); - let neg_inf_result = variant_to_json_value(&neg_inf_variant); + let neg_inf_result = neg_inf_variant.to_json_value(); assert!(neg_inf_result.is_err()); assert!(neg_inf_result .unwrap_err() @@ -1259,7 +1261,7 @@ mod tests { // Test the same for Double variants let nan_double_variant = Variant::Double(f64::NAN); - let nan_double_result = variant_to_json_value(&nan_double_variant); + let nan_double_result = nan_double_variant.to_json_value(); assert!(nan_double_result.is_err()); assert!(nan_double_result .unwrap_err() @@ -1267,7 +1269,7 @@ mod tests { .contains("Invalid double value")); let pos_inf_double_variant = Variant::Double(f64::INFINITY); - let pos_inf_double_result = variant_to_json_value(&pos_inf_double_variant); + let pos_inf_double_result = pos_inf_double_variant.to_json_value(); assert!(pos_inf_double_result.is_err()); assert!(pos_inf_double_result .unwrap_err() @@ -1275,7 +1277,7 @@ mod tests { .contains("Invalid double value")); let neg_inf_double_variant = Variant::Double(f64::NEG_INFINITY); - let neg_inf_double_result = variant_to_json_value(&neg_inf_double_variant); + let neg_inf_double_result = neg_inf_double_variant.to_json_value(); assert!(neg_inf_double_result.is_err()); assert!(neg_inf_double_result .unwrap_err() @@ -1284,11 +1286,11 @@ mod tests { // Test normal float values still work let normal_float = Variant::Float(std::f32::consts::PI); - let normal_result = variant_to_json_value(&normal_float)?; + let normal_result = normal_float.to_json_value()?; assert!(matches!(normal_result, Value::Number(_))); let normal_double = Variant::Double(std::f64::consts::E); - let normal_double_result = variant_to_json_value(&normal_double)?; + let normal_double_result = normal_double.to_json_value()?; assert!(matches!(normal_double_result, Value::Number(_))); Ok(()) From 28eaa294b85e958fa1e6f4556b1a809a295079f2 Mon Sep 17 00:00:00 2001 From: Liam Bao Date: Sat, 16 Aug 2025 13:18:24 -0400 Subject: [PATCH 3/9] Rename batch functions --- parquet-variant-compute/benches/variant_kernels.rs | 10 +++++----- parquet-variant-compute/src/from_json.rs | 6 +++--- parquet-variant-compute/src/lib.rs | 8 ++++---- parquet-variant-compute/src/to_json.rs | 6 +++--- parquet-variant-compute/src/variant_get/mod.rs | 6 +++--- parquet-variant-json/src/from_json.rs | 2 +- parquet-variant-json/src/lib.rs | 10 ++++------ parquet-variant-json/src/to_json.rs | 6 +++--- 8 files changed, 26 insertions(+), 28 deletions(-) diff --git a/parquet-variant-compute/benches/variant_kernels.rs b/parquet-variant-compute/benches/variant_kernels.rs index 8fd6af333fed..5e97f948b231 100644 --- a/parquet-variant-compute/benches/variant_kernels.rs +++ b/parquet-variant-compute/benches/variant_kernels.rs @@ -20,7 +20,7 @@ use arrow::util::test_util::seedable_rng; use criterion::{criterion_group, criterion_main, Criterion}; use parquet_variant::{Variant, VariantBuilder}; use parquet_variant_compute::variant_get::{variant_get, GetOptions}; -use parquet_variant_compute::{batch_json_string_to_variant, VariantArray, VariantArrayBuilder}; +use parquet_variant_compute::{json_to_variant, VariantArray, VariantArrayBuilder}; use rand::distr::Alphanumeric; use rand::rngs::StdRng; use rand::Rng; @@ -34,7 +34,7 @@ fn benchmark_batch_json_string_to_variant(c: &mut Criterion) { "batch_json_string_to_variant repeated_struct 8k string", |b| { b.iter(|| { - let _ = batch_json_string_to_variant(&array_ref).unwrap(); + let _ = json_to_variant(&array_ref).unwrap(); }); }, ); @@ -43,7 +43,7 @@ fn benchmark_batch_json_string_to_variant(c: &mut Criterion) { let array_ref: ArrayRef = Arc::new(input_array); c.bench_function("batch_json_string_to_variant json_list 8k string", |b| { b.iter(|| { - let _ = batch_json_string_to_variant(&array_ref).unwrap(); + let _ = json_to_variant(&array_ref).unwrap(); }); }); @@ -60,7 +60,7 @@ fn benchmark_batch_json_string_to_variant(c: &mut Criterion) { let array_ref: ArrayRef = Arc::new(input_array); c.bench_function(&id, |b| { b.iter(|| { - let _ = batch_json_string_to_variant(&array_ref).unwrap(); + let _ = json_to_variant(&array_ref).unwrap(); }); }); @@ -77,7 +77,7 @@ fn benchmark_batch_json_string_to_variant(c: &mut Criterion) { let array_ref: ArrayRef = Arc::new(input_array); c.bench_function(&id, |b| { b.iter(|| { - let _ = batch_json_string_to_variant(&array_ref).unwrap(); + let _ = json_to_variant(&array_ref).unwrap(); }); }); } diff --git a/parquet-variant-compute/src/from_json.rs b/parquet-variant-compute/src/from_json.rs index 41e42a64cbae..70fe554db96e 100644 --- a/parquet-variant-compute/src/from_json.rs +++ b/parquet-variant-compute/src/from_json.rs @@ -26,7 +26,7 @@ use parquet_variant_json::JsonToVariant; /// Parse a batch of JSON strings into a batch of Variants represented as /// STRUCT where nulls are preserved. The JSON strings in the input /// must be valid. -pub fn batch_json_string_to_variant(input: &ArrayRef) -> Result { +pub fn json_to_variant(input: &ArrayRef) -> Result { let input_string_array = match input.as_any().downcast_ref::() { Some(string_array) => Ok(string_array), None => Err(ArrowError::CastError( @@ -51,7 +51,7 @@ pub fn batch_json_string_to_variant(input: &ArrayRef) -> Result to a batch /// of JSON strings where nulls are preserved. The JSON strings in the input must be valid. -pub fn batch_variant_to_json_string(input: &ArrayRef) -> Result { +pub fn variant_to_json(input: &ArrayRef) -> Result { let struct_array = input .as_any() .downcast_ref::() @@ -104,7 +104,7 @@ pub fn batch_variant_to_json_string(input: &ArrayRef) -> Result>(()) /// ``` -pub fn json_to_variant(json: &str, builder: &mut impl VariantBuilderExt) -> Result<(), ArrowError> { +fn json_to_variant(json: &str, builder: &mut impl VariantBuilderExt) -> Result<(), ArrowError> { let json: Value = serde_json::from_str(json) .map_err(|e| ArrowError::InvalidArgumentError(format!("JSON format error: {e}")))?; diff --git a/parquet-variant-json/src/lib.rs b/parquet-variant-json/src/lib.rs index 909264968f10..f24c740818be 100644 --- a/parquet-variant-json/src/lib.rs +++ b/parquet-variant-json/src/lib.rs @@ -21,10 +21,8 @@ //! [Variant Binary Encoding]: https://github.com/apache/parquet-format/blob/master/VariantEncoding.md //! [Apache Parquet]: https://parquet.apache.org/ //! -//! * See [`json_to_variant`] for converting a JSON string to a Variant. -//! * See [`variant_to_json`] for converting a Variant to a JSON string. -//! * See [`JsonToVariant`] trait for extension methods on VariantBuilder. -//! * See [`VariantToJson`] trait for extension methods on Variants. +//! * See [`JsonToVariant`] trait for converting a JSON string to a Variant. +//! * See [`VariantToJson`] trait for converting a Variant to a JSON string. //! //! ## 🚧 Work In Progress //! @@ -36,5 +34,5 @@ mod from_json; mod to_json; -pub use from_json::{json_to_variant, JsonToVariant}; -pub use to_json::{variant_to_json, variant_to_json_string, variant_to_json_value, VariantToJson}; +pub use from_json::JsonToVariant; +pub use to_json::VariantToJson; diff --git a/parquet-variant-json/src/to_json.rs b/parquet-variant-json/src/to_json.rs index 2d0529893140..c3610d5d5b90 100644 --- a/parquet-variant-json/src/to_json.rs +++ b/parquet-variant-json/src/to_json.rs @@ -104,7 +104,7 @@ fn format_time_ntz_str(time: &chrono::NaiveTime) -> String { /// assert_eq!(br#"{"first_name":"Jiaying","last_name":"Li"}"#, writer.as_slice()); /// # Ok::<(), ArrowError>(()) /// ``` -pub fn variant_to_json(json_buffer: &mut impl Write, variant: &Variant) -> Result<(), ArrowError> { +fn variant_to_json(json_buffer: &mut impl Write, variant: &Variant) -> Result<(), ArrowError> { match variant { Variant::Null => write!(json_buffer, "null")?, Variant::BooleanTrue => write!(json_buffer, "true")?, @@ -256,7 +256,7 @@ fn convert_array_to_json(buffer: &mut impl Write, arr: &VariantList) -> Result<( /// assert_eq!(r#"{"first_name":"Jiaying","last_name":"Li"}"#, json); /// # Ok::<(), ArrowError>(()) /// ``` -pub fn variant_to_json_string(variant: &Variant) -> Result { +fn variant_to_json_string(variant: &Variant) -> Result { let mut buffer = Vec::new(); variant.to_json(&mut buffer)?; String::from_utf8(buffer) @@ -290,7 +290,7 @@ pub fn variant_to_json_string(variant: &Variant) -> Result { /// assert_eq!(json_value, Value::String("hello".to_string())); /// # Ok::<(), ArrowError>(()) /// ``` -pub fn variant_to_json_value(variant: &Variant) -> Result { +fn variant_to_json_value(variant: &Variant) -> Result { match variant { Variant::Null => Ok(Value::Null), Variant::BooleanTrue => Ok(Value::Bool(true)), From cc1d02baf146ba7d7b423d0db0218b33ad1733ba Mon Sep 17 00:00:00 2001 From: Liam Bao Date: Sat, 16 Aug 2025 22:32:59 -0400 Subject: [PATCH 4/9] Rename `from_json` to `with_json` --- parquet-variant-compute/src/from_json.rs | 2 +- parquet-variant-json/src/from_json.rs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/parquet-variant-compute/src/from_json.rs b/parquet-variant-compute/src/from_json.rs index 70fe554db96e..304dc3fc51bf 100644 --- a/parquet-variant-compute/src/from_json.rs +++ b/parquet-variant-compute/src/from_json.rs @@ -42,7 +42,7 @@ pub fn json_to_variant(input: &ArrayRef) -> Result { } else { let mut vb = variant_array_builder.variant_builder(); // parse JSON directly to the variant builder - vb.from_json(input_string_array.value(i))?; + vb.with_json(input_string_array.value(i))?; vb.finish() } } diff --git a/parquet-variant-json/src/from_json.rs b/parquet-variant-json/src/from_json.rs index 6f9c72a5ab30..2b32ec1aa4c1 100644 --- a/parquet-variant-json/src/from_json.rs +++ b/parquet-variant-json/src/from_json.rs @@ -48,7 +48,7 @@ use serde_json::{Number, Value}; /// let person_string = "{\"name\":\"Alice\", \"age\":30, ".to_string() /// + "\"email\":\"alice@example.com\", \"is_active\": true, \"score\": 95.7," /// + "\"additional_info\": null}"; -/// variant_builder.from_json(&person_string)?; +/// variant_builder.with_json(&person_string)?; /// /// let (metadata, value) = variant_builder.finish(); /// @@ -162,17 +162,17 @@ impl VariantBuilderExt for ObjectFieldBuilder<'_, '_, '_> { /// use parquet_variant_json::JsonToVariant; /// /// let mut builder = VariantBuilder::new(); -/// builder.from_json("{\"name\":\"Alice\",\"age\":30}")?; +/// builder.with_json("{\"name\":\"Alice\",\"age\":30}")?; /// let (metadata, value) = builder.finish(); /// # Ok::<(), arrow_schema::ArrowError>(()) /// ``` pub trait JsonToVariant { /// Create a Variant from a JSON string - fn from_json(&mut self, json: &str) -> Result<(), ArrowError>; + fn with_json(&mut self, json: &str) -> Result<(), ArrowError>; } impl JsonToVariant for T { - fn from_json(&mut self, json: &str) -> Result<(), ArrowError> { + fn with_json(&mut self, json: &str) -> Result<(), ArrowError> { json_to_variant(json, self) } } @@ -194,7 +194,7 @@ mod test { impl JsonToVariantTest<'_> { fn run(self) -> Result<(), ArrowError> { let mut variant_builder = VariantBuilder::new(); - variant_builder.from_json(self.json)?; + variant_builder.with_json(self.json)?; let (metadata, value) = variant_builder.finish(); let variant = Variant::try_new(&metadata, &value)?; assert_eq!(variant, self.expected); @@ -645,7 +645,7 @@ mod test { ); // Manually verify raw JSON value size let mut variant_builder = VariantBuilder::new(); - variant_builder.from_json(&json)?; + variant_builder.with_json(&json)?; let (metadata, value) = variant_builder.finish(); let v = Variant::try_new(&metadata, &value)?; let output_string = v.to_json_string()?; @@ -686,7 +686,7 @@ mod test { fn test_json_to_variant_unicode() -> Result<(), ArrowError> { let json = "{\"爱\":\"अ\",\"a\":1}"; let mut variant_builder = VariantBuilder::new(); - variant_builder.from_json(json)?; + variant_builder.with_json(json)?; let (metadata, value) = variant_builder.finish(); let v = Variant::try_new(&metadata, &value)?; let output_string = v.to_json_string()?; From 6e18fe511f94bc2835856170bb65375ad359b598 Mon Sep 17 00:00:00 2001 From: Liam Bao Date: Sat, 16 Aug 2025 22:55:24 -0400 Subject: [PATCH 5/9] Refactor `from_json` --- parquet-variant-json/src/from_json.rs | 48 ++++++--------------------- 1 file changed, 11 insertions(+), 37 deletions(-) diff --git a/parquet-variant-json/src/from_json.rs b/parquet-variant-json/src/from_json.rs index 2b32ec1aa4c1..e70e21d51d53 100644 --- a/parquet-variant-json/src/from_json.rs +++ b/parquet-variant-json/src/from_json.rs @@ -29,9 +29,6 @@ use serde_json::{Number, Value}; /// /// # Arguments /// * `json` - The JSON string to parse as Variant. -/// * `variant_builder` - Object of type `VariantBuilder` used to build the variant from the JSON -/// string -/// /// /// # Returns /// @@ -66,17 +63,19 @@ use serde_json::{Number, Value}; /// assert_eq!(json_result, serde_json::to_string(&json_value)?); /// # Ok::<(), Box>(()) /// ``` -fn json_to_variant(json: &str, builder: &mut impl VariantBuilderExt) -> Result<(), ArrowError> { - let json: Value = serde_json::from_str(json) - .map_err(|e| ArrowError::InvalidArgumentError(format!("JSON format error: {e}")))?; - - build_json(&json, builder)?; - Ok(()) +pub trait JsonToVariant { + /// Create a Variant from a JSON string + fn with_json(&mut self, json: &str) -> Result<(), ArrowError>; } -fn build_json(json: &Value, builder: &mut impl VariantBuilderExt) -> Result<(), ArrowError> { - append_json(json, builder)?; - Ok(()) +impl JsonToVariant for T { + fn with_json(&mut self, json: &str) -> Result<(), ArrowError> { + let json: Value = serde_json::from_str(json) + .map_err(|e| ArrowError::InvalidArgumentError(format!("JSON format error: {e}")))?; + + append_json(&json, self)?; + Ok(()) + } } fn variant_from_number<'m, 'v>(n: &Number) -> Result, ArrowError> { @@ -152,31 +151,6 @@ impl VariantBuilderExt for ObjectFieldBuilder<'_, '_, '_> { } } -/// Extension trait for creating Variants from JSON -/// -/// This trait provides a convenient method for VariantBuilder to parse JSON strings. -/// -/// # Example -/// ```rust -/// use parquet_variant::VariantBuilder; -/// use parquet_variant_json::JsonToVariant; -/// -/// let mut builder = VariantBuilder::new(); -/// builder.with_json("{\"name\":\"Alice\",\"age\":30}")?; -/// let (metadata, value) = builder.finish(); -/// # Ok::<(), arrow_schema::ArrowError>(()) -/// ``` -pub trait JsonToVariant { - /// Create a Variant from a JSON string - fn with_json(&mut self, json: &str) -> Result<(), ArrowError>; -} - -impl JsonToVariant for T { - fn with_json(&mut self, json: &str) -> Result<(), ArrowError> { - json_to_variant(json, self) - } -} - #[cfg(test)] mod test { use super::*; From 0042eb18e4cba0910c1d9f65ba59a738fed13a0e Mon Sep 17 00:00:00 2001 From: Liam Bao Date: Sat, 16 Aug 2025 23:05:24 -0400 Subject: [PATCH 6/9] Refactor `to_json` --- parquet-variant-json/src/to_json.rs | 623 +++++++++++++--------------- 1 file changed, 298 insertions(+), 325 deletions(-) diff --git a/parquet-variant-json/src/to_json.rs b/parquet-variant-json/src/to_json.rs index c3610d5d5b90..4753d6cc96ed 100644 --- a/parquet-variant-json/src/to_json.rs +++ b/parquet-variant-json/src/to_json.rs @@ -23,6 +23,304 @@ use parquet_variant::{Variant, VariantList, VariantObject}; use serde_json::Value; use std::io::Write; +/// Extension trait for converting Variants to JSON +pub trait VariantToJson { + /// + /// This function writes JSON directly to any type that implements [`Write`], + /// making it efficient for streaming or when you want to control the output destination. + /// + /// See [`VariantToJson::to_json_string`] for a convenience function that returns a + /// JSON string. + /// + /// # Arguments + /// + /// * `writer` - Writer to output JSON to + /// * `variant` - The Variant value to convert + /// + /// # Returns + /// + /// * `Ok(())` if successful + /// * `Err` with error details if conversion fails + /// + /// # Examples + /// + /// + /// ```rust + /// # use parquet_variant::{Variant}; + /// # use parquet_variant_json::VariantToJson; + /// # use arrow_schema::ArrowError; + /// let variant = Variant::from("Hello, World!"); + /// let mut buffer = Vec::new(); + /// variant.to_json(&mut buffer)?; + /// assert_eq!(String::from_utf8(buffer).unwrap(), "\"Hello, World!\""); + /// # Ok::<(), ArrowError>(()) + /// ``` + /// + /// # Example: Create a [`Variant::Object`] and convert to JSON + /// ```rust + /// # use parquet_variant::{Variant, VariantBuilder}; + /// # use parquet_variant_json::VariantToJson; + /// # use arrow_schema::ArrowError; + /// let mut builder = VariantBuilder::new(); + /// // Create an object builder that will write fields to the object + /// let mut object_builder = builder.new_object(); + /// object_builder.insert("first_name", "Jiaying"); + /// object_builder.insert("last_name", "Li"); + /// object_builder.finish(); + /// // Finish the builder to get the metadata and value + /// let (metadata, value) = builder.finish(); + /// // Create the Variant and convert to JSON + /// let variant = Variant::try_new(&metadata, &value)?; + /// let mut writer = Vec::new(); + /// variant.to_json(&mut writer)?; + /// assert_eq!(br#"{"first_name":"Jiaying","last_name":"Li"}"#, writer.as_slice()); + /// # Ok::<(), ArrowError>(()) + /// ``` + fn to_json(&self, buffer: &mut impl Write) -> Result<(), ArrowError>; + + /// Convert [`Variant`] to JSON [`String`] + /// + /// This is a convenience function that converts a Variant to a JSON string. + /// This is the same as calling [`VariantToJson::to_json`] with a [`Vec`]. + /// It's the simplest way to get a JSON representation when you just need a String result. + /// + /// # Arguments + /// + /// * `variant` - The Variant value to convert + /// + /// # Returns + /// + /// * `Ok(String)` containing the JSON representation + /// * `Err` with error details if conversion fails + /// + /// # Examples + /// + /// ```rust + /// # use parquet_variant::{Variant}; + /// # use parquet_variant_json::VariantToJson; + /// # use arrow_schema::ArrowError; + /// let variant = Variant::Int32(42); + /// let json = variant.to_json_string()?; + /// assert_eq!(json, "42"); + /// # Ok::<(), ArrowError>(()) + /// ``` + /// + /// # Example: Create a [`Variant::Object`] and convert to JSON + /// + /// This example shows how to create an object with two fields and convert it to JSON: + /// ```json + /// { + /// "first_name": "Jiaying", + /// "last_name": "Li" + /// } + /// ``` + /// + /// ```rust + /// # use parquet_variant::{Variant, VariantBuilder}; + /// # use parquet_variant_json::VariantToJson; + /// # use arrow_schema::ArrowError; + /// let mut builder = VariantBuilder::new(); + /// // Create an object builder that will write fields to the object + /// let mut object_builder = builder.new_object(); + /// object_builder.insert("first_name", "Jiaying"); + /// object_builder.insert("last_name", "Li"); + /// object_builder.finish(); + /// // Finish the builder to get the metadata and value + /// let (metadata, value) = builder.finish(); + /// // Create the Variant and convert to JSON + /// let variant = Variant::try_new(&metadata, &value)?; + /// let json = variant.to_json_string()?; + /// assert_eq!(r#"{"first_name":"Jiaying","last_name":"Li"}"#, json); + /// # Ok::<(), ArrowError>(()) + /// ``` + fn to_json_string(&self) -> Result; + + /// Convert [`Variant`] to [`serde_json::Value`] + /// + /// This function converts a Variant to a [`serde_json::Value`], which is useful + /// when you need to work with the JSON data programmatically or integrate with + /// other serde-based JSON processing. + /// + /// # Arguments + /// + /// * `variant` - The Variant value to convert + /// + /// # Returns + /// + /// * `Ok(Value)` containing the JSON value + /// * `Err` with error details if conversion fails + /// + /// # Examples + /// + /// ```rust + /// # use parquet_variant::{Variant}; + /// # use parquet_variant_json::VariantToJson; + /// # use serde_json::Value; + /// # use arrow_schema::ArrowError; + /// let variant = Variant::from("hello"); + /// let json_value = variant.to_json_value()?; + /// assert_eq!(json_value, Value::String("hello".to_string())); + /// # Ok::<(), ArrowError>(()) + /// ``` + fn to_json_value(&self) -> Result; +} + +impl<'m, 'v> VariantToJson for Variant<'m, 'v> { + fn to_json(&self, buffer: &mut impl Write) -> Result<(), ArrowError> { + match self { + Variant::Null => write!(buffer, "null")?, + Variant::BooleanTrue => write!(buffer, "true")?, + Variant::BooleanFalse => write!(buffer, "false")?, + Variant::Int8(i) => write!(buffer, "{i}")?, + Variant::Int16(i) => write!(buffer, "{i}")?, + Variant::Int32(i) => write!(buffer, "{i}")?, + Variant::Int64(i) => write!(buffer, "{i}")?, + Variant::Float(f) => write!(buffer, "{f}")?, + Variant::Double(f) => write!(buffer, "{f}")?, + Variant::Decimal4(decimal) => write!(buffer, "{decimal}")?, + Variant::Decimal8(decimal) => write!(buffer, "{decimal}")?, + Variant::Decimal16(decimal) => write!(buffer, "{decimal}")?, + Variant::Date(date) => write!(buffer, "\"{}\"", format_date_string(date))?, + Variant::TimestampMicros(ts) => write!(buffer, "\"{}\"", ts.to_rfc3339())?, + Variant::TimestampNtzMicros(ts) => { + write!(buffer, "\"{}\"", format_timestamp_ntz_string(ts))? + } + Variant::Time(time) => write!(buffer, "\"{}\"", format_time_ntz_str(time))?, + Variant::Binary(bytes) => { + // Encode binary as base64 string + let base64_str = format_binary_base64(bytes); + let json_str = serde_json::to_string(&base64_str).map_err(|e| { + ArrowError::InvalidArgumentError(format!("JSON encoding error: {e}")) + })?; + write!(buffer, "{json_str}")? + } + Variant::String(s) => { + // Use serde_json to properly escape the string + let json_str = serde_json::to_string(s).map_err(|e| { + ArrowError::InvalidArgumentError(format!("JSON encoding error: {e}")) + })?; + write!(buffer, "{json_str}")? + } + Variant::ShortString(s) => { + // Use serde_json to properly escape the string + let json_str = serde_json::to_string(s.as_str()).map_err(|e| { + ArrowError::InvalidArgumentError(format!("JSON encoding error: {e}")) + })?; + write!(buffer, "{json_str}")? + } + Variant::Object(obj) => { + convert_object_to_json(buffer, obj)?; + } + Variant::List(arr) => { + convert_array_to_json(buffer, arr)?; + } + } + Ok(()) + } + + fn to_json_string(&self) -> Result { + let mut buffer = Vec::new(); + self.to_json(&mut buffer)?; + String::from_utf8(buffer) + .map_err(|e| ArrowError::InvalidArgumentError(format!("UTF-8 conversion error: {e}"))) + } + + fn to_json_value(&self) -> Result { + match self { + Variant::Null => Ok(Value::Null), + Variant::BooleanTrue => Ok(Value::Bool(true)), + Variant::BooleanFalse => Ok(Value::Bool(false)), + Variant::Int8(i) => Ok(Value::Number((*i).into())), + Variant::Int16(i) => Ok(Value::Number((*i).into())), + Variant::Int32(i) => Ok(Value::Number((*i).into())), + Variant::Int64(i) => Ok(Value::Number((*i).into())), + Variant::Float(f) => serde_json::Number::from_f64((*f).into()) + .map(Value::Number) + .ok_or_else(|| ArrowError::InvalidArgumentError("Invalid float value".to_string())), + Variant::Double(f) => serde_json::Number::from_f64(*f) + .map(Value::Number) + .ok_or_else(|| { + ArrowError::InvalidArgumentError("Invalid double value".to_string()) + }), + Variant::Decimal4(decimal4) => { + let scale = decimal4.scale(); + let integer = decimal4.integer(); + + let integer = if scale == 0 { + integer + } else { + let divisor = 10_i32.pow(scale as u32); + if integer % divisor != 0 { + // fall back to floating point + return Ok(Value::from(integer as f64 / divisor as f64)); + } + integer / divisor + }; + Ok(Value::from(integer)) + } + Variant::Decimal8(decimal8) => { + let scale = decimal8.scale(); + let integer = decimal8.integer(); + + let integer = if scale == 0 { + integer + } else { + let divisor = 10_i64.pow(scale as u32); + if integer % divisor != 0 { + // fall back to floating point + return Ok(Value::from(integer as f64 / divisor as f64)); + } + integer / divisor + }; + Ok(Value::from(integer)) + } + Variant::Decimal16(decimal16) => { + let scale = decimal16.scale(); + let integer = decimal16.integer(); + + let integer = if scale == 0 { + integer + } else { + let divisor = 10_i128.pow(scale as u32); + if integer % divisor != 0 { + // fall back to floating point + return Ok(Value::from(integer as f64 / divisor as f64)); + } + integer / divisor + }; + // i128 has higher precision than any 64-bit type. Try a lossless narrowing cast to + // i64 or u64 first, falling back to a lossy narrowing cast to f64 if necessary. + let value = i64::try_from(integer) + .map(Value::from) + .or_else(|_| u64::try_from(integer).map(Value::from)) + .unwrap_or_else(|_| Value::from(integer as f64)); + Ok(value) + } + Variant::Date(date) => Ok(Value::String(format_date_string(date))), + Variant::TimestampMicros(ts) => Ok(Value::String(ts.to_rfc3339())), + Variant::TimestampNtzMicros(ts) => Ok(Value::String(format_timestamp_ntz_string(ts))), + Variant::Time(time) => Ok(Value::String(format_time_ntz_str(time))), + Variant::Binary(bytes) => Ok(Value::String(format_binary_base64(bytes))), + Variant::String(s) => Ok(Value::String(s.to_string())), + Variant::ShortString(s) => Ok(Value::String(s.to_string())), + Variant::Object(obj) => { + let map = obj + .iter() + .map(|(k, v)| v.to_json_value().map(|json_val| (k.to_string(), json_val))) + .collect::>()?; + Ok(Value::Object(map)) + } + Variant::List(arr) => { + let vec = arr + .iter() + .map(|element| element.to_json_value()) + .collect::>()?; + Ok(Value::Array(vec)) + } + } + } +} + // Format string constants to avoid duplication and reduce errors const DATE_FORMAT: &str = "%Y-%m-%d"; const TIMESTAMP_NTZ_FORMAT: &str = "%Y-%m-%dT%H:%M:%S%.6f"; @@ -53,109 +351,6 @@ fn format_time_ntz_str(time: &chrono::NaiveTime) -> String { } } -/// -/// This function writes JSON directly to any type that implements [`Write`], -/// making it efficient for streaming or when you want to control the output destination. -/// -/// See [`variant_to_json_string`] for a convenience function that returns a -/// JSON string. -/// -/// # Arguments -/// -/// * `writer` - Writer to output JSON to -/// * `variant` - The Variant value to convert -/// -/// # Returns -/// -/// * `Ok(())` if successful -/// * `Err` with error details if conversion fails -/// -/// # Examples -/// -/// -/// ```rust -/// # use parquet_variant::{Variant}; -/// # use parquet_variant_json::VariantToJson; -/// # use arrow_schema::ArrowError; -/// let variant = Variant::from("Hello, World!"); -/// let mut buffer = Vec::new(); -/// variant.to_json(&mut buffer)?; -/// assert_eq!(String::from_utf8(buffer).unwrap(), "\"Hello, World!\""); -/// # Ok::<(), ArrowError>(()) -/// ``` -/// -/// # Example: Create a [`Variant::Object`] and convert to JSON -/// ```rust -/// # use parquet_variant::{Variant, VariantBuilder}; -/// # use parquet_variant_json::VariantToJson; -/// # use arrow_schema::ArrowError; -/// let mut builder = VariantBuilder::new(); -/// // Create an object builder that will write fields to the object -/// let mut object_builder = builder.new_object(); -/// object_builder.insert("first_name", "Jiaying"); -/// object_builder.insert("last_name", "Li"); -/// object_builder.finish(); -/// // Finish the builder to get the metadata and value -/// let (metadata, value) = builder.finish(); -/// // Create the Variant and convert to JSON -/// let variant = Variant::try_new(&metadata, &value)?; -/// let mut writer = Vec::new(); -/// variant.to_json(&mut writer)?; -/// assert_eq!(br#"{"first_name":"Jiaying","last_name":"Li"}"#, writer.as_slice()); -/// # Ok::<(), ArrowError>(()) -/// ``` -fn variant_to_json(json_buffer: &mut impl Write, variant: &Variant) -> Result<(), ArrowError> { - match variant { - Variant::Null => write!(json_buffer, "null")?, - Variant::BooleanTrue => write!(json_buffer, "true")?, - Variant::BooleanFalse => write!(json_buffer, "false")?, - Variant::Int8(i) => write!(json_buffer, "{i}")?, - Variant::Int16(i) => write!(json_buffer, "{i}")?, - Variant::Int32(i) => write!(json_buffer, "{i}")?, - Variant::Int64(i) => write!(json_buffer, "{i}")?, - Variant::Float(f) => write!(json_buffer, "{f}")?, - Variant::Double(f) => write!(json_buffer, "{f}")?, - Variant::Decimal4(decimal) => write!(json_buffer, "{decimal}")?, - Variant::Decimal8(decimal) => write!(json_buffer, "{decimal}")?, - Variant::Decimal16(decimal) => write!(json_buffer, "{decimal}")?, - Variant::Date(date) => write!(json_buffer, "\"{}\"", format_date_string(date))?, - Variant::TimestampMicros(ts) => write!(json_buffer, "\"{}\"", ts.to_rfc3339())?, - Variant::TimestampNtzMicros(ts) => { - write!(json_buffer, "\"{}\"", format_timestamp_ntz_string(ts))? - } - Variant::Time(time) => write!(json_buffer, "\"{}\"", format_time_ntz_str(time))?, - Variant::Binary(bytes) => { - // Encode binary as base64 string - let base64_str = format_binary_base64(bytes); - let json_str = serde_json::to_string(&base64_str).map_err(|e| { - ArrowError::InvalidArgumentError(format!("JSON encoding error: {e}")) - })?; - write!(json_buffer, "{json_str}")? - } - Variant::String(s) => { - // Use serde_json to properly escape the string - let json_str = serde_json::to_string(s).map_err(|e| { - ArrowError::InvalidArgumentError(format!("JSON encoding error: {e}")) - })?; - write!(json_buffer, "{json_str}")? - } - Variant::ShortString(s) => { - // Use serde_json to properly escape the string - let json_str = serde_json::to_string(s.as_str()).map_err(|e| { - ArrowError::InvalidArgumentError(format!("JSON encoding error: {e}")) - })?; - write!(json_buffer, "{json_str}")? - } - Variant::Object(obj) => { - convert_object_to_json(json_buffer, obj)?; - } - Variant::List(arr) => { - convert_array_to_json(json_buffer, arr)?; - } - } - Ok(()) -} - /// Convert object fields to JSON fn convert_object_to_json(buffer: &mut impl Write, obj: &VariantObject) -> Result<(), ArrowError> { write!(buffer, "{{")?; @@ -201,228 +396,6 @@ fn convert_array_to_json(buffer: &mut impl Write, arr: &VariantList) -> Result<( Ok(()) } -/// Convert [`Variant`] to JSON [`String`] -/// -/// This is a convenience function that converts a Variant to a JSON string. -/// This is the same as calling [`variant_to_json`] with a [`Vec`]. -/// It's the simplest way to get a JSON representation when you just need a String result. -/// -/// # Arguments -/// -/// * `variant` - The Variant value to convert -/// -/// # Returns -/// -/// * `Ok(String)` containing the JSON representation -/// * `Err` with error details if conversion fails -/// -/// # Examples -/// -/// ```rust -/// # use parquet_variant::{Variant}; -/// # use parquet_variant_json::VariantToJson; -/// # use arrow_schema::ArrowError; -/// let variant = Variant::Int32(42); -/// let json = variant.to_json_string()?; -/// assert_eq!(json, "42"); -/// # Ok::<(), ArrowError>(()) -/// ``` -/// -/// # Example: Create a [`Variant::Object`] and convert to JSON -/// -/// This example shows how to create an object with two fields and convert it to JSON: -/// ```json -/// { -/// "first_name": "Jiaying", -/// "last_name": "Li" -/// } -/// ``` -/// -/// ```rust -/// # use parquet_variant::{Variant, VariantBuilder}; -/// # use parquet_variant_json::VariantToJson; -/// # use arrow_schema::ArrowError; -/// let mut builder = VariantBuilder::new(); -/// // Create an object builder that will write fields to the object -/// let mut object_builder = builder.new_object(); -/// object_builder.insert("first_name", "Jiaying"); -/// object_builder.insert("last_name", "Li"); -/// object_builder.finish(); -/// // Finish the builder to get the metadata and value -/// let (metadata, value) = builder.finish(); -/// // Create the Variant and convert to JSON -/// let variant = Variant::try_new(&metadata, &value)?; -/// let json = variant.to_json_string()?; -/// assert_eq!(r#"{"first_name":"Jiaying","last_name":"Li"}"#, json); -/// # Ok::<(), ArrowError>(()) -/// ``` -fn variant_to_json_string(variant: &Variant) -> Result { - let mut buffer = Vec::new(); - variant.to_json(&mut buffer)?; - String::from_utf8(buffer) - .map_err(|e| ArrowError::InvalidArgumentError(format!("UTF-8 conversion error: {e}"))) -} - -/// Convert [`Variant`] to [`serde_json::Value`] -/// -/// This function converts a Variant to a [`serde_json::Value`], which is useful -/// when you need to work with the JSON data programmatically or integrate with -/// other serde-based JSON processing. -/// -/// # Arguments -/// -/// * `variant` - The Variant value to convert -/// -/// # Returns -/// -/// * `Ok(Value)` containing the JSON value -/// * `Err` with error details if conversion fails -/// -/// # Examples -/// -/// ```rust -/// # use parquet_variant::{Variant}; -/// # use parquet_variant_json::VariantToJson; -/// # use serde_json::Value; -/// # use arrow_schema::ArrowError; -/// let variant = Variant::from("hello"); -/// let json_value = variant.to_json_value()?; -/// assert_eq!(json_value, Value::String("hello".to_string())); -/// # Ok::<(), ArrowError>(()) -/// ``` -fn variant_to_json_value(variant: &Variant) -> Result { - match variant { - Variant::Null => Ok(Value::Null), - Variant::BooleanTrue => Ok(Value::Bool(true)), - Variant::BooleanFalse => Ok(Value::Bool(false)), - Variant::Int8(i) => Ok(Value::Number((*i).into())), - Variant::Int16(i) => Ok(Value::Number((*i).into())), - Variant::Int32(i) => Ok(Value::Number((*i).into())), - Variant::Int64(i) => Ok(Value::Number((*i).into())), - Variant::Float(f) => serde_json::Number::from_f64((*f).into()) - .map(Value::Number) - .ok_or_else(|| ArrowError::InvalidArgumentError("Invalid float value".to_string())), - Variant::Double(f) => serde_json::Number::from_f64(*f) - .map(Value::Number) - .ok_or_else(|| ArrowError::InvalidArgumentError("Invalid double value".to_string())), - Variant::Decimal4(decimal4) => { - let scale = decimal4.scale(); - let integer = decimal4.integer(); - - let integer = if scale == 0 { - integer - } else { - let divisor = 10_i32.pow(scale as u32); - if integer % divisor != 0 { - // fall back to floating point - return Ok(Value::from(integer as f64 / divisor as f64)); - } - integer / divisor - }; - Ok(Value::from(integer)) - } - Variant::Decimal8(decimal8) => { - let scale = decimal8.scale(); - let integer = decimal8.integer(); - - let integer = if scale == 0 { - integer - } else { - let divisor = 10_i64.pow(scale as u32); - if integer % divisor != 0 { - // fall back to floating point - return Ok(Value::from(integer as f64 / divisor as f64)); - } - integer / divisor - }; - Ok(Value::from(integer)) - } - Variant::Decimal16(decimal16) => { - let scale = decimal16.scale(); - let integer = decimal16.integer(); - - let integer = if scale == 0 { - integer - } else { - let divisor = 10_i128.pow(scale as u32); - if integer % divisor != 0 { - // fall back to floating point - return Ok(Value::from(integer as f64 / divisor as f64)); - } - integer / divisor - }; - // i128 has higher precision than any 64-bit type. Try a lossless narrowing cast to - // i64 or u64 first, falling back to a lossy narrowing cast to f64 if necessary. - let value = i64::try_from(integer) - .map(Value::from) - .or_else(|_| u64::try_from(integer).map(Value::from)) - .unwrap_or_else(|_| Value::from(integer as f64)); - Ok(value) - } - Variant::Date(date) => Ok(Value::String(format_date_string(date))), - Variant::TimestampMicros(ts) => Ok(Value::String(ts.to_rfc3339())), - Variant::TimestampNtzMicros(ts) => Ok(Value::String(format_timestamp_ntz_string(ts))), - Variant::Time(time) => Ok(Value::String(format_time_ntz_str(time))), - Variant::Binary(bytes) => Ok(Value::String(format_binary_base64(bytes))), - Variant::String(s) => Ok(Value::String(s.to_string())), - Variant::ShortString(s) => Ok(Value::String(s.to_string())), - Variant::Object(obj) => { - let map = obj - .iter() - .map(|(k, v)| v.to_json_value().map(|json_val| (k.to_string(), json_val))) - .collect::>()?; - Ok(Value::Object(map)) - } - Variant::List(arr) => { - let vec = arr - .iter() - .map(|element| element.to_json_value()) - .collect::>()?; - Ok(Value::Array(vec)) - } - } -} - -/// Extension trait for converting Variants to JSON -/// -/// This trait provides a convenient method for Variant to convert to JSON. -/// -/// # Example -/// ```rust -/// use parquet_variant::Variant; -/// use parquet_variant_json::VariantToJson; -/// -/// let variant = Variant::Int32(42); -/// let mut buffer = Vec::new(); -/// variant.to_json(&mut buffer)?; -/// assert_eq!(String::from_utf8(buffer)?, "42"); -/// # Ok::<(), arrow_schema::ArrowError>(()) -/// ``` -pub trait VariantToJson { - /// Write this variant as JSON to a writer - fn to_json(&self, buffer: &mut impl Write) -> Result<(), ArrowError>; - - /// Convert this variant to a JSON string - fn to_json_string(&self) -> Result; - - /// Convert this variant to a serde_json::Value - fn to_json_value(&self) -> Result; -} - -impl<'m, 'v> VariantToJson for Variant<'m, 'v> { - fn to_json(&self, buffer: &mut impl Write) -> Result<(), ArrowError> { - variant_to_json(buffer, self) - } - - fn to_json_string(&self) -> Result { - variant_to_json_string(self) - } - - fn to_json_value(&self) -> Result { - variant_to_json_value(self) - } -} - #[cfg(test)] mod tests { use super::*; From 4383f2b4be6ad02aa6cb61eca97106d9de4e74d2 Mon Sep 17 00:00:00 2001 From: Liam Bao Date: Sun, 17 Aug 2025 10:01:52 -0400 Subject: [PATCH 7/9] Rename tests --- parquet-variant-compute/src/from_json.rs | 2 +- parquet-variant-compute/src/to_json.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/parquet-variant-compute/src/from_json.rs b/parquet-variant-compute/src/from_json.rs index 304dc3fc51bf..ca1361cf8b4f 100644 --- a/parquet-variant-compute/src/from_json.rs +++ b/parquet-variant-compute/src/from_json.rs @@ -58,7 +58,7 @@ mod test { use std::sync::Arc; #[test] - fn test_batch_json_string_to_variant() -> Result<(), ArrowError> { + fn test_json_to_variant() -> Result<(), ArrowError> { let input = StringArray::from(vec![ Some("1"), None, diff --git a/parquet-variant-compute/src/to_json.rs b/parquet-variant-compute/src/to_json.rs index f07b2ee39f9d..1d6f51ca2446 100644 --- a/parquet-variant-compute/src/to_json.rs +++ b/parquet-variant-compute/src/to_json.rs @@ -113,7 +113,7 @@ mod test { use std::sync::Arc; #[test] - fn test_batch_variant_to_json_string() { + fn test_variant_to_json() { let mut metadata_builder = BinaryBuilder::new(); let mut value_builder = BinaryBuilder::new(); From 7bc6c8f1fcad17e4e30302707d67c701079a542f Mon Sep 17 00:00:00 2001 From: Andrew Lamb Date: Mon, 18 Aug 2025 14:14:43 -0400 Subject: [PATCH 8/9] rename `with_json` to `append_json` --- parquet-variant-compute/src/from_json.rs | 2 +- parquet-variant-json/src/from_json.rs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/parquet-variant-compute/src/from_json.rs b/parquet-variant-compute/src/from_json.rs index ca1361cf8b4f..28612f8386d9 100644 --- a/parquet-variant-compute/src/from_json.rs +++ b/parquet-variant-compute/src/from_json.rs @@ -42,7 +42,7 @@ pub fn json_to_variant(input: &ArrayRef) -> Result { } else { let mut vb = variant_array_builder.variant_builder(); // parse JSON directly to the variant builder - vb.with_json(input_string_array.value(i))?; + vb.append_json(input_string_array.value(i))?; vb.finish() } } diff --git a/parquet-variant-json/src/from_json.rs b/parquet-variant-json/src/from_json.rs index e70e21d51d53..6f6751ede33e 100644 --- a/parquet-variant-json/src/from_json.rs +++ b/parquet-variant-json/src/from_json.rs @@ -21,7 +21,7 @@ use arrow_schema::ArrowError; use parquet_variant::{ListBuilder, ObjectBuilder, Variant, VariantBuilderExt}; use serde_json::{Number, Value}; -/// Converts a JSON string to Variant to a [`VariantBuilderExt`], such as +/// Converts a JSON string to Variant using a [`VariantBuilderExt`], such as /// [`VariantBuilder`]. /// /// The resulting `value` and `metadata` buffers can be @@ -45,7 +45,7 @@ use serde_json::{Number, Value}; /// let person_string = "{\"name\":\"Alice\", \"age\":30, ".to_string() /// + "\"email\":\"alice@example.com\", \"is_active\": true, \"score\": 95.7," /// + "\"additional_info\": null}"; -/// variant_builder.with_json(&person_string)?; +/// variant_builder.append_json(&person_string)?; /// /// let (metadata, value) = variant_builder.finish(); /// @@ -65,11 +65,11 @@ use serde_json::{Number, Value}; /// ``` pub trait JsonToVariant { /// Create a Variant from a JSON string - fn with_json(&mut self, json: &str) -> Result<(), ArrowError>; + fn append_json(&mut self, json: &str) -> Result<(), ArrowError>; } impl JsonToVariant for T { - fn with_json(&mut self, json: &str) -> Result<(), ArrowError> { + fn append_json(&mut self, json: &str) -> Result<(), ArrowError> { let json: Value = serde_json::from_str(json) .map_err(|e| ArrowError::InvalidArgumentError(format!("JSON format error: {e}")))?; @@ -168,7 +168,7 @@ mod test { impl JsonToVariantTest<'_> { fn run(self) -> Result<(), ArrowError> { let mut variant_builder = VariantBuilder::new(); - variant_builder.with_json(self.json)?; + variant_builder.append_json(self.json)?; let (metadata, value) = variant_builder.finish(); let variant = Variant::try_new(&metadata, &value)?; assert_eq!(variant, self.expected); @@ -619,7 +619,7 @@ mod test { ); // Manually verify raw JSON value size let mut variant_builder = VariantBuilder::new(); - variant_builder.with_json(&json)?; + variant_builder.append_json(&json)?; let (metadata, value) = variant_builder.finish(); let v = Variant::try_new(&metadata, &value)?; let output_string = v.to_json_string()?; @@ -660,7 +660,7 @@ mod test { fn test_json_to_variant_unicode() -> Result<(), ArrowError> { let json = "{\"爱\":\"अ\",\"a\":1}"; let mut variant_builder = VariantBuilder::new(); - variant_builder.with_json(json)?; + variant_builder.append_json(json)?; let (metadata, value) = variant_builder.finish(); let v = Variant::try_new(&metadata, &value)?; let output_string = v.to_json_string()?; From 2f00e879e20641ba88c797ca04d957c00cb64764 Mon Sep 17 00:00:00 2001 From: Liam Bao Date: Tue, 19 Aug 2025 09:59:32 -0400 Subject: [PATCH 9/9] Rename tests --- parquet-variant-compute/src/from_json.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parquet-variant-compute/src/from_json.rs b/parquet-variant-compute/src/from_json.rs index 2b7531ec379b..8512620f4631 100644 --- a/parquet-variant-compute/src/from_json.rs +++ b/parquet-variant-compute/src/from_json.rs @@ -124,7 +124,7 @@ mod test { } #[test] - fn test_batch_json_string_to_variant_large_string() -> Result<(), ArrowError> { + fn test_json_to_variant_large_string() -> Result<(), ArrowError> { let input = LargeStringArray::from(vec![ Some("1"), None, @@ -173,7 +173,7 @@ mod test { } #[test] - fn test_batch_json_string_to_variant_string_view() -> Result<(), ArrowError> { + fn test_json_to_variant_string_view() -> Result<(), ArrowError> { let input = StringViewArray::from(vec![ Some("1"), None,