This is an automated email from the ASF dual-hosted git repository.

tustvold pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git


The following commit(s) were added to refs/heads/master by this push:
     new 4d4c0c62b Implement arrow_json encoder for Decimal128 & Decimal256 
(#6606)
4d4c0c62b is described below

commit 4d4c0c62b30f2112860f8074d0d64176b484cdac
Author: Phillip LeBlanc <[email protected]>
AuthorDate: Mon Oct 21 18:41:06 2024 +0900

    Implement arrow_json encoder for Decimal128 & Decimal256 (#6606)
    
    * Implement arrow_json encoder for Decimal128 & Decimal256
    
    * fix
    
    * Use primitive helper for i128
    
    * Revert "Use primitive helper for i128"
    
    This reverts commit dfe8edb350bd427b552ffbca1b853a7ab52baa0a.
    
    * Use ArrayFormatter directly
    
    ---------
    
    Co-authored-by: Raphael Taylor-Davies <[email protected]>
---
 arrow-json/src/writer/encoder.rs | 14 ++++++++
 arrow-json/src/writer/mod.rs     | 78 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 91 insertions(+), 1 deletion(-)

diff --git a/arrow-json/src/writer/encoder.rs b/arrow-json/src/writer/encoder.rs
index dfe628521..29a302f74 100644
--- a/arrow-json/src/writer/encoder.rs
+++ b/arrow-json/src/writer/encoder.rs
@@ -134,6 +134,11 @@ fn make_encoder_impl<'a>(
             };
             (Box::new(encoder) as _, array.nulls().cloned())
         }
+        DataType::Decimal128(_, _) | DataType::Decimal256(_, _) => {
+            let options = FormatOptions::new().with_display_error(true);
+            let formatter = ArrayFormatter::try_new(array, &options)?;
+            (Box::new(RawArrayFormatter(formatter)) as _, 
array.nulls().cloned())
+        }
         d => match d.is_temporal() {
             true => {
                 // Note: the implementation of Encoder for ArrayFormatter 
assumes it does not produce
@@ -434,6 +439,15 @@ impl<'a> Encoder for ArrayFormatter<'a> {
     }
 }
 
+/// A newtype wrapper around [`ArrayFormatter`] that skips surrounding the 
value with `"`
+struct RawArrayFormatter<'a>(ArrayFormatter<'a>);
+
+impl<'a> Encoder for RawArrayFormatter<'a> {
+    fn encode(&mut self, idx: usize, out: &mut Vec<u8>) {
+        let _ = write!(out, "{}", self.0.value(idx));
+    }
+}
+
 struct NullEncoder;
 
 impl Encoder for NullEncoder {
diff --git a/arrow-json/src/writer/mod.rs b/arrow-json/src/writer/mod.rs
index 9a93cf041..df18a9ad5 100644
--- a/arrow-json/src/writer/mod.rs
+++ b/arrow-json/src/writer/mod.rs
@@ -405,7 +405,7 @@ mod tests {
 
     use arrow_array::builder::*;
     use arrow_array::types::*;
-    use arrow_buffer::{Buffer, NullBuffer, OffsetBuffer, ToByteSlice};
+    use arrow_buffer::{i256, Buffer, NullBuffer, OffsetBuffer, ToByteSlice};
     use arrow_data::ArrayData;
 
     use crate::reader::*;
@@ -1833,4 +1833,80 @@ mod tests {
             r#"[{"my_dict":"a"},{"my_dict":null},{"my_dict":null}]"#
         )
     }
+
+    #[test]
+    fn test_decimal128_encoder() {
+        let array = Decimal128Array::from_iter_values([1234, 5678, 9012])
+            .with_precision_and_scale(10, 2)
+            .unwrap();
+        let field = Arc::new(Field::new("decimal", array.data_type().clone(), 
true));
+        let schema = Schema::new(vec![field]);
+        let batch = RecordBatch::try_new(Arc::new(schema), 
vec![Arc::new(array)]).unwrap();
+
+        let mut buf = Vec::new();
+        {
+            let mut writer = LineDelimitedWriter::new(&mut buf);
+            writer.write_batches(&[&batch]).unwrap();
+        }
+
+        assert_json_eq(
+            &buf,
+            r#"{"decimal":12.34}
+{"decimal":56.78}
+{"decimal":90.12}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_decimal256_encoder() {
+        let array = Decimal256Array::from_iter_values([
+            i256::from(123400),
+            i256::from(567800),
+            i256::from(901200),
+        ])
+        .with_precision_and_scale(10, 4)
+        .unwrap();
+        let field = Arc::new(Field::new("decimal", array.data_type().clone(), 
true));
+        let schema = Schema::new(vec![field]);
+        let batch = RecordBatch::try_new(Arc::new(schema), 
vec![Arc::new(array)]).unwrap();
+
+        let mut buf = Vec::new();
+        {
+            let mut writer = LineDelimitedWriter::new(&mut buf);
+            writer.write_batches(&[&batch]).unwrap();
+        }
+
+        assert_json_eq(
+            &buf,
+            r#"{"decimal":12.3400}
+{"decimal":56.7800}
+{"decimal":90.1200}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_decimal_encoder_with_nulls() {
+        let array = Decimal128Array::from_iter([Some(1234), None, Some(5678)])
+            .with_precision_and_scale(10, 2)
+            .unwrap();
+        let field = Arc::new(Field::new("decimal", array.data_type().clone(), 
true));
+        let schema = Schema::new(vec![field]);
+        let batch = RecordBatch::try_new(Arc::new(schema), 
vec![Arc::new(array)]).unwrap();
+
+        let mut buf = Vec::new();
+        {
+            let mut writer = LineDelimitedWriter::new(&mut buf);
+            writer.write_batches(&[&batch]).unwrap();
+        }
+
+        assert_json_eq(
+            &buf,
+            r#"{"decimal":12.34}
+{}
+{"decimal":56.78}
+"#,
+        );
+    }
 }

Reply via email to