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 2023/06/16 21:27:39 UTC

[avro] branch branch-1.11 updated: AVRO-3772: [Rust] Use the enum default field instead of the field default (#2294)

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

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


The following commit(s) were added to refs/heads/branch-1.11 by this push:
     new 1c0817f07 AVRO-3772: [Rust] Use the enum default field instead of the field default (#2294)
1c0817f07 is described below

commit 1c0817f07cffb8cdde331ffbf8edc8ec212cb1b6
Author: Martin Grigorov <ma...@users.noreply.github.com>
AuthorDate: Sat Jun 17 00:26:50 2023 +0300

    AVRO-3772: [Rust] Use the enum default field instead of the field default (#2294)
    
    Signed-off-by: Martin Tzvetanov Grigorov <mg...@apache.org>
    (cherry picked from commit 2fb183159212e28fbea99dba60a491abe8cb7a96)
---
 lang/rust/avro/src/error.rs                |  3 ++
 lang/rust/avro/src/schema.rs               | 49 ++++++++++++++++++++++++++++++
 lang/rust/avro/src/schema_compatibility.rs | 32 +++++++++----------
 lang/rust/avro/src/types.rs                | 30 ++++++++++++------
 lang/rust/avro_derive/src/lib.rs           |  1 +
 5 files changed, 89 insertions(+), 26 deletions(-)

diff --git a/lang/rust/avro/src/error.rs b/lang/rust/avro/src/error.rs
index 17e2c4e8e..b9b6ccf66 100644
--- a/lang/rust/avro/src/error.rs
+++ b/lang/rust/avro/src/error.rs
@@ -307,6 +307,9 @@ pub enum Error {
     #[error("Duplicate enum symbol {0}")]
     EnumSymbolDuplicate(String),
 
+    #[error("Default value for enum must be a string! Got: {0}")]
+    EnumDefaultWrongType(serde_json::Value),
+
     #[error("No `items` in array")]
     GetArrayItemsField,
 
diff --git a/lang/rust/avro/src/schema.rs b/lang/rust/avro/src/schema.rs
index aa5013ffb..9fb5bacc5 100644
--- a/lang/rust/avro/src/schema.rs
+++ b/lang/rust/avro/src/schema.rs
@@ -692,6 +692,8 @@ pub struct EnumSchema {
     pub doc: Documentation,
     /// The set of symbols of the schema
     pub symbols: Vec<String>,
+    /// An optional default symbol used for compatibility
+    pub default: Option<String>,
     /// The custom attributes of the schema
     pub attributes: BTreeMap<String, Value>,
 }
@@ -1486,11 +1488,21 @@ impl Parser {
             existing_symbols.insert(symbol);
         }
 
+        let mut default: Option<String> = None;
+        if let Some(value) = complex.get("default") {
+            if let Value::String(ref s) = *value {
+                default = Some(s.clone());
+            } else {
+                return Err(Error::EnumDefaultWrongType(value.clone()));
+            }
+        }
+
         let schema = Schema::Enum(EnumSchema {
             name,
             aliases: aliases.clone(),
             doc: complex.doc(),
             symbols,
+            default,
             attributes: self.get_custom_attributes(complex, vec!["symbols"]),
         });
 
@@ -2828,6 +2840,7 @@ mod tests {
                         aliases: None,
                         doc: None,
                         symbols: vec!["one".to_string(), "two".to_string(), "three".to_string()],
+                        default: None,
                         attributes: Default::default(),
                     }),
                     order: RecordFieldOrder::Ascending,
@@ -2847,6 +2860,7 @@ mod tests {
                         aliases: None,
                         doc: None,
                         symbols: vec!["one".to_string(), "two".to_string(), "three".to_string()],
+                        default: None,
                         attributes: Default::default(),
                     }),
                     order: RecordFieldOrder::Ascending,
@@ -2964,6 +2978,7 @@ mod tests {
                 "clubs".to_owned(),
                 "hearts".to_owned(),
             ],
+            default: None,
             attributes: Default::default(),
         });
 
@@ -4715,4 +4730,38 @@ mod tests {
 
         Ok(())
     }
+
+    #[test]
+    fn test_avro_3772_enum_default_wrong_type() -> TestResult {
+        let schema = r#"
+        {
+          "type": "record",
+          "name": "test",
+          "fields": [
+            {"name": "a", "type": "long", "default": 42},
+            {"name": "b", "type": "string"},
+            {
+              "name": "c",
+              "type": {
+                "type": "enum",
+                "name": "suit",
+                "symbols": ["diamonds", "spades", "clubs", "hearts"],
+                "default": 123
+              }
+            }
+          ]
+        }
+        "#;
+
+        match Schema::parse_str(schema) {
+            Err(err) => {
+                assert_eq!(
+                    err.to_string(),
+                    "Default value for enum must be a string! Got: 123"
+                );
+            }
+            _ => panic!("Expected an error"),
+        }
+        Ok(())
+    }
 }
diff --git a/lang/rust/avro/src/schema_compatibility.rs b/lang/rust/avro/src/schema_compatibility.rs
index b8cd46119..b661054d6 100644
--- a/lang/rust/avro/src/schema_compatibility.rs
+++ b/lang/rust/avro/src/schema_compatibility.rs
@@ -912,7 +912,7 @@ mod tests {
     }
 
     #[test]
-    fn avro_3772_enum_default() -> TestResult {
+    fn test_avro_3772_enum_default() -> TestResult {
         let writer_raw_schema = r#"
         {
           "type": "record",
@@ -925,9 +925,9 @@ mod tests {
               "type": {
                 "type": "enum",
                 "name": "suit",
-                "symbols": ["diamonds", "spades", "clubs", "hearts"]
-              },
-              "default": "spades"
+                "symbols": ["diamonds", "spades", "clubs", "hearts"],
+                "default": "spades"
+              }
             }
           ]
         }
@@ -944,10 +944,10 @@ mod tests {
               "name": "c",
               "type": {
                  "type": "enum",
-                "name": "suit",
-                  "symbols": ["diamonds", "spades", "ninja", "hearts"]
-              },
-              "default": "spades"
+                 "name": "suit",
+                 "symbols": ["diamonds", "spades", "ninja", "hearts"],
+                 "default": "spades"
+              }
             }
           ]
         }
@@ -976,7 +976,7 @@ mod tests {
     }
 
     #[test]
-    fn avro_3772_enum_default_less_symbols() -> TestResult {
+    fn test_avro_3772_enum_default_less_symbols() -> TestResult {
         let writer_raw_schema = r#"
         {
           "type": "record",
@@ -989,9 +989,9 @@ mod tests {
               "type": {
                 "type": "enum",
                 "name": "suit",
-                "symbols": ["diamonds", "spades", "clubs", "hearts"]
-              },
-              "default": "spades"
+                "symbols": ["diamonds", "spades", "clubs", "hearts"],
+                "default": "spades"
+              }
             }
           ]
         }
@@ -1008,10 +1008,10 @@ mod tests {
               "name": "c",
               "type": {
                  "type": "enum",
-                "name": "suit",
-                  "symbols": ["hearts", "spades"]
-              },
-              "default": "spades"
+                  "name": "suit",
+                  "symbols": ["hearts", "spades"],
+                  "default": "spades"
+              }
             }
           ]
         }
diff --git a/lang/rust/avro/src/types.rs b/lang/rust/avro/src/types.rs
index b0a022347..7bb933a4b 100644
--- a/lang/rust/avro/src/types.rs
+++ b/lang/rust/avro/src/types.rs
@@ -624,9 +624,11 @@ impl Value {
             Schema::Union(ref inner) => {
                 self.resolve_union(inner, names, enclosing_namespace, field_default)
             }
-            Schema::Enum(EnumSchema { ref symbols, .. }) => {
-                self.resolve_enum(symbols, field_default)
-            }
+            Schema::Enum(EnumSchema {
+                ref symbols,
+                ref default,
+                ..
+            }) => self.resolve_enum(symbols, default, field_default),
             Schema::Array(ref inner) => self.resolve_array(inner, names, enclosing_namespace),
             Schema::Map(ref inner) => self.resolve_map(inner, names, enclosing_namespace),
             Schema::Record(RecordSchema { ref fields, .. }) => {
@@ -848,14 +850,15 @@ impl Value {
     fn resolve_enum(
         self,
         symbols: &[String],
-        field_default: &Option<JsonValue>,
+        enum_default: &Option<String>,
+        _field_default: &Option<JsonValue>,
     ) -> Result<Self, Error> {
         let validate_symbol = |symbol: String, symbols: &[String]| {
             if let Some(index) = symbols.iter().position(|item| item == &symbol) {
                 Ok(Value::Enum(index as u32, symbol))
             } else {
-                match field_default {
-                    Some(JsonValue::String(default)) => {
+                match enum_default {
+                    Some(default) => {
                         if let Some(index) = symbols.iter().position(|item| item == default) {
                             Ok(Value::Enum(index as u32, default.clone()))
                         } else {
@@ -973,10 +976,15 @@ impl Value {
                     Some(value) => value,
                     None => match field.default {
                         Some(ref value) => match field.schema {
-                            Schema::Enum(EnumSchema { ref symbols, .. }) => {
-                                Value::from(value.clone())
-                                    .resolve_enum(symbols, &field.default.clone())?
-                            }
+                            Schema::Enum(EnumSchema {
+                                ref symbols,
+                                ref default,
+                                ..
+                            }) => Value::from(value.clone()).resolve_enum(
+                                symbols,
+                                default,
+                                &field.default.clone(),
+                            )?,
                             Schema::Union(ref union_schema) => {
                                 let first = &union_schema.variants()[0];
                                 // NOTE: this match exists only to optimize null defaults for large
@@ -1236,6 +1244,7 @@ mod tests {
                 "diamonds".to_string(),
                 "clubs".to_string(),
             ],
+            default: None,
             attributes: Default::default(),
         });
 
@@ -1282,6 +1291,7 @@ mod tests {
                 "clubs".to_string(),
                 "spades".to_string(),
             ],
+            default: None,
             attributes: Default::default(),
         });
 
diff --git a/lang/rust/avro_derive/src/lib.rs b/lang/rust/avro_derive/src/lib.rs
index 5e80e70af..5b36839be 100644
--- a/lang/rust/avro_derive/src/lib.rs
+++ b/lang/rust/avro_derive/src/lib.rs
@@ -222,6 +222,7 @@ fn get_data_enum_schema_def(
                 aliases: #enum_aliases,
                 doc: #doc,
                 symbols: vec![#(#symbols.to_owned()),*],
+                default: None,
                 attributes: Default::default(),
             })
         })