This is an automated email from the ASF dual-hosted git repository. mgrigorov pushed a commit to branch avro-3625-union-schema-is-nullable in repository https://gitbox.apache.org/repos/asf/avro.git
commit 9b968c4726c8c660195146c118131825cbdd6ba0 Author: Martin Tzvetanov Grigorov <[email protected]> AuthorDate: Wed Sep 7 11:19:25 2022 +0300 AVRO-3625: [Rust] UnionSchema is nullable if any of its variants is Null Signed-off-by: Martin Tzvetanov Grigorov <[email protected]> --- lang/rust/Cargo.lock | 2 +- lang/rust/avro/Cargo.toml | 2 +- lang/rust/avro/src/schema.rs | 114 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 114 insertions(+), 4 deletions(-) diff --git a/lang/rust/Cargo.lock b/lang/rust/Cargo.lock index 24c4024cc..794a8b74f 100644 --- a/lang/rust/Cargo.lock +++ b/lang/rust/Cargo.lock @@ -31,7 +31,7 @@ checksum = "1485d4d2cc45e7b201ee3767015c96faa5904387c9d87c6efdd0fb511f12d305" [[package]] name = "apache-avro" -version = "0.14.0" +version = "0.15.0" dependencies = [ "anyhow", "apache-avro-derive", diff --git a/lang/rust/avro/Cargo.toml b/lang/rust/avro/Cargo.toml index 4cca09d4d..e65a30bc4 100644 --- a/lang/rust/avro/Cargo.toml +++ b/lang/rust/avro/Cargo.toml @@ -17,7 +17,7 @@ [package] name = "apache-avro" -version = "0.14.0" +version = "0.15.0" authors = ["Apache Avro team <[email protected]>"] description = "A library for working with Apache Avro in Rust" license = "Apache-2.0" diff --git a/lang/rust/avro/src/schema.rs b/lang/rust/avro/src/schema.rs index 26868524a..bbf13138d 100644 --- a/lang/rust/avro/src/schema.rs +++ b/lang/rust/avro/src/schema.rs @@ -678,9 +678,9 @@ impl UnionSchema { &self.schemas } - /// Returns true if the first variant of this `UnionSchema` is `Null`. + /// Returns true if the any of the variants of this `UnionSchema` is `Null`. pub fn is_nullable(&self) -> bool { - !self.schemas.is_empty() && self.schemas[0] == Schema::Null + !self.schemas.is_empty() && self.schemas.iter().any(|s| s == &Schema::Null) } /// Optionally returns a reference to the schema matched by this value, as well as its position @@ -4092,4 +4092,114 @@ mod tests { _ => panic!("Expected Schema::Record"), } } + + #[test] + fn avro_3625_null_is_first() { + let schema_str = String::from( + r#" + { + "type": "record", + "name": "union_schema_test", + "fields": [ + {"name": "a", "type": ["null", "long"], "default": null} + ] + } + "#, + ); + + let schema = Schema::parse_str(&schema_str).unwrap(); + + match schema { + Schema::Record { name, fields, .. } => { + assert_eq!(name, Name::new("union_schema_test").unwrap()); + assert_eq!(fields.len(), 1); + let field = &fields[0]; + assert_eq!(&field.name, "a"); + assert_eq!(&field.default, &Some(Value::Null)); + match &field.schema { + Schema::Union(union) => { + assert_eq!(union.variants().len(), 2); + assert!(union.is_nullable()); + assert_eq!(union.variants()[0], Schema::Null); + assert_eq!(union.variants()[1], Schema::Long); + } + _ => panic!("Expected Schema::Union"), + } + } + _ => panic!("Expected Schema::Record"), + } + } + + #[test] + fn avro_3625_null_is_last() { + let schema_str = String::from( + r#" + { + "type": "record", + "name": "union_schema_test", + "fields": [ + {"name": "a", "type": ["long","null"], "default": 123} + ] + } + "#, + ); + + let schema = Schema::parse_str(&schema_str).unwrap(); + + match schema { + Schema::Record { name, fields, .. } => { + assert_eq!(name, Name::new("union_schema_test").unwrap()); + assert_eq!(fields.len(), 1); + let field = &fields[0]; + assert_eq!(&field.name, "a"); + assert_eq!(&field.default, &Some(json!(123))); + match &field.schema { + Schema::Union(union) => { + assert_eq!(union.variants().len(), 2); + assert_eq!(union.variants()[0], Schema::Long); + assert_eq!(union.variants()[1], Schema::Null); + } + _ => panic!("Expected Schema::Union"), + } + } + _ => panic!("Expected Schema::Record"), + } + } + + #[test] + fn avro_3625_null_is_the_middle() { + let schema_str = String::from( + r#" + { + "type": "record", + "name": "union_schema_test", + "fields": [ + {"name": "a", "type": ["long","null","int"], "default": 123} + ] + } + "#, + ); + + let schema = Schema::parse_str(&schema_str).unwrap(); + + match schema { + Schema::Record { name, fields, .. } => { + assert_eq!(name, Name::new("union_schema_test").unwrap()); + assert_eq!(fields.len(), 1); + let field = &fields[0]; + assert_eq!(&field.name, "a"); + assert_eq!(&field.default, &Some(json!(123))); + match &field.schema { + Schema::Union(union) => { + assert_eq!(union.variants().len(), 3); + assert_eq!(union.variants()[0], Schema::Long); + assert_eq!(union.variants()[1], Schema::Null); + assert_eq!(union.variants()[2], Schema::Int); + } + _ => panic!("Expected Schema::Union"), + } + } + _ => panic!("Expected Schema::Record"), + } + } }
