Ver Fonte

chore: extension for transaction

appflowy há 2 anos atrás
pai
commit
ec574c413a

+ 0 - 2
shared-lib/lib-ot/Cargo.toml

@@ -8,8 +8,6 @@ edition = "2018"
 [dependencies]
 [dependencies]
 bytecount = "0.6.0"
 bytecount = "0.6.0"
 serde = { version = "1.0", features = ["derive", "rc"] }
 serde = { version = "1.0", features = ["derive", "rc"] }
-#flowy-revision = { path = "../../frontend/rust-lib/flowy-revision" }
-#protobuf = {version = "2.18.0"}
 tokio = { version = "1", features = ["sync"] }
 tokio = { version = "1", features = ["sync"] }
 dashmap = "5"
 dashmap = "5"
 md5 = "0.7.0"
 md5 = "0.7.0"

+ 2 - 1
shared-lib/lib-ot/src/core/interval.rs

@@ -1,3 +1,4 @@
+use serde::{Deserialize, Serialize};
 use std::{
 use std::{
     cmp::{max, min},
     cmp::{max, min},
     fmt,
     fmt,
@@ -9,7 +10,7 @@ use std::{
 ///
 ///
 /// It is an invariant that `start <= end`. An interval where `end < start` is
 /// It is an invariant that `start <= end`. An interval where `end < start` is
 /// considered empty.
 /// considered empty.
-#[derive(Clone, Copy, PartialEq, Eq)]
+#[derive(Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
 pub struct Interval {
 pub struct Interval {
     pub start: usize,
     pub start: usize,
     pub end: usize,
     pub end: usize,

+ 1 - 0
shared-lib/lib-ot/src/core/node_tree/mod.rs

@@ -6,6 +6,7 @@ mod operation;
 mod operation_serde;
 mod operation_serde;
 mod path;
 mod path;
 mod transaction;
 mod transaction;
+mod transaction_serde;
 mod tree;
 mod tree;
 
 
 pub use node::*;
 pub use node::*;

+ 0 - 12
shared-lib/lib-ot/src/core/node_tree/node_serde.rs

@@ -33,18 +33,6 @@ where
             formatter.write_str("Expect NodeBody")
             formatter.write_str("Expect NodeBody")
         }
         }
 
 
-        fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
-        where
-            A: de::SeqAccess<'de>,
-        {
-            let mut delta = TextOperations::default();
-            while let Some(op) = seq.next_element()? {
-                delta.add(op);
-            }
-            Ok(Body::Delta(delta))
-        }
-
-        #[inline]
         fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
         fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
         where
         where
             V: MapAccess<'de>,
             V: MapAccess<'de>,

+ 4 - 3
shared-lib/lib-ot/src/core/node_tree/operation.rs

@@ -1,3 +1,4 @@
+use super::operation_serde::{deserialize_changeset, serialize_changeset};
 use crate::core::{Changeset, NodeData, Path};
 use crate::core::{Changeset, NodeData, Path};
 use crate::errors::OTError;
 use crate::errors::OTError;
 use serde::{Deserialize, Serialize};
 use serde::{Deserialize, Serialize};
@@ -10,8 +11,8 @@ pub enum NodeOperation {
     Insert { path: Path, nodes: Vec<NodeData> },
     Insert { path: Path, nodes: Vec<NodeData> },
 
 
     #[serde(rename = "update")]
     #[serde(rename = "update")]
-    // #[serde(serialize_with = "serialize_edit_body")]
-    // #[serde(deserialize_with = "deserialize_edit_body")]
+    #[serde(serialize_with = "serialize_changeset")]
+    #[serde(deserialize_with = "deserialize_changeset")]
     Update { path: Path, changeset: Changeset },
     Update { path: Path, changeset: Changeset },
 
 
     #[serde(rename = "delete")]
     #[serde(rename = "delete")]
@@ -82,7 +83,7 @@ impl NodeOperation {
     ///
     ///
     /// op_1.transform(&mut op_2);
     /// op_1.transform(&mut op_2);
     /// assert_eq!(serde_json::to_string(&op_2).unwrap(), r#"{"op":"insert","path":[0,2],"nodes":[{"type":"text_2"}]}"#);
     /// assert_eq!(serde_json::to_string(&op_2).unwrap(), r#"{"op":"insert","path":[0,2],"nodes":[{"type":"text_2"}]}"#);
-    ///
+    /// assert_eq!(serde_json::to_string(&op_1).unwrap(), r#"{"op":"insert","path":[0,1],"nodes":[{"type":"text_1"}]}"#);
     /// ```
     /// ```
     pub fn transform(&self, other: &mut NodeOperation) {
     pub fn transform(&self, other: &mut NodeOperation) {
         match self {
         match self {

+ 2 - 6
shared-lib/lib-ot/src/core/node_tree/operation_serde.rs

@@ -7,8 +7,7 @@ use std::convert::TryInto;
 use std::fmt;
 use std::fmt;
 use std::marker::PhantomData;
 use std::marker::PhantomData;
 
 
-#[allow(dead_code)]
-pub fn serialize_edit_body<S>(path: &Path, changeset: &Changeset, serializer: S) -> Result<S::Ok, S::Error>
+pub fn serialize_changeset<S>(path: &Path, changeset: &Changeset, serializer: S) -> Result<S::Ok, S::Error>
 where
 where
     S: Serializer,
     S: Serializer,
 {
 {
@@ -34,8 +33,7 @@ where
     }
     }
 }
 }
 
 
-#[allow(dead_code)]
-pub fn deserialize_edit_body<'de, D>(deserializer: D) -> Result<(Path, Changeset), D::Error>
+pub fn deserialize_changeset<'de, D>(deserializer: D) -> Result<(Path, Changeset), D::Error>
 where
 where
     D: Deserializer<'de>,
     D: Deserializer<'de>,
 {
 {
@@ -73,7 +71,6 @@ where
                         if path.is_some() {
                         if path.is_some() {
                             return Err(de::Error::duplicate_field("path"));
                             return Err(de::Error::duplicate_field("path"));
                         }
                         }
-
                         path = Some(map.next_value::<Path>()?)
                         path = Some(map.next_value::<Path>()?)
                     }
                     }
                     other => {
                     other => {
@@ -93,7 +90,6 @@ where
     deserializer.deserialize_any(ChangesetVisitor())
     deserializer.deserialize_any(ChangesetVisitor())
 }
 }
 
 
-#[allow(dead_code)]
 struct DeltaChangeset<E> {
 struct DeltaChangeset<E> {
     delta: Option<TextOperations>,
     delta: Option<TextOperations>,
     inverted: Option<TextOperations>,
     inverted: Option<TextOperations>,

+ 34 - 5
shared-lib/lib-ot/src/core/node_tree/transaction.rs

@@ -1,14 +1,41 @@
+use super::{Changeset, NodeOperations};
 use crate::core::attributes::AttributeHashMap;
 use crate::core::attributes::AttributeHashMap;
-use crate::core::{NodeData, NodeOperation, NodeTree, Path};
+use crate::core::{Interval, NodeData, NodeOperation, NodeTree, Path};
 use crate::errors::OTError;
 use crate::errors::OTError;
 use indextree::NodeId;
 use indextree::NodeId;
+use serde::{Deserialize, Serialize};
 use std::rc::Rc;
 use std::rc::Rc;
 
 
-use super::{Changeset, NodeOperations};
-
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone, Default, Serialize, Deserialize)]
 pub struct Transaction {
 pub struct Transaction {
-    operations: NodeOperations,
+    #[serde(flatten)]
+    pub operations: NodeOperations,
+
+    #[serde(default)]
+    #[serde(flatten)]
+    #[serde(skip_serializing_if = "Extension::is_empty")]
+    pub extension: Extension,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum Extension {
+    Empty,
+    TextSelection {
+        before_selection: Interval,
+        after_selection: Interval,
+    },
+}
+
+impl std::default::Default for Extension {
+    fn default() -> Self {
+        Extension::Empty
+    }
+}
+
+impl Extension {
+    fn is_empty(&self) -> bool {
+        matches!(self, Extension::Empty)
+    }
 }
 }
 
 
 impl Transaction {
 impl Transaction {
@@ -19,6 +46,7 @@ impl Transaction {
     pub fn from_operations<T: Into<NodeOperations>>(operations: T) -> Self {
     pub fn from_operations<T: Into<NodeOperations>>(operations: T) -> Self {
         Self {
         Self {
             operations: operations.into(),
             operations: operations.into(),
+            extension: Extension::Empty,
         }
         }
     }
     }
 
 
@@ -32,6 +60,7 @@ impl Transaction {
     /// the operations of the transaction will be transformed into the conflict operations.
     /// the operations of the transaction will be transformed into the conflict operations.
     pub fn transform(&self, other: &Transaction) -> Result<Transaction, OTError> {
     pub fn transform(&self, other: &Transaction) -> Result<Transaction, OTError> {
         let mut new_transaction = other.clone();
         let mut new_transaction = other.clone();
+        new_transaction.extension = self.extension.clone();
         for other_operation in new_transaction.iter_mut() {
         for other_operation in new_transaction.iter_mut() {
             let other_operation = Rc::make_mut(other_operation);
             let other_operation = Rc::make_mut(other_operation);
             for operation in self.operations.iter() {
             for operation in self.operations.iter() {

+ 29 - 0
shared-lib/lib-ot/src/core/node_tree/transaction_serde.rs

@@ -0,0 +1,29 @@
+use crate::core::Extension;
+use serde::ser::SerializeMap;
+use serde::Serializer;
+
+#[allow(dead_code)]
+pub fn serialize_extension<S>(extension: &Extension, serializer: S) -> Result<S::Ok, S::Error>
+where
+    S: Serializer,
+{
+    match extension {
+        Extension::Empty => {
+            let map = serializer.serialize_map(None)?;
+            map.end()
+        }
+        Extension::TextSelection {
+            before_selection,
+            after_selection,
+        } => {
+            let mut map = serializer.serialize_map(Some(2))?;
+            map.serialize_key("before_selection")?;
+            map.serialize_value(before_selection)?;
+
+            map.serialize_key("after_selection")?;
+            map.serialize_value(after_selection)?;
+
+            map.end()
+        }
+    }
+}

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

@@ -1,4 +1,5 @@
 mod editor_test;
 mod editor_test;
 mod operation_test;
 mod operation_test;
 mod script;
 mod script;
+mod serde_test;
 mod tree_test;
 mod tree_test;

+ 2 - 72
shared-lib/lib-ot/tests/node/operation_test.rs

@@ -1,77 +1,7 @@
 use crate::node::script::NodeScript::*;
 use crate::node::script::NodeScript::*;
 use crate::node::script::NodeTest;
 use crate::node::script::NodeTest;
-use lib_ot::core::{AttributeBuilder, Node};
-use lib_ot::{
-    core::{Changeset, NodeData, NodeDataBuilder, NodeOperation, Path},
-    text_delta::TextOperationBuilder,
-};
-
-#[test]
-fn operation_insert_node_serde_test() {
-    let insert = NodeOperation::Insert {
-        path: Path(vec![0, 1]),
-        nodes: vec![NodeData::new("text".to_owned())],
-    };
-    let result = serde_json::to_string(&insert).unwrap();
-    assert_eq!(result, r#"{"op":"insert","path":[0,1],"nodes":[{"type":"text"}]}"#);
-}
-
-#[test]
-fn operation_insert_node_with_children_serde_test() {
-    let node = NodeDataBuilder::new("text")
-        .add_node(NodeData::new("sub_text".to_owned()))
-        .build();
-
-    let insert = NodeOperation::Insert {
-        path: Path(vec![0, 1]),
-        nodes: vec![node],
-    };
-    assert_eq!(
-        serde_json::to_string(&insert).unwrap(),
-        r#"{"op":"insert","path":[0,1],"nodes":[{"type":"text","children":[{"type":"sub_text"}]}]}"#
-    );
-}
-#[test]
-fn operation_update_node_attributes_serde_test() {
-    let operation = NodeOperation::Update {
-        path: Path(vec![0, 1]),
-        changeset: Changeset::Attributes {
-            new: AttributeBuilder::new().insert("bold", true).build(),
-            old: AttributeBuilder::new().insert("bold", false).build(),
-        },
-    };
-
-    let result = serde_json::to_string(&operation).unwrap();
-    assert_eq!(
-        result,
-        r#"{"op":"update","path":[0,1],"changeset":{"attributes":{"new":{"bold":true},"old":{"bold":null}}}}"#
-    );
-}
-
-#[test]
-fn operation_update_node_body_serialize_test() {
-    let delta = TextOperationBuilder::new().insert("AppFlowy...").build();
-    let inverted = delta.invert_str("");
-    let changeset = Changeset::Delta { delta, inverted };
-    let insert = NodeOperation::Update {
-        path: Path(vec![0, 1]),
-        changeset,
-    };
-    let result = serde_json::to_string(&insert).unwrap();
-    assert_eq!(
-        result,
-        r#"{"op":"update","path":[0,1],"changeset":{"delta":{"delta":[{"insert":"AppFlowy..."}],"inverted":[{"delete":11}]}}}"#
-    );
-    //
-}
-
-#[test]
-fn operation_update_node_body_deserialize_test() {
-    let json_1 = r#"{"op":"update","path":[0,1],"changeset":{"delta":{"delta":[{"insert":"AppFlowy..."}],"inverted":[{"delete":11}]}}}"#;
-    let operation: NodeOperation = serde_json::from_str(json_1).unwrap();
-    let json_2 = serde_json::to_string(&operation).unwrap();
-    assert_eq!(json_1, json_2);
-}
+use lib_ot::core::Node;
+use lib_ot::core::{NodeDataBuilder, NodeOperation, Path};
 
 
 #[test]
 #[test]
 fn operation_insert_op_transform_test() {
 fn operation_insert_op_transform_test() {

+ 95 - 0
shared-lib/lib-ot/tests/node/serde_test.rs

@@ -0,0 +1,95 @@
+use lib_ot::core::{
+    AttributeBuilder, Changeset, Extension, Interval, NodeData, NodeDataBuilder, NodeOperation, Path, Transaction,
+};
+use lib_ot::text_delta::TextOperationBuilder;
+
+#[test]
+fn operation_insert_node_serde_test() {
+    let insert = NodeOperation::Insert {
+        path: Path(vec![0, 1]),
+        nodes: vec![NodeData::new("text".to_owned())],
+    };
+    let result = serde_json::to_string(&insert).unwrap();
+    assert_eq!(result, r#"{"op":"insert","path":[0,1],"nodes":[{"type":"text"}]}"#);
+}
+
+#[test]
+fn operation_insert_node_with_children_serde_test() {
+    let node = NodeDataBuilder::new("text")
+        .add_node(NodeData::new("sub_text".to_owned()))
+        .build();
+
+    let insert = NodeOperation::Insert {
+        path: Path(vec![0, 1]),
+        nodes: vec![node],
+    };
+    assert_eq!(
+        serde_json::to_string(&insert).unwrap(),
+        r#"{"op":"insert","path":[0,1],"nodes":[{"type":"text","children":[{"type":"sub_text"}]}]}"#
+    );
+}
+#[test]
+fn operation_update_node_attributes_serde_test() {
+    let operation = NodeOperation::Update {
+        path: Path(vec![0, 1]),
+        changeset: Changeset::Attributes {
+            new: AttributeBuilder::new().insert("bold", true).build(),
+            old: AttributeBuilder::new().insert("bold", false).build(),
+        },
+    };
+
+    let result = serde_json::to_string(&operation).unwrap();
+    assert_eq!(
+        result,
+        r#"{"op":"update","path":[0,1],"new":{"bold":true},"old":{"bold":null}}"#
+    );
+}
+
+#[test]
+fn operation_update_node_body_serialize_test() {
+    let delta = TextOperationBuilder::new().insert("AppFlowy...").build();
+    let inverted = delta.invert_str("");
+    let changeset = Changeset::Delta { delta, inverted };
+    let insert = NodeOperation::Update {
+        path: Path(vec![0, 1]),
+        changeset,
+    };
+    let result = serde_json::to_string(&insert).unwrap();
+    assert_eq!(
+        result,
+        r#"{"op":"update","path":[0,1],"delta":[{"insert":"AppFlowy..."}],"inverted":[{"delete":11}]}"#
+    );
+}
+
+#[test]
+fn operation_update_node_body_deserialize_test() {
+    let json_1 = r#"{"op":"update","path":[0,1],"delta":[{"insert":"AppFlowy..."}],"inverted":[{"delete":11}]}"#;
+    let operation: NodeOperation = serde_json::from_str(json_1).unwrap();
+    let json_2 = serde_json::to_string(&operation).unwrap();
+    assert_eq!(json_1, json_2);
+}
+
+#[test]
+fn transaction_serialize_test() {
+    let insert = NodeOperation::Insert {
+        path: Path(vec![0, 1]),
+        nodes: vec![NodeData::new("text".to_owned())],
+    };
+    let mut transaction = Transaction::from_operations(vec![insert]);
+    transaction.extension = Extension::TextSelection {
+        before_selection: Interval::new(0, 1),
+        after_selection: Interval::new(1, 2),
+    };
+    let json = serde_json::to_string(&transaction).unwrap();
+    assert_eq!(
+        json,
+        r#"{"operations":[{"op":"insert","path":[0,1],"nodes":[{"type":"text"}]}],"TextSelection":{"before_selection":{"start":0,"end":1},"after_selection":{"start":1,"end":2}}}"#
+    );
+}
+
+#[test]
+fn transaction_deserialize_test() {
+    let json = r#"{"operations":[{"op":"insert","path":[0,1],"nodes":[{"type":"text"}]}],"TextSelection":{"before_selection":{"start":0,"end":1},"after_selection":{"start":1,"end":2}}}"#;
+    let transaction: Transaction = serde_json::from_str(json).unwrap();
+    assert_eq!(transaction.operations.len(), 1);
+}