From 9344ea23ca2c2f7778019c38879658bccfcae37b Mon Sep 17 00:00:00 2001 From: "Nathan.fooo" <86001920+appflowy@users.noreply.github.com> Date: Sun, 30 Oct 2022 09:35:15 +0800 Subject: [PATCH] fix: support float value in attributes (#1396) Co-authored-by: nathan --- .../lib-ot/src/core/attributes/attribute.rs | 17 +++-- .../src/core/attributes/attribute_serde.rs | 30 ++++++--- shared-lib/lib-ot/tests/node/mod.rs | 1 + .../tests/node/operation_attribute_test.rs | 64 +++++++++++++++++++ shared-lib/lib-ot/tests/node/script.rs | 8 +++ 5 files changed, 108 insertions(+), 12 deletions(-) create mode 100644 shared-lib/lib-ot/tests/node/operation_attribute_test.rs diff --git a/shared-lib/lib-ot/src/core/attributes/attribute.rs b/shared-lib/lib-ot/src/core/attributes/attribute.rs index 60830684f8..bed2baade8 100644 --- a/shared-lib/lib-ot/src/core/attributes/attribute.rs +++ b/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 { + 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 for AttributeValue { impl std::convert::From 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 for AttributeValue { } } +impl std::convert::From for AttributeValue { + fn from(value: f64) -> Self { + AttributeValue::from_float(value) + } +} + #[derive(Default)] pub struct AttributeBuilder { attributes: AttributeHashMap, diff --git a/shared-lib/lib-ot/src/core/attributes/attribute_serde.rs b/shared-lib/lib-ot/src/core/attributes/attribute_serde.rs index dd953b7ecd..80fd745343 100644 --- a/shared-lib/lib-ot/src/core/attributes/attribute_serde.rs +++ b/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(self, value: i16) -> Result where E: de::Error, { - Ok(AttributeValue::from_int(value as usize)) + Ok(AttributeValue::from_int(value as i64)) } fn visit_i32(self, value: i32) -> Result where E: de::Error, { - Ok(AttributeValue::from_int(value as usize)) + Ok(AttributeValue::from_int(value as i64)) } fn visit_i64(self, value: i64) -> Result where E: de::Error, { - Ok(AttributeValue::from_int(value as usize)) + Ok(AttributeValue::from_int(value as i64)) } fn visit_u8(self, value: u8) -> Result where E: de::Error, { - Ok(AttributeValue::from_int(value as usize)) + Ok(AttributeValue::from_int(value as i64)) } fn visit_u16(self, value: u16) -> Result where E: de::Error, { - Ok(AttributeValue::from_int(value as usize)) + Ok(AttributeValue::from_int(value as i64)) } fn visit_u32(self, value: u32) -> Result where E: de::Error, { - Ok(AttributeValue::from_int(value as usize)) + Ok(AttributeValue::from_int(value as i64)) } fn visit_u64(self, value: u64) -> Result where E: de::Error, { - Ok(AttributeValue::from_int(value as usize)) + Ok(AttributeValue::from_int(value as i64)) + } + + fn visit_f32(self, value: f32) -> Result + where + E: de::Error, + { + Ok(AttributeValue::from_float(value as f64)) + } + + fn visit_f64(self, value: f64) -> Result + where + E: de::Error, + { + Ok(AttributeValue::from_float(value as f64)) } fn visit_str(self, s: &str) -> Result diff --git a/shared-lib/lib-ot/tests/node/mod.rs b/shared-lib/lib-ot/tests/node/mod.rs index 42fd074dce..dd3f7c446f 100644 --- a/shared-lib/lib-ot/tests/node/mod.rs +++ b/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; diff --git a/shared-lib/lib-ot/tests/node/operation_attribute_test.rs b/shared-lib/lib-ot/tests/node/operation_attribute_test.rs new file mode 100644 index 0000000000..77690e267e --- /dev/null +++ b/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); +} diff --git a/shared-lib/lib-ot/tests/node/script.rs b/shared-lib/lib-ot/tests/node/script.rs index 14c2a09881..a8a35b8ab9 100644 --- a/shared-lib/lib-ot/tests/node/script.rs +++ b/shared-lib/lib-ot/tests/node/script.rs @@ -47,6 +47,10 @@ pub enum NodeScript { path: Path, expected: Option, }, + 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);