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::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 crate::errors::{ErrorBuilder, OTError, OTErrorCode};
|
||||||
use indextree::{Arena, NodeId};
|
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 parent_path = &path.0[0..(path.0.len() - 1)];
|
||||||
let last_index = path.0[path.0.len() - 1];
|
let last_index = path.0[path.0.len() - 1];
|
||||||
let parent_node = self
|
let parent_node = self
|
||||||
.node_at_path(&Position(parent_path.to_vec()))
|
.node_at_path(&Position(parent_path.to_vec()))
|
||||||
.ok_or(ErrorBuilder::new(OTErrorCode::PathNotFound).build())?;
|
.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 {
|
self.insert_child_at_index(parent_node, last_index, nodes.as_ref())
|
||||||
inserted_nodes.push(self.arena.new_node(node.clone()));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.insert_child_at_index(parent_node, last_index, &inserted_nodes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_child_at_index(
|
fn insert_child_at_index(
|
||||||
&mut self,
|
&mut self,
|
||||||
parent: NodeId,
|
parent: NodeId,
|
||||||
index: usize,
|
index: usize,
|
||||||
insert_children: &[NodeId],
|
insert_children: &[NodeSubTree],
|
||||||
) -> Result<(), OTError> {
|
) -> Result<(), OTError> {
|
||||||
if index == 0 && parent.children(&self.arena).next().is_none() {
|
if index == 0 && parent.children(&self.arena).next().is_none() {
|
||||||
for id in insert_children {
|
self.append_subtree(&parent, insert_children);
|
||||||
parent.append(*id, &mut self.arena);
|
|
||||||
}
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let children_length = parent.children(&self.arena).fold(0, |counter, _| counter + 1);
|
let children_length = parent.children(&self.arena).fold(0, |counter, _| counter + 1);
|
||||||
|
|
||||||
if index == children_length {
|
if index == children_length {
|
||||||
for id in insert_children {
|
self.append_subtree(&parent, insert_children);
|
||||||
parent.append(*id, &mut self.arena);
|
|
||||||
}
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,12 +139,24 @@ impl DocumentTree {
|
|||||||
.child_at_index_of_path(parent, index)
|
.child_at_index_of_path(parent, index)
|
||||||
.ok_or(ErrorBuilder::new(OTErrorCode::PathNotFound).build())?;
|
.ok_or(ErrorBuilder::new(OTErrorCode::PathNotFound).build())?;
|
||||||
|
|
||||||
for id in insert_children {
|
self.insert_subtree_before(&node_to_insert, insert_children);
|
||||||
node_to_insert.insert_before(*id, &mut self.arena);
|
|
||||||
}
|
|
||||||
Ok(())
|
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> {
|
fn apply_update(&mut self, path: &Position, attributes: &NodeAttributes) -> Result<(), OTError> {
|
||||||
let update_node = self
|
let update_node = self
|
||||||
.node_at_path(path)
|
.node_at_path(path)
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
use crate::core::document::position::Position;
|
use crate::core::document::position::Position;
|
||||||
use crate::core::{NodeAttributes, NodeData, TextDelta};
|
use crate::core::{NodeAttributes, NodeSubTree, TextDelta};
|
||||||
|
|
||||||
#[derive(Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
pub enum DocumentOperation {
|
pub enum DocumentOperation {
|
||||||
Insert {
|
#[serde(rename = "insert-operation")]
|
||||||
path: Position,
|
Insert { path: Position, nodes: Vec<NodeSubTree> },
|
||||||
nodes: Vec<NodeData>,
|
#[serde(rename = "update-operation")]
|
||||||
},
|
|
||||||
Update {
|
Update {
|
||||||
path: Position,
|
path: Position,
|
||||||
attributes: NodeAttributes,
|
attributes: NodeAttributes,
|
||||||
|
#[serde(rename = "oldAttributes")]
|
||||||
old_attributes: NodeAttributes,
|
old_attributes: NodeAttributes,
|
||||||
},
|
},
|
||||||
Delete {
|
#[serde(rename = "delete-operation")]
|
||||||
path: Position,
|
Delete { path: Position, nodes: Vec<NodeSubTree> },
|
||||||
nodes: Vec<NodeData>,
|
#[serde(rename = "text-edit-operation")]
|
||||||
},
|
|
||||||
TextEdit {
|
TextEdit {
|
||||||
path: Position,
|
path: Position,
|
||||||
delta: TextDelta,
|
delta: TextDelta,
|
||||||
@ -101,7 +101,7 @@ impl DocumentOperation {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::core::Position;
|
use crate::core::{Delta, DocumentOperation, NodeAttributes, NodeSubTree, Position};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_transform_path_1() {
|
fn test_transform_path_1() {
|
||||||
@ -150,4 +150,45 @@ mod tests {
|
|||||||
vec![0, 6]
|
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};
|
use crate::core::{NodeAttributes, TextDelta};
|
||||||
|
|
||||||
#[derive(Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone)]
|
||||||
pub struct NodeData {
|
pub struct NodeData {
|
||||||
pub node_type: String,
|
pub node_type: String,
|
||||||
pub attributes: NodeAttributes,
|
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::document::position::Position;
|
||||||
use crate::core::{DocumentOperation, DocumentTree, NodeAttributes, NodeData};
|
use crate::core::{DocumentOperation, DocumentTree, NodeAttributes, NodeSubTree};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct Transaction {
|
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 {
|
self.push(DocumentOperation::Insert {
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
nodes: nodes.to_vec(),
|
nodes: nodes.to_vec(),
|
||||||
@ -59,11 +59,17 @@ impl<'a> TransactionBuilder<'a> {
|
|||||||
|
|
||||||
pub fn delete_nodes_at_path(&mut self, path: &Position, length: usize) {
|
pub fn delete_nodes_at_path(&mut self, path: &Position, length: usize) {
|
||||||
let mut node = self.document.node_at_path(path).unwrap();
|
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 {
|
for _ in 0..length {
|
||||||
let data = self.document.arena.get(node).unwrap();
|
let node_data = self.document.arena.get(node).unwrap();
|
||||||
deleted_nodes.push(data.get().clone());
|
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();
|
node = node.following_siblings(&self.document.arena).next().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user