瀏覽代碼

feat: serialize

Vincent Chan 2 年之前
父節點
當前提交
bb8e0485cd

+ 27 - 17
shared-lib/lib-ot/src/core/document/document.rs

@@ -1,5 +1,7 @@
 use crate::core::document::position::Position;
-use crate::core::{DocumentOperation, NodeAttributes, NodeData, OperationTransform, TextDelta, Transaction};
+use crate::core::{
+    DocumentOperation, NodeAttributes, NodeData, NodeSubTree, OperationTransform, TextDelta, Transaction,
+};
 use crate::errors::{ErrorBuilder, OTError, OTErrorCode};
 use indextree::{Arena, NodeId};
 
@@ -100,40 +102,36 @@ impl DocumentTree {
         }
     }
 
-    fn apply_insert(&mut self, path: &Position, nodes: &Vec<NodeData>) -> Result<(), OTError> {
+    fn apply_insert(&mut self, path: &Position, nodes: &Vec<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(&Position(parent_path.to_vec()))
             .ok_or(ErrorBuilder::new(OTErrorCode::PathNotFound).build())?;
-        let mut inserted_nodes = Vec::new();
+        // let mut inserted_nodes = Vec::new();
+        //
+        // for node in nodes {
+        //     inserted_nodes.push(self.arena.new_node(node.to_node_data()));
+        // }
 
-        for node in nodes {
-            inserted_nodes.push(self.arena.new_node(node.clone()));
-        }
-
-        self.insert_child_at_index(parent_node, last_index, &inserted_nodes)
+        self.insert_child_at_index(parent_node, last_index, nodes.as_ref())
     }
 
     fn insert_child_at_index(
         &mut self,
         parent: NodeId,
         index: usize,
-        insert_children: &[NodeId],
+        insert_children: &[NodeSubTree],
     ) -> Result<(), OTError> {
         if index == 0 && parent.children(&self.arena).next().is_none() {
-            for id in insert_children {
-                parent.append(*id, &mut self.arena);
-            }
+            self.append_subtree(&parent, insert_children);
             return Ok(());
         }
 
         let children_length = parent.children(&self.arena).fold(0, |counter, _| counter + 1);
 
         if index == children_length {
-            for id in insert_children {
-                parent.append(*id, &mut self.arena);
-            }
+            self.append_subtree(&parent, insert_children);
             return Ok(());
         }
 
@@ -141,10 +139,22 @@ impl DocumentTree {
             .child_at_index_of_path(parent, index)
             .ok_or(ErrorBuilder::new(OTErrorCode::PathNotFound).build())?;
 
+        self.insert_subtree_before(&node_to_insert, insert_children);
+        Ok(())
+    }
+
+    fn append_subtree(&mut self, parent: &NodeId, insert_children: &[NodeSubTree]) {
+        for child in insert_children {
+            let child_id = self.arena.new_node(child.to_node_data());
+            parent.append(child_id, &mut self.arena);
+        }
+    }
+
+    fn insert_subtree_before(&mut self, before: &NodeId, insert_children: &[NodeSubTree]) {
         for id in insert_children {
-            node_to_insert.insert_before(*id, &mut self.arena);
+            let child_id = self.arena.new_node(id.to_node_data());
+            before.insert_before(child_id, &mut self.arena);
         }
-        Ok(())
     }
 
     fn apply_update(&mut self, path: &Position, attributes: &NodeAttributes) -> Result<(), OTError> {

+ 51 - 10
shared-lib/lib-ot/src/core/document/document_operation.rs

@@ -1,21 +1,21 @@
 use crate::core::document::position::Position;
-use crate::core::{NodeAttributes, NodeData, TextDelta};
+use crate::core::{NodeAttributes, NodeSubTree, TextDelta};
 
 #[derive(Clone, serde::Serialize, serde::Deserialize)]
+#[serde(tag = "type")]
 pub enum DocumentOperation {
-    Insert {
-        path: Position,
-        nodes: Vec<NodeData>,
-    },
+    #[serde(rename = "insert-operation")]
+    Insert { path: Position, nodes: Vec<NodeSubTree> },
+    #[serde(rename = "update-operation")]
     Update {
         path: Position,
         attributes: NodeAttributes,
+        #[serde(rename = "oldAttributes")]
         old_attributes: NodeAttributes,
     },
-    Delete {
-        path: Position,
-        nodes: Vec<NodeData>,
-    },
+    #[serde(rename = "delete-operation")]
+    Delete { path: Position, nodes: Vec<NodeSubTree> },
+    #[serde(rename = "text-edit-operation")]
     TextEdit {
         path: Position,
         delta: TextDelta,
@@ -101,7 +101,7 @@ impl DocumentOperation {
 
 #[cfg(test)]
 mod tests {
-    use crate::core::Position;
+    use crate::core::{Delta, DocumentOperation, NodeAttributes, NodeSubTree, Position};
 
     #[test]
     fn test_transform_path_1() {
@@ -150,4 +150,45 @@ mod tests {
             vec![0, 6]
         );
     }
+
+    #[test]
+    fn test_serialize_insert_operation() {
+        let insert = DocumentOperation::Insert {
+            path: Position(vec![0, 1]),
+            nodes: vec![NodeSubTree::new("text")],
+        };
+        let result = serde_json::to_string(&insert).unwrap();
+        assert_eq!(
+            result,
+            r#"{"type":"insert-operation","path":[0,1],"nodes":[{"node_type":"text","attributes":{}}]}"#
+        );
+    }
+
+    #[test]
+    fn test_serialize_update_operation() {
+        let insert = DocumentOperation::Update {
+            path: Position(vec![0, 1]),
+            attributes: NodeAttributes::new(),
+            old_attributes: NodeAttributes::new(),
+        };
+        let result = serde_json::to_string(&insert).unwrap();
+        assert_eq!(
+            result,
+            r#"{"type":"update-operation","path":[0,1],"attributes":{},"oldAttributes":{}}"#
+        );
+    }
+
+    #[test]
+    fn test_serialize_text_edit_operation() {
+        let insert = DocumentOperation::TextEdit {
+            path: Position(vec![0, 1]),
+            delta: Delta::new(),
+            inverted: Delta::new(),
+        };
+        let result = serde_json::to_string(&insert).unwrap();
+        assert_eq!(
+            result,
+            r#"{"type":"text-edit-operation","path":[0,1],"delta":[],"inverted":[]}"#
+        );
+    }
 }

+ 30 - 1
shared-lib/lib-ot/src/core/document/node.rs

@@ -1,6 +1,6 @@
 use crate::core::{NodeAttributes, TextDelta};
 
-#[derive(Clone, serde::Serialize, serde::Deserialize)]
+#[derive(Clone)]
 pub struct NodeData {
     pub node_type: String,
     pub attributes: NodeAttributes,
@@ -16,3 +16,32 @@ impl NodeData {
         }
     }
 }
+
+#[derive(Clone, serde::Serialize, serde::Deserialize)]
+pub struct NodeSubTree {
+    pub node_type: String,
+    pub attributes: NodeAttributes,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub delta: Option<TextDelta>,
+    #[serde(skip_serializing_if = "Vec::is_empty")]
+    pub children: Vec<Box<NodeSubTree>>,
+}
+
+impl NodeSubTree {
+    pub fn new(node_type: &str) -> NodeSubTree {
+        NodeSubTree {
+            node_type: node_type.into(),
+            attributes: NodeAttributes::new(),
+            delta: None,
+            children: Vec::new(),
+        }
+    }
+
+    pub fn to_node_data(&self) -> NodeData {
+        NodeData {
+            node_type: self.node_type.clone(),
+            attributes: self.attributes.clone(),
+            delta: self.delta.clone(),
+        }
+    }
+}

+ 11 - 5
shared-lib/lib-ot/src/core/document/transaction.rs

@@ -1,5 +1,5 @@
 use crate::core::document::position::Position;
-use crate::core::{DocumentOperation, DocumentTree, NodeAttributes, NodeData};
+use crate::core::{DocumentOperation, DocumentTree, NodeAttributes, NodeSubTree};
 use std::collections::HashMap;
 
 pub struct Transaction {
@@ -25,7 +25,7 @@ impl<'a> TransactionBuilder<'a> {
         }
     }
 
-    pub fn insert_nodes_at_path(&mut self, path: &Position, nodes: &[NodeData]) {
+    pub fn insert_nodes_at_path(&mut self, path: &Position, nodes: &[NodeSubTree]) {
         self.push(DocumentOperation::Insert {
             path: path.clone(),
             nodes: nodes.to_vec(),
@@ -59,11 +59,17 @@ impl<'a> TransactionBuilder<'a> {
 
     pub fn delete_nodes_at_path(&mut self, path: &Position, length: usize) {
         let mut node = self.document.node_at_path(path).unwrap();
-        let mut deleted_nodes: Vec<NodeData> = Vec::new();
+        let mut deleted_nodes: Vec<NodeSubTree> = Vec::new();
 
         for _ in 0..length {
-            let data = self.document.arena.get(node).unwrap();
-            deleted_nodes.push(data.get().clone());
+            let node_data = self.document.arena.get(node).unwrap();
+            let data = node_data.get();
+            deleted_nodes.push(NodeSubTree {
+                node_type: data.node_type.clone(),
+                attributes: data.attributes.clone(),
+                delta: data.delta.clone(),
+                children: vec![],
+            });
             node = node.following_siblings(&self.document.arena).next().unwrap();
         }