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/01/05 11:37:52 UTC

[avro] branch master updated: AVRO-3216 Reuse records' schema by name (#1345)

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 b76a437  AVRO-3216 Reuse records' schema by name (#1345)
b76a437 is described below

commit b76a437b970889255703ff48f7ee5981dfbcc17a
Author: Martin Grigorov <ma...@users.noreply.github.com>
AuthorDate: Wed Jan 5 13:37:26 2022 +0200

    AVRO-3216 Reuse records' schema by name (#1345)
    
    * AVRO-3197 Fallback to the 'type' when the logical type does not support the type
    
    Signed-off-by: Martin Tzvetanov Grigorov <mg...@apache.org>
    
    * AVRO-3197 Allow only when the "type" is "string"
    
    * AVRO-3197 Handle problematic complex type for date/time logical types
    
    Read the complex type recursively. It seems Avro Java may produce {"type": {"type": "string", "avro.java.string": "String"}, "logicalType": "timestamp-millis"}}, i.e. logicalType is on the same level as the outer "type"
    
    Signed-off-by: Martin Tzvetanov Grigorov <mg...@apache.org>
    
    * AVRO-3216 Allow to reuse record's schema by name
    
    * AVRO-3216 Extend the test case to do more assertions
    
    * AVRO-3216 Print err with Debug
---
 lang/rust/src/schema.rs   | 10 ++++--
 lang/rust/tests/io.rs     |  2 +-
 lang/rust/tests/schema.rs | 86 +++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 92 insertions(+), 6 deletions(-)

diff --git a/lang/rust/src/schema.rs b/lang/rust/src/schema.rs
index bab99d4..da8c0c3 100644
--- a/lang/rust/src/schema.rs
+++ b/lang/rust/src/schema.rs
@@ -785,12 +785,16 @@ impl Parser {
             lookup.insert(field.name.clone(), field.position);
         }
 
-        Ok(Schema::Record {
-            name,
+        let schema = Schema::Record {
+            name: name.clone(),
             doc: complex.doc(),
             fields,
             lookup,
-        })
+        };
+
+        self.parsed_schemas
+            .insert(name.fullname(None), schema.clone());
+        Ok(schema)
     }
 
     /// Parse a `serde_json::Value` representing a Avro enum type into a
diff --git a/lang/rust/tests/io.rs b/lang/rust/tests/io.rs
index 93edf0d..c1ab1d7 100644
--- a/lang/rust/tests/io.rs
+++ b/lang/rust/tests/io.rs
@@ -319,6 +319,6 @@ fn test_type_exception() -> Result<(), String> {
     match encoded {
         Ok(_) => Err(String::from("Expected ValidationError, got Ok")),
         Err(Error::Validation) => Ok(()),
-        Err(ref e) => Err(format!("Expected ValidationError, got {}", e)),
+        Err(ref e) => Err(format!("Expected ValidationError, got {:?}", e)),
     }
 }
diff --git a/lang/rust/tests/schema.rs b/lang/rust/tests/schema.rs
index efd9df2..d9fdefc 100644
--- a/lang/rust/tests/schema.rs
+++ b/lang/rust/tests/schema.rs
@@ -15,8 +15,10 @@
 // specific language governing permissions and limitations
 // under the License.
 
-//! Port of https://github.com/apache/avro/blob/release-1.9.1/lang/py/test/test_schema.py
-use avro_rs::{schema::Name, Error, Schema};
+use avro_rs::{
+    schema::{Name, RecordField},
+    Error, Schema,
+};
 use lazy_static::lazy_static;
 
 fn init() {
@@ -830,6 +832,86 @@ fn test_parse_list_with_cross_deps_and_namespaces_error() {
     let _ = Schema::parse_list(&schema_strs_second).expect_err("Test failed");
 }
 
+#[test]
+// <https://issues.apache.org/jira/browse/AVRO-3216>
+// test that field's RecordSchema could be referenced by a following field by full name
+fn test_parse_reused_record_schema_by_fullname() {
+    init();
+    let schema_str = r#"
+        {
+          "type" : "record",
+          "name" : "Weather",
+          "namespace" : "test",
+          "doc" : "A weather reading.",
+          "fields" : [
+            {
+                "name" : "station",
+                "type" : {
+                  "type" : "string",
+                  "avro.java.string" : "String"
+                }
+             },
+             {
+                "name" : "max_temp",
+                "type" : {
+                  "type" : "record",
+                  "name" : "Temp",
+                  "namespace": "prefix",
+                  "doc" : "A temperature reading.",
+                  "fields" : [ {
+                    "name" : "temp",
+                    "type" : "long"
+                  } ]
+                }
+            }, {
+                "name" : "min_temp",
+                "type" : "prefix.Temp"
+            }
+        ]
+       }
+    "#;
+
+    let schema = Schema::parse_str(schema_str);
+    assert!(schema.is_ok());
+    match schema.unwrap() {
+        Schema::Record {
+            ref name,
+            doc: _,
+            ref fields,
+            lookup: _,
+        } => {
+            assert_eq!(name.fullname(None), "test.Weather", "Name does not match!");
+
+            assert_eq!(fields.len(), 3, "The number of the fields is not correct!");
+
+            let RecordField {
+                ref name,
+                doc: _,
+                default: _,
+                ref schema,
+                order: _,
+                position: _,
+            } = fields.get(2).unwrap();
+
+            assert_eq!(name, "min_temp");
+
+            match schema {
+                Schema::Record {
+                    ref name,
+                    doc: _,
+                    ref fields,
+                    lookup: _,
+                } => {
+                    assert_eq!(name.fullname(None), "prefix.Temp", "Name does not match!");
+                    assert_eq!(fields.len(), 1, "The number of the fields is not correct!");
+                }
+                unexpected => unreachable!("Unexpected schema type: {:?}", unexpected),
+            }
+        }
+        unexpected => unreachable!("Unexpected schema type: {:?}", unexpected),
+    }
+}
+
 /// Return all permutations of an input slice
 fn permutations<T>(list: &[T]) -> Vec<Vec<&T>> {
     let size = list.len();