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

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


The following commit(s) were added to refs/heads/main by this push:
     new e248e6b20 AVRO-3917: [Rust] take field aliases into account when 
calculating schema compatibilities (#2633)
e248e6b20 is described below

commit e248e6b20c462e3f42e4cb73ab4a9fe0d5eeabbf
Author: Marcos Schroh <[email protected]>
AuthorDate: Tue Dec 12 11:19:46 2023 +0100

    AVRO-3917: [Rust] take field aliases into account when calculating schema 
compatibilities (#2633)
    
    * AVRO-3917: [Rust] take field aliases into account when calculating schema 
compatibilities
    
    * AVRO-3917: Minor improvements
    
    Signed-off-by: Martin Tzvetanov Grigorov <[email protected]>
    
    ---------
    
    Signed-off-by: Martin Tzvetanov Grigorov <[email protected]>
    Co-authored-by: Martin Tzvetanov Grigorov <[email protected]>
---
 lang/rust/avro/src/schema_compatibility.rs | 112 +++++++++++++++++++++--------
 1 file changed, 83 insertions(+), 29 deletions(-)

diff --git a/lang/rust/avro/src/schema_compatibility.rs 
b/lang/rust/avro/src/schema_compatibility.rs
index 46c4d4e02..107a30a37 100644
--- a/lang/rust/avro/src/schema_compatibility.rs
+++ b/lang/rust/avro/src/schema_compatibility.rs
@@ -158,17 +158,45 @@ impl Checker {
             }) = readers_schema
             {
                 for field in r_fields.iter() {
-                    if let Some(pos) = w_lookup.get(&field.name) {
-                        if let Err(err) =
-                            self.full_match_schemas(&w_fields[*pos].schema, 
&field.schema)
-                        {
-                            return Err(CompatibilityError::FieldTypeMismatch(
-                                field.name.clone(),
-                                Box::new(err),
-                            ));
+                    // get all field names in a vector (field.name + aliases)
+                    let mut fields_names = vec![&field.name];
+                    if let Some(ref aliases) = field.aliases {
+                        for alias in aliases {
+                            fields_names.push(alias);
+                        }
+                    }
+
+                    // Check whether any of the possible fields names are in 
the writer schema.
+                    // If the field was found, then it must have the exact 
same name with the writer field,
+                    // otherwise we would have a false positive with the 
writers aliases
+                    let mut position = None;
+                    for field_name in fields_names {
+                        if let Some(pos) = w_lookup.get(field_name) {
+                            if &w_fields[*pos].name == field_name {
+                                position = Some(pos);
+                                break;
+                            }
+                        }
+                    }
+
+                    match position {
+                        Some(pos) => {
+                            if let Err(err) =
+                                
self.full_match_schemas(&w_fields[*pos].schema, &field.schema)
+                            {
+                                return 
Err(CompatibilityError::FieldTypeMismatch(
+                                    field.name.clone(),
+                                    Box::new(err),
+                                ));
+                            }
+                        }
+                        _ => {
+                            if field.default.is_none() {
+                                return 
Err(CompatibilityError::MissingDefaultValue(
+                                    field.name.clone(),
+                                ));
+                            }
                         }
-                    } else if field.default.is_none() {
-                        return 
Err(CompatibilityError::MissingDefaultValue(field.name.clone()));
                     }
                 }
             }
@@ -1162,9 +1190,8 @@ mod tests {
     #[test]
     fn 
avro_3894_take_aliases_into_account_when_serializing_for_schema_compatibility() 
-> TestResult
     {
-        use serde::{Deserialize, Serialize};
-
-        const RAW_SCHEMA_V1: &str = r#"
+        let schema_v1 = Schema::parse_str(
+            r#"
         {
             "type": "record",
             "name": "Conference",
@@ -1173,8 +1200,11 @@ mod tests {
                 {"type": "string", "name": "name"},
                 {"type": "long", "name": "date"}
             ]
-        }"#;
-        const RAW_SCHEMA_V2: &str = r#"
+        }"#,
+        )?;
+
+        let schema_v2 = Schema::parse_str(
+            r#"
         {
             "type": "record",
             "name": "Conference",
@@ -1183,23 +1213,47 @@ mod tests {
                 {"type": "string", "name": "name"},
                 {"type": "long", "name": "date", "aliases" : [ "time" ]}
             ]
-        }"#;
+        }"#,
+        )?;
 
-        #[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
-        pub struct Conference {
-            pub name: String,
-            pub date: i64,
-        }
-        #[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
-        pub struct ConferenceV2 {
-            pub name: String,
-            pub time: i64,
-        }
+        assert!(SchemaCompatibility::mutual_read(&schema_v1, 
&schema_v2).is_ok());
 
-        let schema_v1 = Schema::parse_str(RAW_SCHEMA_V1)?;
-        let schema_v2 = Schema::parse_str(RAW_SCHEMA_V2)?;
+        Ok(())
+    }
 
-        assert!(SchemaCompatibility::can_read(&schema_v1, &schema_v2).is_ok());
+    #[test]
+    fn avro_3917_take_aliases_into_account_for_schema_compatibility() -> 
TestResult {
+        let schema_v1 = Schema::parse_str(
+            r#"
+        {
+            "type": "record",
+            "name": "Conference",
+            "namespace": "advdaba",
+            "fields": [
+                {"type": "string", "name": "name"},
+                {"type": "long", "name": "date", "aliases" : [ "time" ]}
+            ]
+        }"#,
+        )?;
+
+        let schema_v2 = Schema::parse_str(
+            r#"
+        {
+            "type": "record",
+            "name": "Conference",
+            "namespace": "advdaba",
+            "fields": [
+                {"type": "string", "name": "name"},
+                {"type": "long", "name": "time"}
+            ]
+        }"#,
+        )?;
+
+        assert!(SchemaCompatibility::can_read(&schema_v2, &schema_v1).is_ok());
+        assert_eq!(
+            CompatibilityError::MissingDefaultValue(String::from("time")),
+            SchemaCompatibility::can_read(&schema_v1, &schema_v2).unwrap_err()
+        );
 
         Ok(())
     }

Reply via email to