This is an automated email from the ASF dual-hosted git repository.
mgrigorov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/avro.git
The following commit(s) were added to refs/heads/master by this push:
new a35a2a5 AVRO-3315: Rust: Add support to back/cycle reference an alias
(#1466)
a35a2a5 is described below
commit a35a2a5305560da8ccb8eb299498e73c8bafa3bd
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]>
---
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(