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

mgrigorov pushed a commit to branch avro-3709-add-aliases-to-record-fields
in repository https://gitbox.apache.org/repos/asf/avro.git

commit d8654cfae86e23daf680c24bb8de71e76f656cbe
Author: Martin Tzvetanov Grigorov <[email protected]>
AuthorDate: Tue Feb 7 11:58:32 2023 +0200

    AVRO-3709: [Rust] Add 'aliases' field to RecordField
    
    Signed-off-by: Martin Tzvetanov Grigorov <[email protected]>
---
 lang/rust/avro/src/schema.rs     | 38 ++++++++++++++++++++++++++++++++++++++
 lang/rust/avro/src/types.rs      | 19 ++++++++++++-------
 lang/rust/avro/tests/schema.rs   |  1 +
 lang/rust/avro_derive/src/lib.rs |  4 ++++
 4 files changed, 55 insertions(+), 7 deletions(-)

diff --git a/lang/rust/avro/src/schema.rs b/lang/rust/avro/src/schema.rs
index 51a87cd6d..44e22efc7 100644
--- a/lang/rust/avro/src/schema.rs
+++ b/lang/rust/avro/src/schema.rs
@@ -563,6 +563,9 @@ pub struct RecordField {
     pub name: String,
     /// Documentation of the field.
     pub doc: Documentation,
+
+    /// Aliases of the field.
+    pub aliases: Aliases,
     /// Default value of the field.
     /// This value will be used when reading Avro datum if schema resolution
     /// is enabled.
@@ -603,6 +606,16 @@ impl RecordField {
 
         let default = field.get("default").cloned();
 
+        let aliases = field.get("aliases").and_then(|aliases| {
+            aliases.as_array().map(|aliases| {
+                aliases
+                    .iter()
+                    .flat_map(|alias| alias.as_str())
+                    .map(|alias| Alias::new(alias).expect("Alias is not 
valid"))
+                    .collect::<Vec<Alias>>()
+            })
+        });
+
         let order = field
             .get("order")
             .and_then(|order| order.as_str())
@@ -613,6 +626,7 @@ impl RecordField {
             name,
             doc: field.doc(),
             default,
+            aliases,
             schema,
             order,
             position,
@@ -1268,6 +1282,13 @@ impl Parser {
 
         for field in &fields {
             lookup.insert(field.name.clone(), field.position);
+
+            if let Some(ref field_aliases) = field.aliases {
+                for alias in field_aliases {
+                    let alias = alias.fullname(enclosing_namespace.clone());
+                    lookup.insert(alias, field.position);
+                }
+            }
         }
 
         let schema = Schema::Record {
@@ -2067,6 +2088,7 @@ mod tests {
             name: "next".to_string(),
             doc: None,
             default: None,
+            aliases: None,
             schema: Schema::Union(
                 UnionSchema::new(vec![
                     Schema::Null,
@@ -2090,6 +2112,7 @@ mod tests {
             name: "next".to_string(),
             doc: None,
             default: Some(json!(2)),
+            aliases: None,
             schema: Schema::Long,
             order: RecordFieldOrder::Ascending,
             position: 1,
@@ -2144,6 +2167,7 @@ mod tests {
                 name: "field_one".to_string(),
                 doc: None,
                 default: None,
+                aliases: None,
                 schema: Schema::Union(
                     UnionSchema::new(vec![
                         Schema::Ref {
@@ -2235,6 +2259,7 @@ mod tests {
                 name: "field_one".to_string(),
                 doc: None,
                 default: Some(Value::Null),
+                aliases: None,
                 schema: Schema::Union(
                     UnionSchema::new(vec![
                         Schema::Null,
@@ -2284,6 +2309,7 @@ mod tests {
                     name: "a".to_string(),
                     doc: None,
                     default: Some(Value::Number(42i64.into())),
+                    aliases: None,
                     schema: Schema::Long,
                     order: RecordFieldOrder::Ascending,
                     position: 0,
@@ -2293,6 +2319,7 @@ mod tests {
                     name: "b".to_string(),
                     doc: None,
                     default: None,
+                    aliases: None,
                     schema: Schema::String,
                     order: RecordFieldOrder::Ascending,
                     position: 1,
@@ -2345,6 +2372,7 @@ mod tests {
                 name: "recordField".to_string(),
                 doc: None,
                 default: None,
+                aliases: None,
                 schema: Schema::Record {
                     name: Name::new("Node").unwrap(),
                     aliases: None,
@@ -2354,6 +2382,7 @@ mod tests {
                             name: "label".to_string(),
                             doc: None,
                             default: None,
+                            aliases: None,
                             schema: Schema::String,
                             order: RecordFieldOrder::Ascending,
                             position: 0,
@@ -2363,6 +2392,7 @@ mod tests {
                             name: "children".to_string(),
                             doc: None,
                             default: None,
+                            aliases: None,
                             schema: Schema::Array(Box::new(Schema::Ref {
                                 name: Name::new("Node").unwrap(),
                             })),
@@ -2522,6 +2552,7 @@ mod tests {
                     name: "value".to_string(),
                     doc: None,
                     default: None,
+                    aliases: None,
                     schema: Schema::Long,
                     order: RecordFieldOrder::Ascending,
                     position: 0,
@@ -2531,6 +2562,7 @@ mod tests {
                     name: "next".to_string(),
                     doc: None,
                     default: None,
+                    aliases: None,
                     schema: Schema::Union(
                         UnionSchema::new(vec![
                             Schema::Null,
@@ -2591,6 +2623,7 @@ mod tests {
                     name: "value".to_string(),
                     doc: None,
                     default: None,
+                    aliases: None,
                     schema: Schema::Long,
                     order: RecordFieldOrder::Ascending,
                     position: 0,
@@ -2600,6 +2633,7 @@ mod tests {
                     name: "next".to_string(),
                     doc: None,
                     default: None,
+                    aliases: None,
                     schema: Schema::Ref {
                         name: Name {
                             name: "record".to_owned(),
@@ -2658,6 +2692,7 @@ mod tests {
                     name: "enum".to_string(),
                     doc: None,
                     default: None,
+                    aliases: None,
                     schema: Schema::Enum {
                         name: Name {
                             name: "enum".to_owned(),
@@ -2676,6 +2711,7 @@ mod tests {
                     name: "next".to_string(),
                     doc: None,
                     default: None,
+                    aliases: None,
                     schema: Schema::Enum {
                         name: Name {
                             name: "enum".to_owned(),
@@ -2738,6 +2774,7 @@ mod tests {
                     name: "fixed".to_string(),
                     doc: None,
                     default: None,
+                    aliases: None,
                     schema: Schema::Fixed {
                         name: Name {
                             name: "fixed".to_owned(),
@@ -2756,6 +2793,7 @@ mod tests {
                     name: "next".to_string(),
                     doc: None,
                     default: None,
+                    aliases: None,
                     schema: Schema::Fixed {
                         name: Name {
                             name: "fixed".to_owned(),
diff --git a/lang/rust/avro/src/types.rs b/lang/rust/avro/src/types.rs
index 9f3f3d253..60f94ecf8 100644
--- a/lang/rust/avro/src/types.rs
+++ b/lang/rust/avro/src/types.rs
@@ -1107,6 +1107,7 @@ mod tests {
                         name: "field_name".to_string(),
                         doc: None,
                         default: None,
+                        aliases: None,
                         schema: Schema::Int,
                         order: RecordFieldOrder::Ignore,
                         position: 0,
@@ -1116,7 +1117,7 @@ mod tests {
                     attributes: Default::default(),
                 },
                 false,
-                r#"Invalid value: Record([("unknown_field_name", Null)]) for 
schema: Record { name: Name { name: "record_name", namespace: None }, aliases: 
None, doc: None, fields: [RecordField { name: "field_name", doc: None, default: 
None, schema: Int, order: Ignore, position: 0, custom_attributes: {} }], 
lookup: {}, attributes: {} }. Reason: There is no schema field for field 
'unknown_field_name'"#,
+                r#"Invalid value: Record([("unknown_field_name", Null)]) for 
schema: Record { name: Name { name: "record_name", namespace: None }, aliases: 
None, doc: None, fields: [RecordField { name: "field_name", doc: None, aliases: 
None, default: None, schema: Int, order: Ignore, position: 0, 
custom_attributes: {} }], lookup: {}, attributes: {} }. Reason: There is no 
schema field for field 'unknown_field_name'"#,
             ),
             (
                 Value::Record(vec![("field_name".to_string(), Value::Null)]),
@@ -1128,6 +1129,7 @@ mod tests {
                         name: "field_name".to_string(),
                         doc: None,
                         default: None,
+                        aliases: None,
                         schema: Schema::Ref {
                             name: Name::new("missing").unwrap(),
                         },
@@ -1139,7 +1141,7 @@ mod tests {
                     attributes: Default::default(),
                 },
                 false,
-                r#"Invalid value: Record([("field_name", Null)]) for schema: 
Record { name: Name { name: "record_name", namespace: None }, aliases: None, 
doc: None, fields: [RecordField { name: "field_name", doc: None, default: None, 
schema: Ref { name: Name { name: "missing", namespace: None } }, order: Ignore, 
position: 0, custom_attributes: {} }], lookup: {"field_name": 0}, attributes: 
{} }. Reason: Unresolved schema reference: 'Name { name: "missing", namespace: 
None }'. Parsed names: []"#,
+                r#"Invalid value: Record([("field_name", Null)]) for schema: 
Record { name: Name { name: "record_name", namespace: None }, aliases: None, 
doc: None, fields: [RecordField { name: "field_name", doc: None, aliases: None, 
default: None, schema: Ref { name: Name { name: "missing", namespace: None } }, 
order: Ignore, position: 0, custom_attributes: {} }], lookup: {"field_name": 
0}, attributes: {} }. Reason: Unresolved schema reference: 'Name { name: 
"missing", namespace: None } [...]
             ),
         ];
 
@@ -1287,6 +1289,7 @@ mod tests {
                     name: "a".to_string(),
                     doc: None,
                     default: None,
+                    aliases: None,
                     schema: Schema::Long,
                     order: RecordFieldOrder::Ascending,
                     position: 0,
@@ -1296,6 +1299,7 @@ mod tests {
                     name: "b".to_string(),
                     doc: None,
                     default: None,
+                    aliases: None,
                     schema: Schema::String,
                     order: RecordFieldOrder::Ascending,
                     position: 1,
@@ -1305,6 +1309,7 @@ mod tests {
                     name: "c".to_string(),
                     doc: None,
                     default: Some(JsonValue::Null),
+                    aliases: None,
                     schema: Schema::Union(
                         UnionSchema::new(vec![Schema::Null, 
Schema::Int]).unwrap(),
                     ),
@@ -1342,7 +1347,7 @@ mod tests {
         ]);
         assert!(!value.validate(&schema));
         assert_logged(
-            r#"Invalid value: Record([("a", Boolean(false)), ("b", 
String("foo"))]) for schema: Record { name: Name { name: "some_record", 
namespace: None }, aliases: None, doc: None, fields: [RecordField { name: "a", 
doc: None, default: None, schema: Long, order: Ascending, position: 0, 
custom_attributes: {} }, RecordField { name: "b", doc: None, default: None, 
schema: String, order: Ascending, position: 1, custom_attributes: {} }, 
RecordField { name: "c", doc: None, default: Some(Null) [...]
+            r#"Invalid value: Record([("a", Boolean(false)), ("b", 
String("foo"))]) for schema: Record { name: Name { name: "some_record", 
namespace: None }, aliases: None, doc: None, fields: [RecordField { name: "a", 
doc: None, aliases: None, default: None, schema: Long, order: Ascending, 
position: 0, custom_attributes: {} }, RecordField { name: "b", doc: None, 
aliases: None, default: None, schema: String, order: Ascending, position: 1, 
custom_attributes: {} }, RecordField { name: "c",  [...]
         );
 
         let value = Value::Record(vec![
@@ -1351,7 +1356,7 @@ mod tests {
         ]);
         assert!(!value.validate(&schema));
         assert_logged(
-            r#"Invalid value: Record([("a", Long(42)), ("c", String("foo"))]) 
for schema: Record { name: Name { name: "some_record", namespace: None }, 
aliases: None, doc: None, fields: [RecordField { name: "a", doc: None, default: 
None, schema: Long, order: Ascending, position: 0, custom_attributes: {} }, 
RecordField { name: "b", doc: None, default: None, schema: String, order: 
Ascending, position: 1, custom_attributes: {} }, RecordField { name: "c", doc: 
None, default: Some(Null), sche [...]
+            r#"Invalid value: Record([("a", Long(42)), ("c", String("foo"))]) 
for schema: Record { name: Name { name: "some_record", namespace: None }, 
aliases: None, doc: None, fields: [RecordField { name: "a", doc: None, aliases: 
None, default: None, schema: Long, order: Ascending, position: 0, 
custom_attributes: {} }, RecordField { name: "b", doc: None, aliases: None, 
default: None, schema: String, order: Ascending, position: 1, 
custom_attributes: {} }, RecordField { name: "c", doc: N [...]
         );
         assert_not_logged(
             r#"Invalid value: String("foo") for schema: Int. Reason: 
Unsupported value-schema combination"#,
@@ -1363,7 +1368,7 @@ mod tests {
         ]);
         assert!(!value.validate(&schema));
         assert_logged(
-            r#"Invalid value: Record([("a", Long(42)), ("d", String("foo"))]) 
for schema: Record { name: Name { name: "some_record", namespace: None }, 
aliases: None, doc: None, fields: [RecordField { name: "a", doc: None, default: 
None, schema: Long, order: Ascending, position: 0, custom_attributes: {} }, 
RecordField { name: "b", doc: None, default: None, schema: String, order: 
Ascending, position: 1, custom_attributes: {} }, RecordField { name: "c", doc: 
None, default: Some(Null), sche [...]
+            r#"Invalid value: Record([("a", Long(42)), ("d", String("foo"))]) 
for schema: Record { name: Name { name: "some_record", namespace: None }, 
aliases: None, doc: None, fields: [RecordField { name: "a", doc: None, aliases: 
None, default: None, schema: Long, order: Ascending, position: 0, 
custom_attributes: {} }, RecordField { name: "b", doc: None, aliases: None, 
default: None, schema: String, order: Ascending, position: 1, 
custom_attributes: {} }, RecordField { name: "c", doc: N [...]
         );
 
         let value = Value::Record(vec![
@@ -1374,7 +1379,7 @@ mod tests {
         ]);
         assert!(!value.validate(&schema));
         assert_logged(
-            r#"Invalid value: Record([("a", Long(42)), ("b", String("foo")), 
("c", Null), ("d", Null)]) for schema: Record { name: Name { name: 
"some_record", namespace: None }, aliases: None, doc: None, fields: 
[RecordField { name: "a", doc: None, default: None, schema: Long, order: 
Ascending, position: 0, custom_attributes: {} }, RecordField { name: "b", doc: 
None, default: None, schema: String, order: Ascending, position: 1, 
custom_attributes: {} }, RecordField { name: "c", doc: None, [...]
+            r#"Invalid value: Record([("a", Long(42)), ("b", String("foo")), 
("c", Null), ("d", Null)]) for schema: Record { name: Name { name: 
"some_record", namespace: None }, aliases: None, doc: None, fields: 
[RecordField { name: "a", doc: None, aliases: None, default: None, schema: 
Long, order: Ascending, position: 0, custom_attributes: {} }, RecordField { 
name: "b", doc: None, aliases: None, default: None, schema: String, order: 
Ascending, position: 1, custom_attributes: {} }, Recor [...]
         );
 
         assert!(Value::Map(
@@ -1394,7 +1399,7 @@ mod tests {
         )
         .validate(&schema));
         assert_logged(
-            r#"Invalid value: Map({"d": Long(123)}) for schema: Record { name: 
Name { name: "some_record", namespace: None }, aliases: None, doc: None, 
fields: [RecordField { name: "a", doc: None, default: None, schema: Long, 
order: Ascending, position: 0, custom_attributes: {} }, RecordField { name: 
"b", doc: None, default: None, schema: String, order: Ascending, position: 1, 
custom_attributes: {} }, RecordField { name: "c", doc: None, default: 
Some(Null), schema: Union(UnionSchema { sc [...]
+            r#"Invalid value: Map({"d": Long(123)}) for schema: Record { name: 
Name { name: "some_record", namespace: None }, aliases: None, doc: None, 
fields: [RecordField { name: "a", doc: None, aliases: None, default: None, 
schema: Long, order: Ascending, position: 0, custom_attributes: {} }, 
RecordField { name: "b", doc: None, aliases: None, default: None, schema: 
String, order: Ascending, position: 1, custom_attributes: {} }, RecordField { 
name: "c", doc: None, aliases: None, defaul [...]
 Field with name '"b"' is not a member of the map items"#,
         );
 
diff --git a/lang/rust/avro/tests/schema.rs b/lang/rust/avro/tests/schema.rs
index 83cd6c502..95ba18c2f 100644
--- a/lang/rust/avro/tests/schema.rs
+++ b/lang/rust/avro/tests/schema.rs
@@ -896,6 +896,7 @@ fn test_parse_reused_record_schema_by_fullname() {
                 ref name,
                 doc: _,
                 default: _,
+                aliases: _,
                 ref schema,
                 order: _,
                 position: _,
diff --git a/lang/rust/avro_derive/src/lib.rs b/lang/rust/avro_derive/src/lib.rs
index 77b0c6a24..5f8c0bc1c 100644
--- a/lang/rust/avro_derive/src/lib.rs
+++ b/lang/rust/avro_derive/src/lib.rs
@@ -30,6 +30,8 @@ struct FieldOptions {
     doc: Option<String>,
     #[darling(default)]
     default: Option<String>,
+    // #[darling(default)]
+    // aliases: Option<Vec<String>>,
     #[darling(default)]
     rename: Option<String>,
     #[darling(default)]
@@ -148,6 +150,7 @@ fn get_data_struct_schema_def(
                     }
                     None => quote! { None },
                 };
+                let aliases = quote! { None };
                 let schema_expr = type_to_schema_expr(&field.ty)?;
                 let position = index;
                 record_field_exprs.push(quote! {
@@ -155,6 +158,7 @@ fn get_data_struct_schema_def(
                             name: #name.to_string(),
                             doc: #doc,
                             default: #default_value,
+                            aliases: #aliases,
                             schema: #schema_expr,
                             order: 
apache_avro::schema::RecordFieldOrder::Ascending,
                             position: #position,

Reply via email to