This is an automated email from the ASF dual-hosted git repository.
mbrobbel pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git
The following commit(s) were added to refs/heads/main by this push:
new 4545c1ea2e feat: Ensure consistent metadata display for data types
(#8760)
4545c1ea2e is described below
commit 4545c1ea2e5f4853617899d21968c2a8aae3706a
Author: Martin Hilton <[email protected]>
AuthorDate: Mon Nov 3 09:58:39 2025 +0000
feat: Ensure consistent metadata display for data types (#8760)
Where a datatype has associated metadata format that metadata
consistently in lexical order by key.
# Which issue does this PR close?
- closes https://github.com/apache/arrow-rs/issues/8761
- helps with #8351.
# Rationale for this change
# What changes are included in this PR?
A consistent formatter for the metadata hash tables embedded in
DataType.
# Are these changes tested?
Yes, I have enhanced an existing test that would have shown the issue.
# Are there any user-facing changes?
No
---------
Co-authored-by: Andrew Lamb <[email protected]>
---
arrow-schema/src/datatype_display.rs | 31 +++++++++++++++++++++++--------
1 file changed, 23 insertions(+), 8 deletions(-)
diff --git a/arrow-schema/src/datatype_display.rs
b/arrow-schema/src/datatype_display.rs
index 2d54e76dd8..6c89e3cdae 100644
--- a/arrow-schema/src/datatype_display.rs
+++ b/arrow-schema/src/datatype_display.rs
@@ -22,11 +22,7 @@ use crate::DataType;
impl fmt::Display for DataType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn format_metadata(metadata: &HashMap<String, String>) -> String {
- if metadata.is_empty() {
- String::new()
- } else {
- format!(", metadata: {metadata:?}")
- }
+ format!("{}", FormatMetadata(metadata))
}
fn format_field(field: &crate::Field) -> String {
@@ -182,6 +178,23 @@ impl fmt::Display for DataType {
}
}
+/// Adapter to format a metadata HashMap consistently.
+struct FormatMetadata<'a>(&'a HashMap<String, String>);
+
+impl fmt::Display for FormatMetadata<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let metadata = self.0;
+ if metadata.is_empty() {
+ Ok(())
+ } else {
+ let mut entries: Vec<(&String, &String)> =
metadata.iter().collect();
+ entries.sort_by(|a, b| a.0.cmp(b.0));
+ write!(f, ", metadata: ")?;
+ f.debug_map().entries(entries).finish()
+ }
+ }
+}
+
#[cfg(test)]
mod tests {
@@ -361,14 +374,16 @@ mod tests {
// Test with metadata
let mut field_with_metadata = Field::new("b", DataType::Utf8, true);
- let metadata = HashMap::from([("key".to_string(),
"value".to_string())]);
+ let metadata = HashMap::from([
+ ("key".to_string(), "value".to_string()),
+ ("key2".to_string(), "value2".to_string()),
+ ]);
field_with_metadata.set_metadata(metadata);
let struct_fields_with_metadata =
vec![Field::new("a", DataType::Int32, false), field_with_metadata];
let struct_data_type_with_metadata =
DataType::Struct(struct_fields_with_metadata.into());
let struct_data_type_with_metadata_string =
struct_data_type_with_metadata.to_string();
- let expected_string_with_metadata =
- "Struct(\"a\": Int32, \"b\": nullable Utf8, metadata: {\"key\":
\"value\"})";
+ let expected_string_with_metadata = "Struct(\"a\": Int32, \"b\":
nullable Utf8, metadata: {\"key\": \"value\", \"key2\": \"value2\"})";
assert_eq!(
struct_data_type_with_metadata_string,
expected_string_with_metadata