mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: serialize
This commit is contained in:
parent
ef65551340
commit
bb8e0485cd
@ -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,12 +139,24 @@ impl DocumentTree {
|
||||
.child_at_index_of_path(parent, index)
|
||||
.ok_or(ErrorBuilder::new(OTErrorCode::PathNotFound).build())?;
|
||||
|
||||
for id in insert_children {
|
||||
node_to_insert.insert_before(*id, &mut self.arena);
|
||||
}
|
||||
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 {
|
||||
let child_id = self.arena.new_node(id.to_node_data());
|
||||
before.insert_before(child_id, &mut self.arena);
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_update(&mut self, path: &Position, attributes: &NodeAttributes) -> Result<(), OTError> {
|
||||
let update_node = self
|
||||
.node_at_path(path)
|
||||
|
@ -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":[]}"#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user