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

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


The following commit(s) were added to refs/heads/main by this push:
     new f76e2ff  fix: Choose correct schema when serializing an Option<Enum> 
(#337)
f76e2ff is described below

commit f76e2ff90e4f8730268db1c86f9d37ffdb9a59ed
Author: Allen Ho <[email protected]>
AuthorDate: Sat Nov 22 07:37:10 2025 -0800

    fix: Choose correct schema when serializing an Option<Enum> (#337)
    
    * fix: Choose correct schema when serializing an Option<Enum>
    
    * chore: Rename test to match Github PR number
    
    ---------
    
    Co-authored-by: allenyuchen <[email protected]>
---
 avro/src/ser_schema.rs | 194 +++++++++++++++++++++++++++++++++++++++++--------
 avro/src/writer.rs     |   2 +-
 2 files changed, 163 insertions(+), 33 deletions(-)

diff --git a/avro/src/ser_schema.rs b/avro/src/ser_schema.rs
index 7d0ed3e..5a91eb6 100644
--- a/avro/src/ser_schema.rs
+++ b/avro/src/ser_schema.rs
@@ -1072,38 +1072,13 @@ impl<'s, W: Write> SchemaAwareWriteSerializer<'s, W> {
     where
         T: ?Sized + ser::Serialize,
     {
-        let create_error = |cause: String| {
-            Error::new(Details::SerializeValueWithSchema {
-                value_type: "some",
-                value: format!("Some(?). Cause: {cause}"),
-                schema: schema.clone(),
-            })
-        };
-
-        match schema {
-            Schema::Union(union_schema) => {
-                for (i, variant_schema) in 
union_schema.schemas.iter().enumerate() {
-                    match variant_schema {
-                        Schema::Null => { /* skip */ }
-                        _ => {
-                            encode_long(i as i64, &mut *self.writer)?;
-                            let mut variant_ser = 
SchemaAwareWriteSerializer::new(
-                                &mut *self.writer,
-                                variant_schema,
-                                self.names,
-                                self.enclosing_namespace.clone(),
-                            );
-                            return value.serialize(&mut variant_ser);
-                        }
-                    }
-                }
-                Err(create_error(format!(
-                    "Cannot find a matching Null schema in {:?}",
-                    union_schema.schemas
-                )))
-            }
-            _ => value.serialize(self),
-        }
+        let mut inner_ser = SchemaAwareWriteSerializer::new(
+            &mut *self.writer,
+            schema,
+            self.names,
+            self.enclosing_namespace.clone(),
+        );
+        value.serialize(&mut inner_ser)
     }
 
     fn serialize_unit_struct_with_schema(
@@ -2770,4 +2745,159 @@ mod tests {
 
         Ok(())
     }
+
+    #[test]
+    fn avro_rs_337_serialize_union_record_variant() -> TestResult {
+        let schema = Schema::parse_str(
+            r#"{
+            "type": "record",
+            "name": "TestRecord",
+            "fields": [{
+                "name": "innerUnion", "type": [
+                    {"type": "record", "name": "innerRecordFoo", "fields": [
+                        {"name": "foo", "type": "string"}
+                    ]},
+                    {"type": "record", "name": "innerRecordBar", "fields": [
+                        {"name": "bar", "type": "string"}
+                    ]},
+                    {"name": "intField", "type": "int"},
+                    {"name": "stringField", "type": "string"}
+                ]
+            }]
+        }"#,
+        )?;
+
+        #[derive(Serialize)]
+        #[serde(rename_all = "camelCase")]
+        struct TestRecord {
+            inner_union: InnerUnion,
+        }
+
+        #[derive(Serialize)]
+        #[serde(untagged)]
+        enum InnerUnion {
+            InnerVariantFoo(InnerRecordFoo),
+            InnerVariantBar(InnerRecordBar),
+            IntField(i32),
+            StringField(String),
+        }
+
+        #[derive(Serialize)]
+        #[serde(rename = "innerRecordFoo")]
+        struct InnerRecordFoo {
+            foo: String,
+        }
+
+        #[derive(Serialize)]
+        #[serde(rename = "innerRecordBar")]
+        struct InnerRecordBar {
+            bar: String,
+        }
+
+        let mut buffer: Vec<u8> = Vec::new();
+        let rs = ResolvedSchema::try_from(&schema)?;
+        let mut serializer =
+            SchemaAwareWriteSerializer::new(&mut buffer, &schema, 
rs.get_names(), None);
+
+        let foo_record = TestRecord {
+            inner_union: InnerUnion::InnerVariantFoo(InnerRecordFoo {
+                foo: String::from("foo"),
+            }),
+        };
+        foo_record.serialize(&mut serializer)?;
+        let bar_record = TestRecord {
+            inner_union: InnerUnion::InnerVariantBar(InnerRecordBar {
+                bar: String::from("bar"),
+            }),
+        };
+        bar_record.serialize(&mut serializer)?;
+        let int_record = TestRecord {
+            inner_union: InnerUnion::IntField(1),
+        };
+        int_record.serialize(&mut serializer)?;
+        let string_record = TestRecord {
+            inner_union: InnerUnion::StringField(String::from("string")),
+        };
+        string_record.serialize(&mut serializer)?;
+        Ok(())
+    }
+
+    #[test]
+    fn avro_rs_337_serialize_option_union_record_variant() -> TestResult {
+        let schema = Schema::parse_str(
+            r#"{
+            "type": "record",
+            "name": "TestRecord",
+            "fields": [{
+                "name": "innerUnion", "type": [
+                    "null",
+                    {"type": "record", "name": "innerRecordFoo", "fields": [
+                        {"name": "foo", "type": "string"}
+                    ]},
+                    {"type": "record", "name": "innerRecordBar", "fields": [
+                        {"name": "bar", "type": "string"}
+                    ]},
+                    {"name": "intField", "type": "int"},
+                    {"name": "stringField", "type": "string"}
+                ]
+            }]
+        }"#,
+        )?;
+
+        #[derive(Serialize)]
+        #[serde(rename_all = "camelCase")]
+        struct TestRecord {
+            inner_union: Option<InnerUnion>,
+        }
+
+        #[derive(Serialize)]
+        #[serde(untagged)]
+        enum InnerUnion {
+            InnerVariantFoo(InnerRecordFoo),
+            InnerVariantBar(InnerRecordBar),
+            IntField(i32),
+            StringField(String),
+        }
+
+        #[derive(Serialize)]
+        #[serde(rename = "innerRecordFoo")]
+        struct InnerRecordFoo {
+            foo: String,
+        }
+
+        #[derive(Serialize)]
+        #[serde(rename = "innerRecordBar")]
+        struct InnerRecordBar {
+            bar: String,
+        }
+
+        let mut buffer: Vec<u8> = Vec::new();
+        let rs = ResolvedSchema::try_from(&schema)?;
+        let mut serializer =
+            SchemaAwareWriteSerializer::new(&mut buffer, &schema, 
rs.get_names(), None);
+
+        let null_record = TestRecord { inner_union: None };
+        null_record.serialize(&mut serializer)?;
+        let foo_record = TestRecord {
+            inner_union: Some(InnerUnion::InnerVariantFoo(InnerRecordFoo {
+                foo: String::from("foo"),
+            })),
+        };
+        foo_record.serialize(&mut serializer)?;
+        let bar_record = TestRecord {
+            inner_union: Some(InnerUnion::InnerVariantBar(InnerRecordBar {
+                bar: String::from("bar"),
+            })),
+        };
+        bar_record.serialize(&mut serializer)?;
+        let int_record = TestRecord {
+            inner_union: Some(InnerUnion::IntField(1)),
+        };
+        int_record.serialize(&mut serializer)?;
+        let string_record = TestRecord {
+            inner_union: Some(InnerUnion::StringField(String::from("string"))),
+        };
+        string_record.serialize(&mut serializer)?;
+        Ok(())
+    }
 }
diff --git a/avro/src/writer.rs b/avro/src/writer.rs
index 4bf2cde..31fb5c7 100644
--- a/avro/src/writer.rs
+++ b/avro/src/writer.rs
@@ -1653,7 +1653,7 @@ mod tests {
             Err(e) => {
                 assert_eq!(
                     e.to_string(),
-                    r#"Failed to serialize field 'time' for record 
Record(RecordSchema { name: Name { name: "Conference", namespace: None }, 
aliases: None, doc: None, fields: [RecordField { name: "name", doc: None, 
aliases: None, default: None, schema: String, order: Ascending, position: 0, 
custom_attributes: {} }, RecordField { name: "date", doc: None, aliases: 
Some(["time2", "time"]), default: None, schema: Union(UnionSchema { schemas: 
[Null, Long], variant_index: {Null: 0, Long: 1} }) [...]
+                    r#"Failed to serialize field 'time' for record 
Record(RecordSchema { name: Name { name: "Conference", namespace: None }, 
aliases: None, doc: None, fields: [RecordField { name: "name", doc: None, 
aliases: None, default: None, schema: String, order: Ascending, position: 0, 
custom_attributes: {} }, RecordField { name: "date", doc: None, aliases: 
Some(["time2", "time"]), default: None, schema: Union(UnionSchema { schemas: 
[Null, Long], variant_index: {Null: 0, Long: 1} }) [...]
                 );
             }
         }

Reply via email to