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 b9d8a6ba7 AVRO-3928: [Rust] Convert serde_json::Value::Number to 
apache_avro::types::Value::Int when possible (#2682)
b9d8a6ba7 is described below

commit b9d8a6ba7b3a1e4c1a9d4fa0ce0cc10fcfe4a9b8
Author: Martin Grigorov <[email protected]>
AuthorDate: Thu Jan 11 14:49:30 2024 +0200

    AVRO-3928: [Rust] Convert serde_json::Value::Number to 
apache_avro::types::Value::Int when possible (#2682)
    
    * AVRO-3928: [Rust] Convert serde_json::Value::Number to 
apache_avro::types::Value::Int when possible
    
    If the number is bigger than i32::MIN and smaller than i32::MAX then
    convert to types::Value::Int, otherwise to types::Value::Long
    
    Signed-off-by: Martin Tzvetanov Grigorov <[email protected]>
    
    * AVRO-3928: [Rust] Add more unit tests for 
types::Value::from(serde_json::Value)
    
    Signed-off-by: Martin Tzvetanov Grigorov <[email protected]>
    
    ---------
    
    Signed-off-by: Martin Tzvetanov Grigorov <[email protected]>
---
 lang/rust/avro/src/schema.rs | 30 ++++++++++++++++++++++++
 lang/rust/avro/src/types.rs  | 55 +++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 84 insertions(+), 1 deletion(-)

diff --git a/lang/rust/avro/src/schema.rs b/lang/rust/avro/src/schema.rs
index 680a54a02..a7c622335 100644
--- a/lang/rust/avro/src/schema.rs
+++ b/lang/rust/avro/src/schema.rs
@@ -6611,4 +6611,34 @@ mod tests {
 
         Ok(())
     }
+
+    #[test]
+    fn avro_3928_parse_int_based_schema_with_default() -> TestResult {
+        let schema = r#"
+        {
+          "type": "record",
+          "name": "DateLogicalType",
+          "fields": [ {
+            "name": "birthday",
+            "type": {"type": "int", "logicalType": "date"},
+            "default": 1681601653
+          } ]
+        }"#;
+
+        match Schema::parse_str(schema)? {
+            Schema::Record(record_schema) => {
+                assert_eq!(record_schema.fields.len(), 1);
+                let field = record_schema.fields.first().unwrap();
+                assert_eq!(field.name, "birthday");
+                assert_eq!(field.schema, Schema::Date);
+                assert_eq!(
+                    types::Value::from(field.default.clone().unwrap()),
+                    types::Value::Int(1681601653)
+                );
+            }
+            _ => unreachable!("Expected Schema::Record"),
+        }
+
+        Ok(())
+    }
 }
diff --git a/lang/rust/avro/src/types.rs b/lang/rust/avro/src/types.rs
index 62752bbba..97b99a81a 100644
--- a/lang/rust/avro/src/types.rs
+++ b/lang/rust/avro/src/types.rs
@@ -281,7 +281,14 @@ impl From<JsonValue> for Value {
         match value {
             JsonValue::Null => Self::Null,
             JsonValue::Bool(b) => b.into(),
-            JsonValue::Number(ref n) if n.is_i64() => 
Value::Long(n.as_i64().unwrap()),
+            JsonValue::Number(ref n) if n.is_i64() => {
+                let n = n.as_i64().unwrap();
+                if n >= i32::MIN as i64 && n <= i32::MAX as i64 {
+                    Value::Int(n as i32)
+                } else {
+                    Value::Long(n)
+                }
+            }
             JsonValue::Number(ref n) if n.is_f64() => 
Value::Double(n.as_f64().unwrap()),
             JsonValue::Number(n) => Value::Long(n.as_u64().unwrap() as i64), 
// TODO: Not so great
             JsonValue::String(s) => s.into(),
@@ -1154,6 +1161,7 @@ mod tests {
     };
     use num_bigint::BigInt;
     use pretty_assertions::assert_eq;
+    use serde_json::json;
     use uuid::Uuid;
 
     #[test]
@@ -3061,4 +3069,49 @@ Field with name '"b"' is not a member of the map items"#,
 
         Ok(())
     }
+
+    #[test]
+    fn avro_3928_from_serde_value_to_types_value() {
+        assert_eq!(Value::from(serde_json::Value::Null), Value::Null);
+        assert_eq!(Value::from(json!(true)), Value::Boolean(true));
+        assert_eq!(Value::from(json!(false)), Value::Boolean(false));
+        assert_eq!(Value::from(json!(0)), Value::Int(0));
+        assert_eq!(Value::from(json!(i32::MIN)), Value::Int(i32::MIN));
+        assert_eq!(Value::from(json!(i32::MAX)), Value::Int(i32::MAX));
+        assert_eq!(
+            Value::from(json!(i32::MIN as i64 - 1)),
+            Value::Long(i32::MIN as i64 - 1)
+        );
+        assert_eq!(
+            Value::from(json!(i32::MAX as i64 + 1)),
+            Value::Long(i32::MAX as i64 + 1)
+        );
+        assert_eq!(Value::from(json!(1.23)), Value::Double(1.23));
+        assert_eq!(Value::from(json!(-1.23)), Value::Double(-1.23));
+        assert_eq!(Value::from(json!(u64::MIN)), Value::Int(u64::MIN as i32));
+        assert_eq!(Value::from(json!(u64::MAX)), Value::Long(u64::MAX as i64));
+        assert_eq!(
+            Value::from(json!("some text")),
+            Value::String("some text".into())
+        );
+        assert_eq!(
+            Value::from(json!(["text1", "text2", "text3"])),
+            Value::Array(vec![
+                Value::String("text1".into()),
+                Value::String("text2".into()),
+                Value::String("text3".into())
+            ])
+        );
+        assert_eq!(
+            Value::from(json!({"key1": "value1", "key2": "value2"})),
+            Value::Map(
+                vec![
+                    ("key1".into(), Value::String("value1".into())),
+                    ("key2".into(), Value::String("value2".into()))
+                ]
+                .into_iter()
+                .collect()
+            )
+        );
+    }
 }

Reply via email to