From 8f5134305e98a41a2bbb21360815c8339a76bdc9 Mon Sep 17 00:00:00 2001 From: appflowy Date: Thu, 8 Sep 2022 17:38:11 +0800 Subject: [PATCH] refactor: generic insert_nodes method --- .../lib-ot/src/core/document/document.rs | 7 ++- .../lib-ot/src/core/document/position.rs | 37 +++++++++--- .../lib-ot/src/core/document/transaction.rs | 60 ++++++++++++++++++- shared-lib/lib-ot/src/errors.rs | 1 + shared-lib/lib-ot/tests/main.rs | 40 ++++++------- 5 files changed, 112 insertions(+), 33 deletions(-) diff --git a/shared-lib/lib-ot/src/core/document/document.rs b/shared-lib/lib-ot/src/core/document/document.rs index 76fb7ed3fa..95508237a4 100644 --- a/shared-lib/lib-ot/src/core/document/document.rs +++ b/shared-lib/lib-ot/src/core/document/document.rs @@ -23,7 +23,8 @@ impl DocumentTree { DocumentTree { arena, root } } - pub fn node_at_path(&self, path: &Path) -> Option { + pub fn node_at_path>(&self, path: T) -> Option { + let path = path.into(); if path.is_empty() { return Some(self.root); } @@ -120,8 +121,12 @@ impl DocumentTree { } fn apply_insert(&mut self, path: &Path, nodes: &[NodeSubTree]) -> Result<(), OTError> { + + let parent_path = &path.0[0..(path.0.len() - 1)]; let last_index = path.0[path.0.len() - 1]; + + let parent_node = self .node_at_path(&Path(parent_path.to_vec())) .ok_or_else(|| ErrorBuilder::new(OTErrorCode::PathNotFound).build())?; diff --git a/shared-lib/lib-ot/src/core/document/position.rs b/shared-lib/lib-ot/src/core/document/position.rs index 54ead9c28a..697bde8177 100644 --- a/shared-lib/lib-ot/src/core/document/position.rs +++ b/shared-lib/lib-ot/src/core/document/position.rs @@ -9,12 +9,37 @@ impl std::ops::Deref for Path { } } -impl AsRef for usize { - fn as_ref(&self) -> &Path { - todo!() +impl std::convert::Into for usize { + fn into(self) -> Path { + Path(vec![self]) } } +impl std::convert::Into for &usize { + fn into(self) -> Path { + Path(vec![*self]) + } +} + +impl std::convert::Into for &Path { + fn into(self) -> Path { + self.clone() + } +} + +impl From> for Path { + fn from(v: Vec) -> Self { + Path(v) + } +} + +impl From<&Vec> for Path { + fn from(values: &Vec) -> Self { + Path(values.clone()) + } +} + + impl Path { // delta is default to be 1 pub fn transform(pre_insert_path: &Path, b: &Path, offset: i64) -> Path { @@ -44,9 +69,3 @@ impl Path { Path(prefix) } } - -impl From> for Path { - fn from(v: Vec) -> Self { - Path(v) - } -} diff --git a/shared-lib/lib-ot/src/core/document/transaction.rs b/shared-lib/lib-ot/src/core/document/transaction.rs index f08f828706..bede8ebe2f 100644 --- a/shared-lib/lib-ot/src/core/document/transaction.rs +++ b/shared-lib/lib-ot/src/core/document/transaction.rs @@ -26,13 +26,67 @@ impl<'a> TransactionBuilder<'a> { } } - pub fn insert_nodes_at_path(&mut self, path: &Path, nodes: &[NodeSubTree]) { + + /// + /// + /// # Arguments + /// + /// * `path`: the path that is used to save the nodes + /// * `nodes`: the nodes you will be save in the path + /// + /// # Examples + /// + /// ``` + /// // 0 + /// // -- 0 + /// // |-- text_1 + /// // |-- text_2 + /// use lib_ot::core::{DocumentTree, NodeSubTree, TransactionBuilder}; + /// let mut document = DocumentTree::new(); + /// let transaction = { + /// let mut tb = TransactionBuilder::new(&document); + /// tb.insert_nodes_at_path(0,vec![ NodeSubTree::new("text_1"), NodeSubTree::new("text_2")]); + /// tb.finalize() + /// }; + /// document.apply(transaction).unwrap(); + /// + /// document.node_at_path(vec![0, 0]); + /// ``` + /// + pub fn insert_nodes_at_path>(&mut self, path: T, nodes: Vec) { self.push(DocumentOperation::Insert { - path: path.clone(), - nodes: nodes.to_vec(), + path: path.into(), + nodes, }); } + /// + /// + /// # Arguments + /// + /// * `path`: the path that is used to save the nodes + /// * `node`: the node data will be saved in the path + /// + /// # Examples + /// + /// ``` + /// // 0 + /// // -- 0 + /// // |-- text + /// use lib_ot::core::{DocumentTree, NodeSubTree, TransactionBuilder}; + /// let mut document = DocumentTree::new(); + /// let transaction = { + /// let mut tb = TransactionBuilder::new(&document); + /// tb.insert_node_at_path(0, NodeSubTree::new("text")); + /// tb.finalize() + /// }; + /// document.apply(transaction).unwrap(); + /// ``` + /// + pub fn insert_node_at_path>(&mut self, path: T, node: NodeSubTree) { + self.insert_nodes_at_path(path, vec![node]); + } + pub fn update_attributes_at_path(&mut self, path: &Path, attributes: HashMap>) { let mut old_attributes: HashMap> = HashMap::new(); let node = self.document.node_at_path(path).unwrap(); diff --git a/shared-lib/lib-ot/src/errors.rs b/shared-lib/lib-ot/src/errors.rs index eb313c784f..449c662883 100644 --- a/shared-lib/lib-ot/src/errors.rs +++ b/shared-lib/lib-ot/src/errors.rs @@ -75,6 +75,7 @@ pub enum OTErrorCode { RevisionIDConflict, Internal, PathNotFound, + PathIsEmpty, } pub struct ErrorBuilder { diff --git a/shared-lib/lib-ot/tests/main.rs b/shared-lib/lib-ot/tests/main.rs index 49a986ab6e..8ac6aae55a 100644 --- a/shared-lib/lib-ot/tests/main.rs +++ b/shared-lib/lib-ot/tests/main.rs @@ -13,13 +13,13 @@ fn test_documents() { let mut document = DocumentTree::new(); let transaction = { let mut tb = TransactionBuilder::new(&document); - tb.insert_nodes_at_path(&vec![0].into(), &[NodeSubTree::new("text")]); + tb.insert_node_at_path(0, NodeSubTree::new("text")); tb.finalize() }; document.apply(transaction).unwrap(); - assert!(document.node_at_path(&vec![0].into()).is_some()); - let node = document.node_at_path(&vec![0].into()).unwrap(); + assert!(document.node_at_path(0).is_some()); + let node = document.node_at_path(0).unwrap(); let node_data = document.arena.get(node).unwrap().get(); assert_eq!(node_data.node_type, "text"); @@ -39,7 +39,7 @@ fn test_documents() { tb.finalize() }; document.apply(transaction).unwrap(); - assert!(document.node_at_path(&vec![0].into()).is_none()); + assert!(document.node_at_path(0).is_none()); } #[test] @@ -47,16 +47,16 @@ fn test_inserts_nodes() { let mut document = DocumentTree::new(); let transaction = { let mut tb = TransactionBuilder::new(&document); - tb.insert_nodes_at_path(&vec![0].into(), &[NodeSubTree::new("text")]); - tb.insert_nodes_at_path(&vec![1].into(), &[NodeSubTree::new("text")]); - tb.insert_nodes_at_path(&vec![2].into(), &[NodeSubTree::new("text")]); + tb.insert_node_at_path(0, NodeSubTree::new("text")); + tb.insert_node_at_path(1, NodeSubTree::new("text")); + tb.insert_node_at_path(2, NodeSubTree::new("text")); tb.finalize() }; document.apply(transaction).unwrap(); let transaction = { let mut tb = TransactionBuilder::new(&document); - tb.insert_nodes_at_path(&vec![1].into(), &[NodeSubTree::new("text")]); + tb.insert_node_at_path(1, NodeSubTree::new("text")); tb.finalize() }; document.apply(transaction).unwrap(); @@ -67,14 +67,14 @@ fn test_inserts_subtrees() { let mut document = DocumentTree::new(); let transaction = { let mut tb = TransactionBuilder::new(&document); - tb.insert_nodes_at_path( - &vec![0].into(), - &[NodeSubTree { + tb.insert_node_at_path( + 0, + NodeSubTree { node_type: "text".into(), attributes: NodeAttributes::new(), delta: None, children: vec![NodeSubTree::new("image")], - }], + }, ); tb.finalize() }; @@ -90,9 +90,9 @@ fn test_update_nodes() { let mut document = DocumentTree::new(); let transaction = { let mut tb = TransactionBuilder::new(&document); - tb.insert_nodes_at_path(&vec![0].into(), &[NodeSubTree::new("text")]); - tb.insert_nodes_at_path(&vec![1].into(), &[NodeSubTree::new("text")]); - tb.insert_nodes_at_path(&vec![2].into(), &[NodeSubTree::new("text")]); + tb.insert_node_at_path(&vec![0], NodeSubTree::new("text")); + tb.insert_node_at_path(&vec![1], NodeSubTree::new("text")); + tb.insert_node_at_path(vec![2], NodeSubTree::new("text")); tb.finalize() }; document.apply(transaction).unwrap(); @@ -115,9 +115,9 @@ fn test_delete_nodes() { let mut document = DocumentTree::new(); let transaction = { let mut tb = TransactionBuilder::new(&document); - tb.insert_nodes_at_path(&vec![0].into(), &[NodeSubTree::new("text")]); - tb.insert_nodes_at_path(&vec![1].into(), &[NodeSubTree::new("text")]); - tb.insert_nodes_at_path(&vec![2].into(), &[NodeSubTree::new("text")]); + tb.insert_node_at_path(0, NodeSubTree::new("text")); + tb.insert_node_at_path(1, NodeSubTree::new("text")); + tb.insert_node_at_path(2, NodeSubTree::new("text")); tb.finalize() }; document.apply(transaction).unwrap(); @@ -138,8 +138,8 @@ fn test_errors() { let mut document = DocumentTree::new(); let transaction = { let mut tb = TransactionBuilder::new(&document); - tb.insert_nodes_at_path(&vec![0].into(), &[NodeSubTree::new("text")]); - tb.insert_nodes_at_path(&vec![100].into(), &[NodeSubTree::new("text")]); + tb.insert_node_at_path(0, NodeSubTree::new("text")); + tb.insert_node_at_path(100, NodeSubTree::new("text")); tb.finalize() }; let result = document.apply(transaction);