Merge pull request #1023 from AppFlowy-IO/feat/node_documentation

chore: update node documentation
This commit is contained in:
Nathan.fooo 2022-09-11 12:57:56 +08:00 committed by GitHub
commit d368ba78e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 148 additions and 108 deletions

View File

@ -4,7 +4,7 @@ use crate::errors::OTError;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Default, Clone, Serialize, Deserialize, Eq, PartialEq)] #[derive(Default, Clone, Serialize, Deserialize, Eq, PartialEq)]
pub struct Node { pub struct NodeData {
#[serde(rename = "type")] #[serde(rename = "type")]
pub node_type: String, pub node_type: String,
@ -15,48 +15,64 @@ pub struct Node {
pub body: NodeBody, pub body: NodeBody,
#[serde(skip_serializing_if = "Vec::is_empty")] #[serde(skip_serializing_if = "Vec::is_empty")]
pub children: Vec<Node>, pub children: Vec<NodeData>,
} }
impl Node { impl NodeData {
pub fn new<T: ToString>(node_type: T) -> Node { pub fn new<T: ToString>(node_type: T) -> NodeData {
Node { NodeData {
node_type: node_type.to_string(), node_type: node_type.to_string(),
..Default::default() ..Default::default()
} }
} }
} }
/// Builder for [`NodeData`]
pub struct NodeBuilder { pub struct NodeBuilder {
node: Node, node: NodeData,
} }
impl NodeBuilder { impl NodeBuilder {
pub fn new<T: ToString>(node_type: T) -> Self { pub fn new<T: ToString>(node_type: T) -> Self {
Self { Self {
node: Node::new(node_type.to_string()), node: NodeData::new(node_type.to_string()),
} }
} }
pub fn add_node(mut self, node: Node) -> Self { /// Appends a new node to the end of the builder's node children.
pub fn add_node(mut self, node: NodeData) -> 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
} }
pub fn build(self) -> Node {
/// Returns the builder's node
pub fn build(self) -> NodeData {
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,16 +157,18 @@ impl NodeBodyChangeset {
} }
} }
/// [`Node`] represents as a leaf in the [`NodeTree`].
///
#[derive(Clone, Eq, PartialEq, Debug)] #[derive(Clone, Eq, PartialEq, Debug)]
pub struct NodeData { pub struct Node {
pub node_type: String, pub node_type: String,
pub body: NodeBody, pub body: NodeBody,
pub attributes: NodeAttributes, pub attributes: NodeAttributes,
} }
impl NodeData { impl Node {
pub fn new(node_type: &str) -> NodeData { pub fn new(node_type: &str) -> Node {
NodeData { Node {
node_type: node_type.into(), node_type: node_type.into(),
attributes: NodeAttributes::new(), attributes: NodeAttributes::new(),
body: NodeBody::Empty, body: NodeBody::Empty,
@ -161,8 +185,8 @@ impl NodeData {
} }
} }
impl std::convert::From<Node> for NodeData { impl std::convert::From<NodeData> for Node {
fn from(node: Node) -> Self { fn from(node: NodeData) -> Self {
Self { Self {
node_type: node.node_type, node_type: node.node_type,
attributes: node.attributes, attributes: node.attributes,
@ -171,8 +195,8 @@ impl std::convert::From<Node> for NodeData {
} }
} }
impl std::convert::From<&Node> for NodeData { impl std::convert::From<&NodeData> for Node {
fn from(node: &Node) -> Self { fn from(node: &NodeData) -> Self {
Self { Self {
node_type: node.node_type.clone(), node_type: node.node_type.clone(),
attributes: node.attributes.clone(), attributes: node.attributes.clone(),

View File

@ -3,8 +3,9 @@ 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<Node>,
root: NodeId, root: NodeId,
} }
@ -17,11 +18,11 @@ impl Default for NodeTree {
impl NodeTree { impl NodeTree {
pub fn new() -> NodeTree { pub fn new() -> NodeTree {
let mut arena = Arena::new(); let mut arena = Arena::new();
let root = arena.new_node(NodeData::new("root")); let root = arena.new_node(Node::new("root"));
NodeTree { arena, root } NodeTree { arena, root }
} }
pub fn get_node_data(&self, node_id: NodeId) -> Option<&NodeData> { pub fn get_node(&self, node_id: NodeId) -> Option<&Node> {
Some(self.arena.get(node_id)?.get()) Some(self.arena.get(node_id)?.get())
} }
@ -29,8 +30,8 @@ impl NodeTree {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use lib_ot::core::{NodeOperation, NodeTree, Node, Path}; /// use lib_ot::core::{NodeOperation, NodeTree, NodeData, Path};
/// let nodes = vec![Node::new("text".to_string())]; /// let nodes = vec![NodeData::new("text".to_string())];
/// let root_path: Path = vec![0].into(); /// let root_path: Path = vec![0].into();
/// let op = NodeOperation::Insert {path: root_path.clone(),nodes }; /// let op = NodeOperation::Insert {path: root_path.clone(),nodes };
/// ///
@ -91,15 +92,15 @@ impl NodeTree {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use lib_ot::core::{NodeOperation, NodeTree, Node, Path}; /// use lib_ot::core::{NodeOperation, NodeTree, NodeData, Path};
/// let node = Node::new("text".to_string()); /// let node = NodeData::new("text".to_string());
/// let inserted_path: Path = vec![0].into(); /// let inserted_path: Path = vec![0].into();
/// ///
/// let mut node_tree = NodeTree::new(); /// let mut node_tree = NodeTree::new();
/// node_tree.apply_op(&NodeOperation::Insert {path: inserted_path.clone(),nodes: vec![node.clone()] }).unwrap(); /// node_tree.apply_op(&NodeOperation::Insert {path: inserted_path.clone(),nodes: vec![node.clone()] }).unwrap();
/// ///
/// let inserted_note = node_tree.node_at_path(&inserted_path).unwrap(); /// let inserted_note = node_tree.node_at_path(&inserted_path).unwrap();
/// let inserted_data = node_tree.get_node_data(inserted_note).unwrap(); /// let inserted_data = node_tree.get_node(inserted_note).unwrap();
/// assert_eq!(inserted_data.node_type, node.node_type); /// assert_eq!(inserted_data.node_type, node.node_type);
/// ``` /// ```
pub fn child_from_node_at_index(&self, node_id: NodeId, index: usize) -> Option<NodeId> { pub fn child_from_node_at_index(&self, node_id: NodeId, index: usize) -> Option<NodeId> {
@ -113,7 +114,7 @@ impl NodeTree {
None None
} }
pub fn children_from_node(&self, node_id: NodeId) -> Children<'_, NodeData> { pub fn children_from_node(&self, node_id: NodeId) -> Children<'_, Node> {
node_id.children(&self.arena) node_id.children(&self.arena)
} }
@ -131,7 +132,7 @@ impl NodeTree {
} }
} }
pub fn following_siblings(&self, node_id: NodeId) -> FollowingSiblings<'_, NodeData> { pub fn following_siblings(&self, node_id: NodeId) -> FollowingSiblings<'_, Node> {
node_id.following_siblings(&self.arena) node_id.following_siblings(&self.arena)
} }
@ -145,13 +146,16 @@ 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
fn insert_nodes(&mut self, path: &Path, nodes: &[Node]) -> Result<(), OTError> { ///
/// returns error if the path is empty
///
fn insert_nodes(&mut self, path: &Path, nodes: &[NodeData]) -> Result<(), OTError> {
debug_assert!(!path.is_empty()); debug_assert!(!path.is_empty());
if path.is_empty() { if path.is_empty() {
return Err(OTErrorCode::PathIsEmpty.into()); return Err(OTErrorCode::PathIsEmpty.into());
@ -166,7 +170,27 @@ impl NodeTree {
self.insert_nodes_at_index(parent_node, last_index, nodes) self.insert_nodes_at_index(parent_node, last_index, nodes)
} }
fn insert_nodes_at_index(&mut self, parent: NodeId, index: usize, insert_children: &[Node]) -> Result<(), OTError> { /// Inserts nodes before the node with node_id
///
fn insert_nodes_before(&mut self, node_id: &NodeId, nodes: &[NodeData]) {
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: &[NodeData],
) -> 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);
return Ok(()); return Ok(());
@ -181,38 +205,28 @@ 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: &[NodeData]) {
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 { self.mut_node_at_path(path, |node| {
let child_id = self.arena.new_node(child.into()); let new_attributes = NodeAttributes::compose(&node.attributes, attributes)?;
before.insert_before(child_id, &mut self.arena); node.attributes = new_attributes;
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| {
let new_attributes = NodeAttributes::compose(&node_data.attributes, attributes)?;
node_data.attributes = new_attributes;
Ok(()) Ok(())
}) })
} }
fn delete_node(&mut self, path: &Path, nodes: &[Node]) -> Result<(), OTError> { fn delete_node(&mut self, path: &Path, nodes: &[NodeData]) -> Result<(), OTError> {
let mut update_node = self let mut update_node = self
.node_at_path(path) .node_at_path(path)
.ok_or_else(|| ErrorBuilder::new(OTErrorCode::PathNotFound).build())?; .ok_or_else(|| ErrorBuilder::new(OTErrorCode::PathNotFound).build())?;
@ -230,15 +244,15 @@ impl NodeTree {
} }
fn update_body(&mut self, path: &Path, changeset: &NodeBodyChangeset) -> Result<(), OTError> { fn update_body(&mut self, path: &Path, changeset: &NodeBodyChangeset) -> Result<(), OTError> {
self.mut_node_at_path(path, |node_data| { self.mut_node_at_path(path, |node| {
node_data.apply_body_changeset(changeset); node.apply_body_changeset(changeset);
Ok(()) Ok(())
}) })
} }
fn mut_node_at_path<F>(&mut self, path: &Path, f: F) -> Result<(), OTError> fn mut_node_at_path<F>(&mut self, path: &Path, f: F) -> Result<(), OTError>
where where
F: Fn(&mut NodeData) -> Result<(), OTError>, F: Fn(&mut Node) -> Result<(), OTError>,
{ {
let node_id = self let node_id = self
.node_at_path(path) .node_at_path(path)
@ -246,8 +260,8 @@ impl NodeTree {
match self.arena.get_mut(node_id) { match self.arena.get_mut(node_id) {
None => tracing::warn!("The path: {:?} does not contain any nodes", path), None => tracing::warn!("The path: {:?} does not contain any nodes", path),
Some(node) => { Some(node) => {
let node_data = node.get_mut(); let node = node.get_mut();
let _ = f(node_data)?; let _ = f(node)?;
} }
} }
Ok(()) Ok(())

View File

@ -1,37 +1,37 @@
use crate::core::document::operation_serde::*; use crate::core::document::operation_serde::*;
use crate::core::document::path::Path; use crate::core::document::path::Path;
use crate::core::{Node, NodeAttributes, NodeBodyChangeset}; use crate::core::{NodeAttributes, NodeBodyChangeset, NodeData};
#[derive(Clone, serde::Serialize, serde::Deserialize)] #[derive(Clone, serde::Serialize, serde::Deserialize)]
#[serde(tag = "op")] #[serde(tag = "op")]
pub enum NodeOperation { pub enum NodeOperation {
#[serde(rename = "insert")] #[serde(rename = "insert")]
Insert { path: Path, nodes: Vec<Node> }, Insert { path: Path, nodes: Vec<NodeData> },
#[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<NodeData> },
} }
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(),
}, },
} }
} }
@ -101,12 +101,12 @@ impl NodeOperation {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::core::{Node, NodeAttributes, NodeBodyChangeset, NodeBuilder, NodeOperation, Path, TextDelta}; use crate::core::{NodeAttributes, NodeBodyChangeset, NodeBuilder, NodeData, NodeOperation, Path, TextDelta};
#[test] #[test]
fn test_serialize_insert_operation() { fn test_serialize_insert_operation() {
let insert = NodeOperation::Insert { let insert = NodeOperation::Insert {
path: Path(vec![0, 1]), path: Path(vec![0, 1]),
nodes: vec![Node::new("text".to_owned())], nodes: vec![NodeData::new("text".to_owned())],
}; };
let result = serde_json::to_string(&insert).unwrap(); let result = serde_json::to_string(&insert).unwrap();
assert_eq!(result, r#"{"op":"insert","path":[0,1],"nodes":[{"type":"text"}]}"#); assert_eq!(result, r#"{"op":"insert","path":[0,1],"nodes":[{"type":"text"}]}"#);
@ -116,7 +116,9 @@ mod tests {
fn test_serialize_insert_sub_trees() { fn test_serialize_insert_sub_trees() {
let insert = NodeOperation::Insert { let insert = NodeOperation::Insert {
path: Path(vec![0, 1]), path: Path(vec![0, 1]),
nodes: vec![NodeBuilder::new("text").add_node(Node::new("text".to_owned())).build()], nodes: vec![NodeBuilder::new("text")
.add_node(NodeData::new("text".to_owned()))
.build()],
}; };
let result = serde_json::to_string(&insert).unwrap(); let result = serde_json::to_string(&insert).unwrap();
assert_eq!( assert_eq!(
@ -127,7 +129,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 +147,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,
}; };

View File

@ -1,5 +1,5 @@
use crate::core::document::path::Path; use crate::core::document::path::Path;
use crate::core::{Node, NodeAttributes, NodeOperation, NodeTree}; use crate::core::{NodeAttributes, NodeData, NodeOperation, NodeTree};
use indextree::NodeId; use indextree::NodeId;
pub struct Transaction { pub struct Transaction {
@ -38,17 +38,17 @@ impl<'a> TransactionBuilder<'a> {
/// // -- 0 (root) /// // -- 0 (root)
/// // 0 -- text_1 /// // 0 -- text_1
/// // 1 -- text_2 /// // 1 -- text_2
/// use lib_ot::core::{NodeTree, Node, TransactionBuilder}; /// use lib_ot::core::{NodeTree, NodeData, TransactionBuilder};
/// let mut node_tree = NodeTree::new(); /// let mut node_tree = NodeTree::new();
/// let transaction = TransactionBuilder::new(&node_tree) /// let transaction = TransactionBuilder::new(&node_tree)
/// .insert_nodes_at_path(0,vec![ Node::new("text_1"), Node::new("text_2")]) /// .insert_nodes_at_path(0,vec![ NodeData::new("text_1"), NodeData::new("text_2")])
/// .finalize(); /// .finalize();
/// node_tree.apply(transaction).unwrap(); /// node_tree.apply(transaction).unwrap();
/// ///
/// node_tree.node_at_path(vec![0, 0]); /// node_tree.node_at_path(vec![0, 0]);
/// ``` /// ```
/// ///
pub fn insert_nodes_at_path<T: Into<Path>>(self, path: T, nodes: Vec<Node>) -> Self { pub fn insert_nodes_at_path<T: Into<Path>>(self, path: T, nodes: Vec<NodeData>) -> Self {
self.push(NodeOperation::Insert { self.push(NodeOperation::Insert {
path: path.into(), path: path.into(),
nodes, nodes,
@ -68,22 +68,22 @@ impl<'a> TransactionBuilder<'a> {
/// // 0 /// // 0
/// // -- 0 /// // -- 0
/// // |-- text /// // |-- text
/// use lib_ot::core::{NodeTree, Node, TransactionBuilder}; /// use lib_ot::core::{NodeTree, NodeData, TransactionBuilder};
/// let mut node_tree = NodeTree::new(); /// let mut node_tree = NodeTree::new();
/// let transaction = TransactionBuilder::new(&node_tree) /// let transaction = TransactionBuilder::new(&node_tree)
/// .insert_node_at_path(0, Node::new("text")) /// .insert_node_at_path(0, NodeData::new("text"))
/// .finalize(); /// .finalize();
/// node_tree.apply(transaction).unwrap(); /// node_tree.apply(transaction).unwrap();
/// ``` /// ```
/// ///
pub fn insert_node_at_path<T: Into<Path>>(self, path: T, node: Node) -> Self { pub fn insert_node_at_path<T: Into<Path>>(self, path: T, node: NodeData) -> Self {
self.insert_nodes_at_path(path, vec![node]) self.insert_nodes_at_path(path, vec![node])
} }
pub fn update_attributes_at_path(self, path: &Path, attributes: NodeAttributes) -> Self { pub fn update_attributes_at_path(self, path: &Path, attributes: NodeAttributes) -> Self {
let mut old_attributes = NodeAttributes::new(); let mut old_attributes = NodeAttributes::new();
let node = self.node_tree.node_at_path(path).unwrap(); let node = self.node_tree.node_at_path(path).unwrap();
let node_data = self.node_tree.get_node_data(node).unwrap(); let node_data = self.node_tree.get_node(node).unwrap();
for key in attributes.keys() { for key in attributes.keys() {
let old_attrs = &node_data.attributes; let old_attrs = &node_data.attributes;
@ -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,
@ -118,15 +118,15 @@ impl<'a> TransactionBuilder<'a> {
self self
} }
fn get_deleted_nodes(&self, node_id: NodeId) -> Node { fn get_deleted_nodes(&self, node_id: NodeId) -> NodeData {
let node_data = self.node_tree.get_node_data(node_id).unwrap(); let node_data = self.node_tree.get_node(node_id).unwrap();
let mut children = vec![]; let mut children = vec![];
self.node_tree.children_from_node(node_id).for_each(|child_id| { self.node_tree.children_from_node(node_id).for_each(|child_id| {
children.push(self.get_deleted_nodes(child_id)); children.push(self.get_deleted_nodes(child_id));
}); });
Node { NodeData {
node_type: node_data.node_type.clone(), node_type: node_data.node_type.clone(),
attributes: node_data.attributes.clone(), attributes: node_data.attributes.clone(),
body: node_data.body.clone(), body: node_data.body.clone(),

View File

@ -1,11 +1,11 @@
use lib_ot::core::{Node, NodeAttributes, NodeTree, Path, TransactionBuilder}; use lib_ot::core::{NodeAttributes, NodeData, NodeTree, Path, TransactionBuilder};
pub enum NodeScript { pub enum NodeScript {
InsertNode { path: Path, node: Node }, InsertNode { path: Path, node: NodeData },
InsertAttributes { path: Path, attributes: NodeAttributes }, InsertAttributes { path: Path, attributes: NodeAttributes },
DeleteNode { path: Path }, DeleteNode { path: Path },
AssertNumberOfChildrenAtPath { path: Option<Path>, len: usize }, AssertNumberOfChildrenAtPath { path: Option<Path>, len: usize },
AssertNode { path: Path, expected: Option<Node> }, AssertNode { path: Path, expected: Option<NodeData> },
} }
pub struct NodeTest { pub struct NodeTest {
@ -52,7 +52,7 @@ impl NodeTest {
match node_id { match node_id {
None => assert!(node_id.is_none()), None => assert!(node_id.is_none()),
Some(node_id) => { Some(node_id) => {
let node_data = self.node_tree.get_node_data(node_id).cloned(); let node_data = self.node_tree.get_node(node_id).cloned();
assert_eq!(node_data, expected.and_then(|e| Some(e.into()))); assert_eq!(node_data, expected.and_then(|e| Some(e.into())));
} }
} }

View File

@ -1,11 +1,11 @@
use crate::node::script::NodeScript::*; use crate::node::script::NodeScript::*;
use crate::node::script::NodeTest; use crate::node::script::NodeTest;
use lib_ot::core::{Node, NodeBuilder, Path}; use lib_ot::core::{NodeBuilder, NodeData, Path};
#[test] #[test]
fn node_insert_test() { fn node_insert_test() {
let mut test = NodeTest::new(); let mut test = NodeTest::new();
let inserted_node = Node::new("text"); let inserted_node = NodeData::new("text");
let path: Path = 0.into(); let path: Path = 0.into();
let scripts = vec![ let scripts = vec![
InsertNode { InsertNode {
@ -23,7 +23,7 @@ fn node_insert_test() {
#[test] #[test]
fn node_insert_node_with_children_test() { fn node_insert_node_with_children_test() {
let mut test = NodeTest::new(); let mut test = NodeTest::new();
let inserted_node = NodeBuilder::new("text").add_node(Node::new("image")).build(); let inserted_node = NodeBuilder::new("text").add_node(NodeData::new("image")).build();
let path: Path = 0.into(); let path: Path = 0.into();
let scripts = vec![ let scripts = vec![
InsertNode { InsertNode {
@ -42,13 +42,13 @@ fn node_insert_node_with_children_test() {
fn node_insert_multi_nodes_test() { fn node_insert_multi_nodes_test() {
let mut test = NodeTest::new(); let mut test = NodeTest::new();
let path_1: Path = 0.into(); let path_1: Path = 0.into();
let node_1 = Node::new("text_1"); let node_1 = NodeData::new("text_1");
let path_2: Path = 1.into(); let path_2: Path = 1.into();
let node_2 = Node::new("text_2"); let node_2 = NodeData::new("text_2");
let path_3: Path = 2.into(); let path_3: Path = 2.into();
let node_3 = Node::new("text_3"); let node_3 = NodeData::new("text_3");
let scripts = vec![ let scripts = vec![
InsertNode { InsertNode {
@ -83,14 +83,14 @@ fn node_insert_multi_nodes_test() {
fn node_insert_node_in_ordered_nodes_test() { fn node_insert_node_in_ordered_nodes_test() {
let mut test = NodeTest::new(); let mut test = NodeTest::new();
let path_1: Path = 0.into(); let path_1: Path = 0.into();
let node_1 = Node::new("text_1"); let node_1 = NodeData::new("text_1");
let path_2: Path = 1.into(); let path_2: Path = 1.into();
let node_2_1 = Node::new("text_2_1"); let node_2_1 = NodeData::new("text_2_1");
let node_2_2 = Node::new("text_2_2"); let node_2_2 = NodeData::new("text_2_2");
let path_3: Path = 2.into(); let path_3: Path = 2.into();
let node_3 = Node::new("text_3"); let node_3 = NodeData::new("text_3");
let path_4: Path = 3.into(); let path_4: Path = 3.into();
@ -138,7 +138,7 @@ fn node_insert_node_in_ordered_nodes_test() {
fn node_insert_with_attributes_test() { fn node_insert_with_attributes_test() {
let mut test = NodeTest::new(); let mut test = NodeTest::new();
let path: Path = 0.into(); let path: Path = 0.into();
let mut inserted_node = Node::new("text"); let mut inserted_node = NodeData::new("text");
inserted_node.attributes.insert("bold", true); inserted_node.attributes.insert("bold", true);
inserted_node.attributes.insert("underline", true); inserted_node.attributes.insert("underline", true);
@ -162,7 +162,7 @@ fn node_insert_with_attributes_test() {
#[test] #[test]
fn node_delete_test() { fn node_delete_test() {
let mut test = NodeTest::new(); let mut test = NodeTest::new();
let inserted_node = Node::new("text"); let inserted_node = NodeData::new("text");
let path: Path = 0.into(); let path: Path = 0.into();
let scripts = vec![ let scripts = vec![