This is an automated email from the ASF dual-hosted git repository.
mgrigorov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/avro-rs.git
The following commit(s) were added to refs/heads/main by this push:
new 18ee808 fix: Do not store "items" for Schema::Array and "values" for
Schema::Map in custom_attributes (#306)
18ee808 is described below
commit 18ee808d184e096e003304a020929ea39d7a90f4
Author: Martin Grigorov <[email protected]>
AuthorDate: Tue Sep 30 16:23:43 2025 +0300
fix: Do not store "items" for Schema::Array and "values" for Schema::Map in
custom_attributes (#306)
Fixes: #292
---
avro/src/schema.rs | 144 +++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 141 insertions(+), 3 deletions(-)
diff --git a/avro/src/schema.rs b/avro/src/schema.rs
index 833ca30..874fe79 100644
--- a/avro/src/schema.rs
+++ b/avro/src/schema.rs
@@ -778,6 +778,8 @@ impl RecordField {
| "logicalType" => continue,
key if key == "symbols" && matches!(schema, Schema::Enum(_))
=> continue,
key if key == "size" && matches!(schema, Schema::Fixed(_)) =>
continue,
+ key if key == "items" && matches!(schema, Schema::Array(_)) =>
continue,
+ key if key == "values" && matches!(schema, Schema::Map(_)) =>
continue,
_ => custom_attributes.insert(key.clone(), value.clone()),
};
}
@@ -2315,11 +2317,10 @@ fn parsing_canonical_form(schema: &Value,
defined_names: &mut HashSet<String>) -
}
fn pcf_map(schema: &Map<String, Value>, defined_names: &mut HashSet<String>)
-> String {
- // Look for the namespace variant up front.
- let ns = schema.get("namespace").and_then(|v| v.as_str());
let typ = schema.get("type").and_then(|v| v.as_str());
- let raw_name = schema.get("name").and_then(|v| v.as_str());
let name = if is_named_type(typ) {
+ let ns = schema.get("namespace").and_then(|v| v.as_str());
+ let raw_name = schema.get("name").and_then(|v| v.as_str());
Some(format!(
"{}{}",
ns.map_or("".to_string(), |n| { format!("{n}.") }),
@@ -7227,4 +7228,141 @@ mod tests {
Ok(())
}
+
+ #[test]
+ fn avro_rs_292_array_items_should_be_ignored_in_custom_attributes() ->
TestResult {
+ let raw_schema = r#"{
+ "type": "array",
+ "items": {
+ "name": "foo",
+ "type": "record",
+ "fields": [
+ {
+ "name": "bar",
+ "type": "array",
+ "items": {
+ "type": "record",
+ "name": "baz",
+ "fields": [
+ {
+ "name": "quux",
+ "type": "int"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }"#;
+
+ let schema1 = Schema::parse_str(raw_schema)?;
+ match &schema1 {
+ Schema::Array(ArraySchema { items, attributes }) => {
+ assert!(attributes.is_empty());
+
+ match **items {
+ Schema::Record(RecordSchema {
+ ref name,
+ aliases: _,
+ doc: _,
+ ref fields,
+ lookup: _,
+ ref attributes,
+ }) => {
+ assert_eq!(name.to_string(), "foo");
+ assert_eq!(fields.len(), 1);
+ assert!(attributes.is_empty());
+
+ match &fields[0].schema {
+ Schema::Array(ArraySchema {
+ items: _,
+ attributes,
+ }) => {
+ assert!(attributes.is_empty());
+ }
+ _ => panic!("Expected ArraySchema. got: {}",
&fields[0].schema),
+ }
+ }
+ _ => panic!("Expected RecordSchema. got: {}", &items),
+ }
+ }
+ _ => panic!("Expected ArraySchema. got: {}", &schema1),
+ }
+ let canonical_form1 = schema1.canonical_form();
+ let schema2 = Schema::parse_str(&canonical_form1)?;
+ let canonical_form2 = schema2.canonical_form();
+
+ assert_eq!(canonical_form1, canonical_form2);
+
+ Ok(())
+ }
+
+ #[test]
+ fn avro_rs_292_map_values_should_be_ignored_in_custom_attributes() ->
TestResult {
+ let raw_schema = r#"{
+ "type": "array",
+ "items": {
+ "name": "foo",
+ "type": "record",
+ "fields": [
+ {
+ "name": "bar",
+ "type": "map",
+ "values": {
+ "type": "record",
+ "name": "baz",
+ "fields": [
+ {
+ "name": "quux",
+ "type": "int"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }"#;
+
+ let schema1 = Schema::parse_str(raw_schema)?;
+ match &schema1 {
+ Schema::Array(ArraySchema { items, attributes }) => {
+ assert!(attributes.is_empty());
+
+ match **items {
+ Schema::Record(RecordSchema {
+ ref name,
+ aliases: _,
+ doc: _,
+ ref fields,
+ lookup: _,
+ ref attributes,
+ }) => {
+ assert_eq!(name.to_string(), "foo");
+ assert_eq!(fields.len(), 1);
+ assert!(attributes.is_empty());
+
+ match &fields[0].schema {
+ Schema::Map(MapSchema {
+ types: _,
+ attributes,
+ }) => {
+ assert!(attributes.is_empty());
+ }
+ _ => panic!("Expected MapSchema. got: {}",
&fields[0].schema),
+ }
+ }
+ _ => panic!("Expected RecordSchema. got: {}", &items),
+ }
+ }
+ _ => panic!("Expected ArraySchema. got: {}", &schema1),
+ }
+ let canonical_form1 = schema1.canonical_form();
+ println!("Canonical Form 1: {}", &canonical_form1);
+ let schema2 = Schema::parse_str(&canonical_form1)?;
+ let canonical_form2 = schema2.canonical_form();
+
+ assert_eq!(canonical_form1, canonical_form2);
+
+ Ok(())
+ }
}