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 });
+ }
}