You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by mg...@apache.org on 2022/04/18 05:37:21 UTC

[avro] branch master updated: AVRO-3492: Add support for deriving Schema::Record aliases (#1647)

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 fbe790109 AVRO-3492: Add support for deriving Schema::Record aliases (#1647)
fbe790109 is described below

commit fbe7901093c5af959c9f0ddb3c8e447f62f86181
Author: Martin Grigorov <ma...@users.noreply.github.com>
AuthorDate: Mon Apr 18 08:37:16 2022 +0300

    AVRO-3492: Add support for deriving Schema::Record aliases (#1647)
    
    * AVRO-3492: Add support for deriving Schema::Record aliases
    
    Uses Darling's 'multiple' attribute feature.
    
    Signed-off-by: Martin Tzvetanov Grigorov <mg...@apache.org>
    
    * AVRO-3492: Add a test case with multiple attributes with different values for 'alias' key
    
    Signed-off-by: Martin Tzvetanov Grigorov <mg...@apache.org>
---
 lang/rust/avro_derive/src/lib.rs      | 16 +++++++-
 lang/rust/avro_derive/tests/derive.rs | 74 +++++++++++++++++++++++++++++++++++
 2 files changed, 89 insertions(+), 1 deletion(-)

diff --git a/lang/rust/avro_derive/src/lib.rs b/lang/rust/avro_derive/src/lib.rs
index 96575e090..11ab7a616 100644
--- a/lang/rust/avro_derive/src/lib.rs
+++ b/lang/rust/avro_derive/src/lib.rs
@@ -39,6 +39,8 @@ struct NamedTypeOptions {
     namespace: Option<String>,
     #[darling(default)]
     doc: Option<String>,
+    #[darling(multiple)]
+    alias: Vec<String>,
 }
 
 #[proc_macro_derive(AvroSchema, attributes(avro))]
@@ -64,6 +66,7 @@ fn derive_avro_schema(input: &mut DeriveInput) -> Result<TokenStream, Vec<syn::E
             named_type_options
                 .doc
                 .or_else(|| extract_outer_doc(&input.attrs)),
+            named_type_options.alias,
             s,
             input.ident.span(),
         )?,
@@ -104,6 +107,7 @@ fn derive_avro_schema(input: &mut DeriveInput) -> Result<TokenStream, Vec<syn::E
 fn get_data_struct_schema_def(
     full_schema_name: &str,
     record_doc: Option<String>,
+    aliases: Vec<String>,
     s: &syn::DataStruct,
     error_span: Span,
 ) -> Result<TokenStream, Vec<syn::Error>> {
@@ -143,6 +147,7 @@ fn get_data_struct_schema_def(
         }
     }
     let record_doc = preserve_optional(record_doc);
+    let record_aliases = preserve_vec(aliases);
     Ok(quote! {
         let schema_fields = vec![#(#record_field_exprs),*];
         let name = apache_avro::schema::Name::new(#full_schema_name).expect(&format!("Unable to parse struct name for schema {}", #full_schema_name)[..]);
@@ -152,7 +157,7 @@ fn get_data_struct_schema_def(
             .collect();
         apache_avro::schema::Schema::Record {
             name,
-            aliases: None,
+            aliases: #record_aliases,
             doc: #record_doc,
             fields: schema_fields,
             lookup,
@@ -277,6 +282,15 @@ fn preserve_optional(op: Option<impl quote::ToTokens>) -> TokenStream {
     }
 }
 
+fn preserve_vec(op: Vec<impl quote::ToTokens>) -> TokenStream {
+    let items: Vec<TokenStream> = op.iter().map(|tt| quote! {#tt.into()}).collect();
+    if items.is_empty() {
+        quote! {None}
+    } else {
+        quote! {Some(vec![#(#items),*])}
+    }
+}
+
 fn darling_to_syn(e: darling::Error) -> Vec<syn::Error> {
     let msg = format!("{}", e);
     let token_errors = e.write_errors();
diff --git a/lang/rust/avro_derive/tests/derive.rs b/lang/rust/avro_derive/tests/derive.rs
index 8ac95755f..c058c44c1 100644
--- a/lang/rust/avro_derive/tests/derive.rs
+++ b/lang/rust/avro_derive/tests/derive.rs
@@ -1063,4 +1063,78 @@ mod test_derive {
         serde_assert(TestBasicWithU32 { a: u32::MIN });
         serde_assert(TestBasicWithU32 { a: 1_u32 });
     }
+
+    #[derive(Debug, Serialize, Deserialize, AvroSchema, Clone, PartialEq)]
+    #[avro(alias = "a", alias = "b", alias = "c")]
+    struct TestBasicWithAliases {
+        a: i32,
+    }
+
+    #[test]
+    fn test_basic_with_aliases() {
+        let schema = r#"
+        {
+            "type":"record",
+            "name":"TestBasicWithAliases",
+            "aliases":["a", "b", "c"],
+            "fields":[
+                {
+                    "name":"a",
+                    "type":"int"
+                }
+            ]
+        }
+        "#;
+        let schema = Schema::parse_str(schema).unwrap();
+        if let Schema::Record { name, aliases, .. } = TestBasicWithAliases::get_schema() {
+            assert_eq!("TestBasicWithAliases", name.fullname(None));
+            assert_eq!(
+                Some(vec!["a".to_owned(), "b".to_owned(), "c".to_owned()]),
+                aliases
+            );
+        } else {
+            panic!("TestBasicWithAliases schema must be a record schema")
+        }
+        assert_eq!(schema, TestBasicWithAliases::get_schema());
+
+        serde_assert(TestBasicWithAliases { a: i32::MAX });
+    }
+
+    #[derive(Debug, Serialize, Deserialize, AvroSchema, Clone, PartialEq)]
+    #[avro(alias = "d")]
+    #[avro(alias = "e")]
+    #[avro(alias = "f")]
+    struct TestBasicWithAliases2 {
+        a: i32,
+    }
+
+    #[test]
+    fn test_basic_with_aliases2() {
+        let schema = r#"
+        {
+            "type":"record",
+            "name":"TestBasicWithAliases2",
+            "aliases":["d", "e", "f"],
+            "fields":[
+                {
+                    "name":"a",
+                    "type":"int"
+                }
+            ]
+        }
+        "#;
+        let schema = Schema::parse_str(schema).unwrap();
+        if let Schema::Record { name, aliases, .. } = TestBasicWithAliases2::get_schema() {
+            assert_eq!("TestBasicWithAliases2", name.fullname(None));
+            assert_eq!(
+                Some(vec!["d".to_owned(), "e".to_owned(), "f".to_owned()]),
+                aliases
+            );
+        } else {
+            panic!("TestBasicWithAliases2 schema must be a record schema")
+        }
+        assert_eq!(schema, TestBasicWithAliases2::get_schema());
+
+        serde_assert(TestBasicWithAliases2 { a: i32::MAX });
+    }
 }