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

mgrigorov pushed a commit to branch branch-1.11
in repository https://gitbox.apache.org/repos/asf/avro.git

commit 34ba17f1c486f1fd7e801e6a204ad62b78d80ee3
Author: Martin Grigorov <[email protected]>
AuthorDate: Fri Jan 21 08:37:30 2022 +0200

    AVRO-3315: Rust: Add support to back/cycle reference an alias (#1466)
    
    Signed-off-by: Martin Tzvetanov Grigorov <[email protected]>
    (cherry picked from commit a35a2a5305560da8ccb8eb299498e73c8bafa3bd)
---
 lang/rust/src/schema.rs | 125 ++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 115 insertions(+), 10 deletions(-)

diff --git a/lang/rust/src/schema.rs b/lang/rust/src/schema.rs
index a60e047..ab5fd04 100644
--- a/lang/rust/src/schema.rs
+++ b/lang/rust/src/schema.rs
@@ -799,6 +799,45 @@ impl Parser {
         }
     }
 
+    fn register_resolving_schema(&mut self, name: &Name) {
+        let resolving_schema = Schema::Ref { name: name.clone() };
+        self.resolving_schemas
+            .insert(name.fullname(None), resolving_schema.clone());
+
+        let namespace = &name.namespace;
+
+        if let Some(ref aliases) = name.aliases {
+            aliases.iter().for_each(|alias| {
+                let alias_fullname = match namespace {
+                    Some(ref ns) => format!("{}.{}", ns, alias),
+                    None => alias.clone(),
+                };
+                self.resolving_schemas
+                    .insert(alias_fullname, resolving_schema.clone());
+            });
+        }
+    }
+
+    fn register_parsed_schema(&mut self, name: &Name, schema: &Schema) {
+        self.parsed_schemas
+            .insert(name.fullname(None), schema.clone());
+        self.resolving_schemas.remove(name.fullname(None).as_str());
+
+        let namespace = &name.namespace;
+
+        if let Some(ref aliases) = name.aliases {
+            aliases.iter().for_each(|alias| {
+                let alias_fullname = match namespace {
+                    Some(ref ns) => format!("{}.{}", ns, alias),
+                    None => alias.clone(),
+                };
+                self.parsed_schemas
+                    .insert(alias_fullname.clone(), schema.clone());
+                self.resolving_schemas.remove(alias_fullname.as_str());
+            });
+        }
+    }
+
     /// Parse a `serde_json::Value` representing a Avro record type into a
     /// `Schema`.
     fn parse_record(&mut self, complex: &Map<String, Value>) -> 
AvroResult<Schema> {
@@ -806,9 +845,7 @@ impl Parser {
 
         let mut lookup = HashMap::new();
 
-        let resolving_schema = Schema::Ref { name: name.clone() };
-        self.resolving_schemas
-            .insert(name.name.clone(), resolving_schema);
+        self.register_resolving_schema(&name);
 
         let fields: Vec<RecordField> = complex
             .get("fields")
@@ -834,9 +871,7 @@ impl Parser {
             lookup,
         };
 
-        self.parsed_schemas
-            .insert(name.fullname(None), schema.clone());
-        self.resolving_schemas.remove(name.name.as_str());
+        self.register_parsed_schema(&name, &schema);
         Ok(schema)
     }
 
@@ -877,8 +912,9 @@ impl Parser {
             doc: complex.doc(),
             symbols,
         };
-        self.parsed_schemas
-            .insert(name.fullname(None), schema.clone());
+
+        self.register_parsed_schema(&name, &schema);
+
         Ok(schema)
     }
 
@@ -932,8 +968,9 @@ impl Parser {
             doc,
             size: size as usize,
         };
-        self.parsed_schemas
-            .insert(name.fullname(None), schema.clone());
+
+        self.register_parsed_schema(&name, &schema);
+
         Ok(schema)
     }
 }
@@ -1620,6 +1657,74 @@ mod tests {
         assert_eq!(schema_str, expected);
     }
 
+    // AVRO-3302
+    #[test]
+    fn test_record_schema_with_currently_parsing_schema_aliases() {
+        let schema = Schema::parse_str(
+            r#"
+            {
+              "type": "record",
+              "name": "LongList",
+              "aliases": ["LinkedLongs"],
+              "fields" : [
+                {"name": "value", "type": "long"},
+                {"name": "next", "type": ["null", "LinkedLongs"]}
+              ]
+            }
+        "#,
+        )
+        .unwrap();
+
+        let mut lookup = HashMap::new();
+        lookup.insert("value".to_owned(), 0);
+        lookup.insert("next".to_owned(), 1);
+
+        let expected = Schema::Record {
+            name: Name {
+                name: "LongList".to_owned(),
+                namespace: None,
+                aliases: Some(vec!["LinkedLongs".to_owned()]),
+            },
+            doc: None,
+            fields: vec![
+                RecordField {
+                    name: "value".to_string(),
+                    doc: None,
+                    default: None,
+                    schema: Schema::Long,
+                    order: RecordFieldOrder::Ascending,
+                    position: 0,
+                },
+                RecordField {
+                    name: "next".to_string(),
+                    doc: None,
+                    default: None,
+                    schema: Schema::Union(
+                        UnionSchema::new(vec![
+                            Schema::Null,
+                            Schema::Ref {
+                                name: Name {
+                                    name: "LongList".to_owned(),
+                                    namespace: None,
+                                    aliases: 
Some(vec!["LinkedLongs".to_owned()]),
+                                },
+                            },
+                        ])
+                        .unwrap(),
+                    ),
+                    order: RecordFieldOrder::Ascending,
+                    position: 1,
+                },
+            ],
+            lookup,
+        };
+        assert_eq!(schema, expected);
+
+        let canonical_form = &schema.canonical_form();
+        let expected = 
r#"{"name":"LongList","type":"record","fields":[{"name":"value","type":"long"},{"name":"next","type":["null","LongList"]}]}"#;
+        assert_eq!(canonical_form, &expected);
+    }
+
     #[test]
     fn test_enum_schema() {
         let schema = Schema::parse_str(

Reply via email to