Selaa lähdekoodia

fix: support float value in attributes (#1396)

Co-authored-by: nathan <[email protected]>
Nathan.fooo 2 vuotta sitten
vanhempi
commit
9344ea23ca

+ 13 - 4
shared-lib/lib-ot/src/core/attributes/attribute.rs

@@ -115,6 +115,10 @@ impl AttributeHashMap {
     pub fn is_empty(&self) -> bool {
         self.0.is_empty()
     }
+
+    pub fn to_json(&self) -> Result<String, OTError> {
+        serde_json::to_string(self).map_err(|err| OTError::serde().context(err))
+    }
 }
 
 impl Display for AttributeHashMap {
@@ -210,11 +214,10 @@ impl AttributeValue {
     pub fn none() -> Self {
         Self { ty: None, value: None }
     }
-    pub fn from_int(val: usize) -> Self {
-        let value = if val > 0_usize { Some(val.to_string()) } else { None };
+    pub fn from_int(val: i64) -> Self {
         Self {
             ty: Some(ValueType::IntType),
-            value,
+            value: Some(val.to_string()),
         }
     }
 
@@ -268,7 +271,7 @@ impl std::convert::From<bool> for AttributeValue {
 
 impl std::convert::From<usize> for AttributeValue {
     fn from(value: usize) -> Self {
-        AttributeValue::from_int(value)
+        AttributeValue::from_int(value as i64)
     }
 }
 
@@ -284,6 +287,12 @@ impl std::convert::From<String> for AttributeValue {
     }
 }
 
+impl std::convert::From<f64> for AttributeValue {
+    fn from(value: f64) -> Self {
+        AttributeValue::from_float(value)
+    }
+}
+
 #[derive(Default)]
 pub struct AttributeBuilder {
     attributes: AttributeHashMap,

+ 22 - 8
shared-lib/lib-ot/src/core/attributes/attribute_serde.rs

@@ -70,56 +70,70 @@ impl<'de> Deserialize<'de> for AttributeValue {
             where
                 E: de::Error,
             {
-                Ok(AttributeValue::from_int(value as usize))
+                Ok(AttributeValue::from_int(value as i64))
             }
 
             fn visit_i16<E>(self, value: i16) -> Result<Self::Value, E>
             where
                 E: de::Error,
             {
-                Ok(AttributeValue::from_int(value as usize))
+                Ok(AttributeValue::from_int(value as i64))
             }
 
             fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E>
             where
                 E: de::Error,
             {
-                Ok(AttributeValue::from_int(value as usize))
+                Ok(AttributeValue::from_int(value as i64))
             }
 
             fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
             where
                 E: de::Error,
             {
-                Ok(AttributeValue::from_int(value as usize))
+                Ok(AttributeValue::from_int(value as i64))
             }
 
             fn visit_u8<E>(self, value: u8) -> Result<Self::Value, E>
             where
                 E: de::Error,
             {
-                Ok(AttributeValue::from_int(value as usize))
+                Ok(AttributeValue::from_int(value as i64))
             }
 
             fn visit_u16<E>(self, value: u16) -> Result<Self::Value, E>
             where
                 E: de::Error,
             {
-                Ok(AttributeValue::from_int(value as usize))
+                Ok(AttributeValue::from_int(value as i64))
             }
 
             fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
             where
                 E: de::Error,
             {
-                Ok(AttributeValue::from_int(value as usize))
+                Ok(AttributeValue::from_int(value as i64))
             }
 
             fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
             where
                 E: de::Error,
             {
-                Ok(AttributeValue::from_int(value as usize))
+                Ok(AttributeValue::from_int(value as i64))
+            }
+
+            fn visit_f32<E>(self, value: f32) -> Result<Self::Value, E>
+            where
+                E: de::Error,
+            {
+                Ok(AttributeValue::from_float(value as f64))
+            }
+
+            fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
+            where
+                E: de::Error,
+            {
+                Ok(AttributeValue::from_float(value as f64))
             }
 
             fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>

+ 1 - 0
shared-lib/lib-ot/tests/node/mod.rs

@@ -1,3 +1,4 @@
+mod operation_attribute_test;
 mod operation_delete_test;
 mod operation_delta_test;
 mod operation_insert_test;

+ 64 - 0
shared-lib/lib-ot/tests/node/operation_attribute_test.rs

@@ -0,0 +1,64 @@
+use crate::node::script::NodeScript::*;
+use crate::node::script::NodeTest;
+use lib_ot::core::{AttributeEntry, AttributeValue, Changeset, NodeData};
+
+#[test]
+fn operation_update_attribute_with_float_value_test() {
+    let mut test = NodeTest::new();
+    let text_node = NodeData::new("text");
+    let scripts = vec![
+        InsertNode {
+            path: 0.into(),
+            node_data: text_node.clone(),
+            rev_id: 1,
+        },
+        UpdateBody {
+            path: 0.into(),
+            changeset: Changeset::Attributes {
+                new: AttributeEntry::new("value", 12.2).into(),
+                old: Default::default(),
+            },
+        },
+        AssertNodeAttributes {
+            path: 0.into(),
+            expected: r#"{"value":12.2}"#,
+        },
+    ];
+    test.run_scripts(scripts);
+}
+
+#[test]
+fn operation_update_attribute_with_negative_value_test() {
+    let mut test = NodeTest::new();
+    let text_node = NodeData::new("text");
+    let scripts = vec![
+        InsertNode {
+            path: 0.into(),
+            node_data: text_node.clone(),
+            rev_id: 1,
+        },
+        UpdateBody {
+            path: 0.into(),
+            changeset: Changeset::Attributes {
+                new: AttributeEntry::new("value", -12.2).into(),
+                old: Default::default(),
+            },
+        },
+        AssertNodeAttributes {
+            path: 0.into(),
+            expected: r#"{"value":-12.2}"#,
+        },
+        UpdateBody {
+            path: 0.into(),
+            changeset: Changeset::Attributes {
+                new: AttributeEntry::new("value", AttributeValue::from_int(-12)).into(),
+                old: Default::default(),
+            },
+        },
+        AssertNodeAttributes {
+            path: 0.into(),
+            expected: r#"{"value":-12}"#,
+        },
+    ];
+    test.run_scripts(scripts);
+}

+ 8 - 0
shared-lib/lib-ot/tests/node/script.rs

@@ -47,6 +47,10 @@ pub enum NodeScript {
         path: Path,
         expected: Option<NodeData>,
     },
+    AssertNodeAttributes {
+        path: Path,
+        expected: &'static str,
+    },
     AssertNodeDelta {
         path: Path,
         expected: DeltaTextOperations,
@@ -130,6 +134,10 @@ impl NodeTest {
                 let node = self.node_tree.get_node_data_at_path(&path);
                 assert_eq!(node, expected.map(|e| e.into()));
             }
+            NodeScript::AssertNodeAttributes { path, expected } => {
+                let node = self.node_tree.get_node_data_at_path(&path).unwrap();
+                assert_eq!(node.attributes.to_json().unwrap(), expected);
+            }
             NodeScript::AssertNumberOfChildrenAtPath { path, expected } => match path {
                 None => {
                     let len = self.node_tree.number_of_children(None);