You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by tu...@apache.org on 2023/06/05 18:43:51 UTC

[arrow-rs] branch master updated: Have array_to_json_array support MapArray (#4364)

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 7c406e446 Have array_to_json_array support MapArray (#4364)
7c406e446 is described below

commit 7c406e4465ced4b3a69ef8ba4d1dbb341ce8d0c7
Author: dadepo <da...@gmail.com>
AuthorDate: Mon Jun 5 22:43:45 2023 +0400

    Have array_to_json_array support MapArray (#4364)
    
    * Have array_to_json_array support MapArray
    
    * Have the iterator for MapArray return StructArray
---
 arrow-array/src/array/map_array.rs | 22 +++++++++++++-
 arrow-array/src/iterator.rs        |  4 ++-
 arrow-json/src/writer.rs           | 59 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 83 insertions(+), 2 deletions(-)

diff --git a/arrow-array/src/array/map_array.rs b/arrow-array/src/array/map_array.rs
index cf0978f05..c98bca950 100644
--- a/arrow-array/src/array/map_array.rs
+++ b/arrow-array/src/array/map_array.rs
@@ -16,7 +16,10 @@
 // under the License.
 
 use crate::array::{get_offsets, print_long_array};
-use crate::{make_array, Array, ArrayRef, ListArray, StringArray, StructArray};
+use crate::iterator::MapArrayIter;
+use crate::{
+    make_array, Array, ArrayAccessor, ArrayRef, ListArray, StringArray, StructArray,
+};
 use arrow_buffer::{ArrowNativeType, Buffer, NullBuffer, OffsetBuffer, ToByteSlice};
 use arrow_data::{ArrayData, ArrayDataBuilder};
 use arrow_schema::{ArrowError, DataType, Field};
@@ -116,6 +119,11 @@ impl MapArray {
             value_offsets: self.value_offsets.slice(offset, length),
         }
     }
+
+    /// constructs a new iterator
+    pub fn iter(&self) -> MapArrayIter<'_> {
+        MapArrayIter::new(self)
+    }
 }
 
 impl From<ArrayData> for MapArray {
@@ -284,6 +292,18 @@ impl Array for MapArray {
     }
 }
 
+impl<'a> ArrayAccessor for &'a MapArray {
+    type Item = StructArray;
+
+    fn value(&self, index: usize) -> Self::Item {
+        MapArray::value(self, index)
+    }
+
+    unsafe fn value_unchecked(&self, index: usize) -> Self::Item {
+        MapArray::value(self, index)
+    }
+}
+
 impl std::fmt::Debug for MapArray {
     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
         write!(f, "MapArray\n[\n")?;
diff --git a/arrow-array/src/iterator.rs b/arrow-array/src/iterator.rs
index fa76e09b2..86f5d9912 100644
--- a/arrow-array/src/iterator.rs
+++ b/arrow-array/src/iterator.rs
@@ -21,7 +21,7 @@ use crate::array::{
     ArrayAccessor, BooleanArray, FixedSizeBinaryArray, GenericBinaryArray,
     GenericListArray, GenericStringArray, PrimitiveArray,
 };
-use crate::FixedSizeListArray;
+use crate::{FixedSizeListArray, MapArray};
 
 /// An iterator that returns Some(T) or None, that can be used on any [`ArrayAccessor`]
 ///
@@ -129,6 +129,8 @@ pub type FixedSizeBinaryIter<'a> = ArrayIter<&'a FixedSizeBinaryArray>;
 pub type FixedSizeListIter<'a> = ArrayIter<&'a FixedSizeListArray>;
 /// an iterator that returns Some(T) or None, that can be used on any ListArray
 pub type GenericListArrayIter<'a, O> = ArrayIter<&'a GenericListArray<O>>;
+/// an iterator that returns Some(T) or None, that can be used on any MapArray
+pub type MapArrayIter<'a> = ArrayIter<&'a MapArray>;
 
 #[cfg(test)]
 mod tests {
diff --git a/arrow-json/src/writer.rs b/arrow-json/src/writer.rs
index d2365118a..6fed0f747 100644
--- a/arrow-json/src/writer.rs
+++ b/arrow-json/src/writer.rs
@@ -94,6 +94,7 @@
 //! ```
 
 use std::iter;
+use std::sync::Arc;
 use std::{fmt::Debug, io::Write};
 
 use serde_json::map::Map as JsonMap;
@@ -202,6 +203,15 @@ pub fn array_to_json_array(array: &ArrayRef) -> Result<Vec<Value>, ArrowError> {
             let jsonmaps = struct_array_to_jsonmap_array(array.as_struct())?;
             Ok(jsonmaps.into_iter().map(Value::Object).collect())
         }
+        DataType::Map(_, _) => as_map_array(array)
+            .iter()
+            .map(|maybe_value| match maybe_value {
+                Some(v) => Ok(Value::Array(array_to_json_array(
+                    &(Arc::new(v) as ArrayRef),
+                )?)),
+                None => Ok(Value::Null),
+            })
+            .collect(),
         t => Err(ArrowError::JsonError(format!(
             "data type {t:?} not supported"
         ))),
@@ -617,6 +627,7 @@ mod tests {
     use std::io::{BufReader, Seek};
     use std::sync::Arc;
 
+    use arrow_array::builder::{Int32Builder, MapBuilder, StringBuilder};
     use serde_json::json;
 
     use arrow_buffer::{Buffer, ToByteSlice};
@@ -1520,4 +1531,52 @@ mod tests {
 
         assert_eq!(array_to_json_array(&list_array).unwrap(), expected_json);
     }
+
+    #[test]
+    fn test_array_to_json_array_for_map_array() {
+        let expected_json = serde_json::from_value::<Vec<Value>>(json!([
+            [
+                {
+                    "keys": "joe",
+                    "values": 1
+                }
+            ],
+            [
+                {
+                    "keys": "blogs",
+                    "values": 2
+                },
+                {
+                    "keys": "foo",
+                    "values": 4
+                }
+            ],
+            [],
+            null
+        ]))
+        .unwrap();
+
+        let string_builder = StringBuilder::new();
+        let int_builder = Int32Builder::with_capacity(4);
+
+        let mut builder = MapBuilder::new(None, string_builder, int_builder);
+
+        builder.keys().append_value("joe");
+        builder.values().append_value(1);
+        builder.append(true).unwrap();
+
+        builder.keys().append_value("blogs");
+        builder.values().append_value(2);
+        builder.keys().append_value("foo");
+        builder.values().append_value(4);
+        builder.append(true).unwrap();
+        builder.append(true).unwrap();
+        builder.append(false).unwrap();
+
+        let array = builder.finish();
+
+        let map_array = Arc::new(array) as ArrayRef;
+
+        assert_eq!(array_to_json_array(&map_array).unwrap(), expected_json);
+    }
 }