mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: update node documentation
This commit is contained in:
parent
9142f5d870
commit
3c84e8df51
@ -27,6 +27,7 @@ impl Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builder for [`Node`]
|
||||||
pub struct NodeBuilder {
|
pub struct NodeBuilder {
|
||||||
node: Node,
|
node: Node,
|
||||||
}
|
}
|
||||||
@ -38,25 +39,40 @@ impl NodeBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Appends a new node to the end of the builder's node children.
|
||||||
pub fn add_node(mut self, node: Node) -> Self {
|
pub fn add_node(mut self, node: Node) -> Self {
|
||||||
self.node.children.push(node);
|
self.node.children.push(node);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Inserts attributes to the builder's node.
|
||||||
|
///
|
||||||
|
/// The attributes will be replace if they shared the same key
|
||||||
pub fn insert_attribute(mut self, key: AttributeKey, value: AttributeValue) -> Self {
|
pub fn insert_attribute(mut self, key: AttributeKey, value: AttributeValue) -> Self {
|
||||||
self.node.attributes.insert(key, value);
|
self.node.attributes.insert(key, value);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_body(mut self, body: NodeBody) -> Self {
|
/// Inserts a body to the builder's node
|
||||||
|
pub fn insert_body(mut self, body: NodeBody) -> Self {
|
||||||
self.node.body = body;
|
self.node.body = body;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the builder's node
|
||||||
pub fn build(self) -> Node {
|
pub fn build(self) -> Node {
|
||||||
self.node
|
self.node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// NodeBody represents as the node's data.
|
||||||
|
///
|
||||||
|
/// For the moment, the NodeBody can be Empty or Delta. We can extend
|
||||||
|
/// the NodeBody by adding a new enum type.
|
||||||
|
///
|
||||||
|
/// The NodeBody implements the [`OperationTransform`] trait which means it can perform
|
||||||
|
/// compose, transform and invert.
|
||||||
|
///
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum NodeBody {
|
pub enum NodeBody {
|
||||||
Empty,
|
Empty,
|
||||||
@ -79,6 +95,7 @@ impl NodeBody {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl OperationTransform for NodeBody {
|
impl OperationTransform for NodeBody {
|
||||||
|
/// Only the same enum variant can perform the compose operation.
|
||||||
fn compose(&self, other: &Self) -> Result<Self, OTError>
|
fn compose(&self, other: &Self) -> Result<Self, OTError>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
@ -93,6 +110,7 @@ impl OperationTransform for NodeBody {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Only the same enum variant can perform the transform operation.
|
||||||
fn transform(&self, other: &Self) -> Result<(Self, Self), OTError>
|
fn transform(&self, other: &Self) -> Result<(Self, Self), OTError>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
@ -107,6 +125,7 @@ impl OperationTransform for NodeBody {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Only the same enum variant can perform the invert operation.
|
||||||
fn invert(&self, other: &Self) -> Self {
|
fn invert(&self, other: &Self) -> Self {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Delta(l), Delta(r)) => Delta(l.invert(r)),
|
(Delta(l), Delta(r)) => Delta(l.invert(r)),
|
||||||
@ -119,6 +138,9 @@ impl OperationTransform for NodeBody {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the changeset of the [`NodeBody`]
|
||||||
|
///
|
||||||
|
/// Each NodeBody except the Empty should have its corresponding changeset variant.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum NodeBodyChangeset {
|
pub enum NodeBodyChangeset {
|
||||||
Delta { delta: TextDelta, inverted: TextDelta },
|
Delta { delta: TextDelta, inverted: TextDelta },
|
||||||
@ -135,6 +157,8 @@ impl NodeBodyChangeset {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// [`NodeData`] represents as a leaf data in the [`NodeTree`].
|
||||||
|
///
|
||||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||||
pub struct NodeData {
|
pub struct NodeData {
|
||||||
pub node_type: String,
|
pub node_type: String,
|
||||||
|
@ -3,6 +3,7 @@ use crate::core::{Node, NodeAttributes, NodeBodyChangeset, NodeData, NodeOperati
|
|||||||
use crate::errors::{ErrorBuilder, OTError, OTErrorCode};
|
use crate::errors::{ErrorBuilder, OTError, OTErrorCode};
|
||||||
use indextree::{Arena, Children, FollowingSiblings, NodeId};
|
use indextree::{Arena, Children, FollowingSiblings, NodeId};
|
||||||
|
|
||||||
|
///
|
||||||
pub struct NodeTree {
|
pub struct NodeTree {
|
||||||
arena: Arena<NodeData>,
|
arena: Arena<NodeData>,
|
||||||
root: NodeId,
|
root: NodeId,
|
||||||
@ -145,12 +146,15 @@ impl NodeTree {
|
|||||||
pub fn apply_op(&mut self, op: &NodeOperation) -> Result<(), OTError> {
|
pub fn apply_op(&mut self, op: &NodeOperation) -> Result<(), OTError> {
|
||||||
match op {
|
match op {
|
||||||
NodeOperation::Insert { path, nodes } => self.insert_nodes(path, nodes),
|
NodeOperation::Insert { path, nodes } => self.insert_nodes(path, nodes),
|
||||||
NodeOperation::Update { path, attributes, .. } => self.update_node(path, attributes),
|
NodeOperation::UpdateAttributes { path, attributes, .. } => self.update_attributes(path, attributes),
|
||||||
|
NodeOperation::UpdateBody { path, changeset } => self.update_body(path, changeset),
|
||||||
NodeOperation::Delete { path, nodes } => self.delete_node(path, nodes),
|
NodeOperation::Delete { path, nodes } => self.delete_node(path, nodes),
|
||||||
NodeOperation::EditBody { path, changeset: body } => self.update_body(path, body),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Inserts nodes at given path
|
||||||
|
///
|
||||||
|
/// returns error if the path is empty
|
||||||
|
///
|
||||||
fn insert_nodes(&mut self, path: &Path, nodes: &[Node]) -> Result<(), OTError> {
|
fn insert_nodes(&mut self, path: &Path, nodes: &[Node]) -> Result<(), OTError> {
|
||||||
debug_assert!(!path.is_empty());
|
debug_assert!(!path.is_empty());
|
||||||
if path.is_empty() {
|
if path.is_empty() {
|
||||||
@ -166,6 +170,21 @@ impl NodeTree {
|
|||||||
self.insert_nodes_at_index(parent_node, last_index, nodes)
|
self.insert_nodes_at_index(parent_node, last_index, nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Inserts nodes before the node with node_id
|
||||||
|
///
|
||||||
|
fn insert_nodes_before(&mut self, node_id: &NodeId, nodes: &[Node]) {
|
||||||
|
for node in nodes {
|
||||||
|
let new_node_id = self.arena.new_node(node.into());
|
||||||
|
if node_id.is_removed(&self.arena) {
|
||||||
|
tracing::warn!("Node:{:?} is remove before insert", node_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_id.insert_before(new_node_id, &mut self.arena);
|
||||||
|
self.append_nodes(&new_node_id, &node.children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn insert_nodes_at_index(&mut self, parent: NodeId, index: usize, insert_children: &[Node]) -> Result<(), OTError> {
|
fn insert_nodes_at_index(&mut self, parent: NodeId, index: usize, insert_children: &[Node]) -> Result<(), OTError> {
|
||||||
if index == 0 && parent.children(&self.arena).next().is_none() {
|
if index == 0 && parent.children(&self.arena).next().is_none() {
|
||||||
self.append_nodes(&parent, insert_children);
|
self.append_nodes(&parent, insert_children);
|
||||||
@ -181,30 +200,20 @@ impl NodeTree {
|
|||||||
.child_from_node_at_index(parent, index)
|
.child_from_node_at_index(parent, index)
|
||||||
.ok_or_else(|| ErrorBuilder::new(OTErrorCode::PathNotFound).build())?;
|
.ok_or_else(|| ErrorBuilder::new(OTErrorCode::PathNotFound).build())?;
|
||||||
|
|
||||||
self.insert_subtree_before(&node_to_insert, insert_children);
|
self.insert_nodes_before(&node_to_insert, insert_children);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// recursive append the subtrees to the node
|
fn append_nodes(&mut self, parent: &NodeId, nodes: &[Node]) {
|
||||||
fn append_nodes(&mut self, parent: &NodeId, insert_children: &[Node]) {
|
for node in nodes {
|
||||||
for child in insert_children {
|
let new_node_id = self.arena.new_node(node.into());
|
||||||
let child_id = self.arena.new_node(child.into());
|
parent.append(new_node_id, &mut self.arena);
|
||||||
parent.append(child_id, &mut self.arena);
|
|
||||||
|
|
||||||
self.append_nodes(&child_id, &child.children);
|
self.append_nodes(&new_node_id, &node.children);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_subtree_before(&mut self, before: &NodeId, insert_children: &[Node]) {
|
fn update_attributes(&mut self, path: &Path, attributes: &NodeAttributes) -> Result<(), OTError> {
|
||||||
for child in insert_children {
|
|
||||||
let child_id = self.arena.new_node(child.into());
|
|
||||||
before.insert_before(child_id, &mut self.arena);
|
|
||||||
|
|
||||||
self.append_nodes(&child_id, &child.children);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_node(&mut self, path: &Path, attributes: &NodeAttributes) -> Result<(), OTError> {
|
|
||||||
self.mut_node_at_path(path, |node_data| {
|
self.mut_node_at_path(path, |node_data| {
|
||||||
let new_attributes = NodeAttributes::compose(&node_data.attributes, attributes)?;
|
let new_attributes = NodeAttributes::compose(&node_data.attributes, attributes)?;
|
||||||
node_data.attributes = new_attributes;
|
node_data.attributes = new_attributes;
|
||||||
|
@ -9,29 +9,29 @@ pub enum NodeOperation {
|
|||||||
Insert { path: Path, nodes: Vec<Node> },
|
Insert { path: Path, nodes: Vec<Node> },
|
||||||
|
|
||||||
#[serde(rename = "update")]
|
#[serde(rename = "update")]
|
||||||
Update {
|
UpdateAttributes {
|
||||||
path: Path,
|
path: Path,
|
||||||
attributes: NodeAttributes,
|
attributes: NodeAttributes,
|
||||||
#[serde(rename = "oldAttributes")]
|
#[serde(rename = "oldAttributes")]
|
||||||
old_attributes: NodeAttributes,
|
old_attributes: NodeAttributes,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[serde(rename = "delete")]
|
|
||||||
Delete { path: Path, nodes: Vec<Node> },
|
|
||||||
|
|
||||||
#[serde(rename = "edit-body")]
|
#[serde(rename = "edit-body")]
|
||||||
#[serde(serialize_with = "serialize_edit_body")]
|
#[serde(serialize_with = "serialize_edit_body")]
|
||||||
// #[serde(deserialize_with = "operation_serde::deserialize_edit_body")]
|
// #[serde(deserialize_with = "operation_serde::deserialize_edit_body")]
|
||||||
EditBody { path: Path, changeset: NodeBodyChangeset },
|
UpdateBody { path: Path, changeset: NodeBodyChangeset },
|
||||||
|
|
||||||
|
#[serde(rename = "delete")]
|
||||||
|
Delete { path: Path, nodes: Vec<Node> },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeOperation {
|
impl NodeOperation {
|
||||||
pub fn path(&self) -> &Path {
|
pub fn path(&self) -> &Path {
|
||||||
match self {
|
match self {
|
||||||
NodeOperation::Insert { path, .. } => path,
|
NodeOperation::Insert { path, .. } => path,
|
||||||
NodeOperation::Update { path, .. } => path,
|
NodeOperation::UpdateAttributes { path, .. } => path,
|
||||||
NodeOperation::Delete { path, .. } => path,
|
NodeOperation::Delete { path, .. } => path,
|
||||||
NodeOperation::EditBody { path, .. } => path,
|
NodeOperation::UpdateBody { path, .. } => path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn invert(&self) -> NodeOperation {
|
pub fn invert(&self) -> NodeOperation {
|
||||||
@ -40,11 +40,11 @@ impl NodeOperation {
|
|||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
nodes: nodes.clone(),
|
nodes: nodes.clone(),
|
||||||
},
|
},
|
||||||
NodeOperation::Update {
|
NodeOperation::UpdateAttributes {
|
||||||
path,
|
path,
|
||||||
attributes,
|
attributes,
|
||||||
old_attributes,
|
old_attributes,
|
||||||
} => NodeOperation::Update {
|
} => NodeOperation::UpdateAttributes {
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
attributes: old_attributes.clone(),
|
attributes: old_attributes.clone(),
|
||||||
old_attributes: attributes.clone(),
|
old_attributes: attributes.clone(),
|
||||||
@ -53,7 +53,7 @@ impl NodeOperation {
|
|||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
nodes: nodes.clone(),
|
nodes: nodes.clone(),
|
||||||
},
|
},
|
||||||
NodeOperation::EditBody { path, changeset: body } => NodeOperation::EditBody {
|
NodeOperation::UpdateBody { path, changeset: body } => NodeOperation::UpdateBody {
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
changeset: body.inverted(),
|
changeset: body.inverted(),
|
||||||
},
|
},
|
||||||
@ -65,11 +65,11 @@ impl NodeOperation {
|
|||||||
path,
|
path,
|
||||||
nodes: nodes.clone(),
|
nodes: nodes.clone(),
|
||||||
},
|
},
|
||||||
NodeOperation::Update {
|
NodeOperation::UpdateAttributes {
|
||||||
attributes,
|
attributes,
|
||||||
old_attributes,
|
old_attributes,
|
||||||
..
|
..
|
||||||
} => NodeOperation::Update {
|
} => NodeOperation::UpdateAttributes {
|
||||||
path,
|
path,
|
||||||
attributes: attributes.clone(),
|
attributes: attributes.clone(),
|
||||||
old_attributes: old_attributes.clone(),
|
old_attributes: old_attributes.clone(),
|
||||||
@ -78,9 +78,9 @@ impl NodeOperation {
|
|||||||
path,
|
path,
|
||||||
nodes: nodes.clone(),
|
nodes: nodes.clone(),
|
||||||
},
|
},
|
||||||
NodeOperation::EditBody { path, changeset: body } => NodeOperation::EditBody {
|
NodeOperation::UpdateBody { path, changeset } => NodeOperation::UpdateBody {
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
changeset: body.clone(),
|
changeset: changeset.clone(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,7 +127,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialize_update_operation() {
|
fn test_serialize_update_operation() {
|
||||||
let insert = NodeOperation::Update {
|
let insert = NodeOperation::UpdateAttributes {
|
||||||
path: Path(vec![0, 1]),
|
path: Path(vec![0, 1]),
|
||||||
attributes: NodeAttributes::new(),
|
attributes: NodeAttributes::new(),
|
||||||
old_attributes: NodeAttributes::new(),
|
old_attributes: NodeAttributes::new(),
|
||||||
@ -145,7 +145,7 @@ mod tests {
|
|||||||
delta: TextDelta::new(),
|
delta: TextDelta::new(),
|
||||||
inverted: TextDelta::new(),
|
inverted: TextDelta::new(),
|
||||||
};
|
};
|
||||||
let insert = NodeOperation::EditBody {
|
let insert = NodeOperation::UpdateBody {
|
||||||
path: Path(vec![0, 1]),
|
path: Path(vec![0, 1]),
|
||||||
changeset,
|
changeset,
|
||||||
};
|
};
|
||||||
|
@ -92,7 +92,7 @@ impl<'a> TransactionBuilder<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.push(NodeOperation::Update {
|
self.push(NodeOperation::UpdateAttributes {
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
attributes,
|
attributes,
|
||||||
old_attributes,
|
old_attributes,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user