Skip to content

Commit 3acb8ec

Browse files
committed
Preserve list element metadata when rebuilding scalar values
1 parent db83fcc commit 3acb8ec

1 file changed

Lines changed: 26 additions & 6 deletions

File tree

  • datafusion/common/src/utils

‎datafusion/common/src/utils/mod.rs‎

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use arrow::compute::kernels::cmp::eq;
4343
use arrow::compute::kernels::length::length;
4444
use arrow::compute::{SortColumn, SortOptions, nullif, partition};
4545
use arrow::datatypes::{
46-
ArrowNativeType, DataType, Field, Int32Type, Int64Type, SchemaRef,
46+
ArrowNativeType, DataType, Field, Int32Type, Int64Type, Metadata, SchemaRef,
4747
};
4848
#[cfg(feature = "sql")]
4949
use sqlparser::{ast::Ident, dialect::GenericDialect, parser::Parser};
@@ -559,6 +559,7 @@ pub struct SingleRowListArrayBuilder {
559559
/// Specify the field name for the resulting array. Defaults to value used in
560560
/// [`Field::new_list_field`]
561561
field_name: Option<String>,
562+
field_metadata: Metadata,
562563
}
563564

564565
impl SingleRowListArrayBuilder {
@@ -568,6 +569,7 @@ impl SingleRowListArrayBuilder {
568569
arr,
569570
nullable: true,
570571
field_name: None,
572+
field_metadata: Metadata::default(),
571573
}
572574
}
573575

@@ -583,10 +585,12 @@ impl SingleRowListArrayBuilder {
583585
self
584586
}
585587

586-
/// Copies field name and nullable from the specified field
587-
pub fn with_field(self, field: &Field) -> Self {
588-
self.with_field_name(Some(field.name().to_owned()))
589-
.with_nullable(field.is_nullable())
588+
/// Copies field name, nullability, and metadata from the specified field
589+
pub fn with_field(mut self, field: &Field) -> Self {
590+
self.field_name = Some(field.name().to_owned());
591+
self.nullable = field.is_nullable();
592+
self.field_metadata = field.metadata().clone();
593+
self
590594
}
591595

592596
/// Build a single element [`ListArray`]
@@ -659,13 +663,14 @@ impl SingleRowListArrayBuilder {
659663
arr,
660664
nullable,
661665
field_name,
666+
field_metadata,
662667
} = self;
663668
let data_type = arr.data_type().to_owned();
664669
let field = match field_name {
665670
Some(name) => Field::new(name, data_type, nullable),
666671
None => Field::new_list_field(data_type, nullable),
667672
};
668-
(Arc::new(field), arr)
673+
(Arc::new(field.with_metadata(field_metadata)), arr)
669674
}
670675
}
671676

@@ -1606,6 +1611,7 @@ pub fn apply_parent_nulls(
16061611

16071612
#[cfg(test)]
16081613
mod tests {
1614+
use std::collections::HashMap;
16091615
use std::sync::Arc;
16101616

16111617
use super::*;
@@ -1617,6 +1623,20 @@ mod tests {
16171623
#[cfg(feature = "sql")]
16181624
use sqlparser::ast::Ident;
16191625

1626+
#[test]
1627+
fn test_list_scalar_cast_preserves_target_element_metadata() -> Result<()> {
1628+
let input =
1629+
ListArray::from_iter_primitive::<Int32Type, _, _>(vec![Some(vec![Some(1)])]);
1630+
let item = Field::new("item", DataType::Int32, true)
1631+
.with_metadata(HashMap::from([("PARQUET:field_id".into(), "2".into())]));
1632+
let target = DataType::List(Arc::new(item));
1633+
1634+
let casted = ScalarValue::List(Arc::new(input)).cast_to(&target)?;
1635+
assert_eq!(casted.data_type(), target);
1636+
assert_eq!(casted.to_array_of_size(2)?.data_type(), &target);
1637+
Ok(())
1638+
}
1639+
16201640
#[test]
16211641
fn test_apply_parent_nulls_sliced() -> Result<()> {
16221642
let child = Arc::new(

0 commit comments

Comments
 (0)