mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: support delete consecutive nodes on backend (#1877)
This commit is contained in:
@ -285,7 +285,7 @@ class _AutoCompletionInputState extends State<_AutoCompletionInput> {
|
|||||||
final transaction = widget.editorState.transaction;
|
final transaction = widget.editorState.transaction;
|
||||||
transaction.deleteNodesAtPath(
|
transaction.deleteNodesAtPath(
|
||||||
start,
|
start,
|
||||||
end.last - start.last,
|
end.last - start.last + 1,
|
||||||
);
|
);
|
||||||
await widget.editorState.apply(transaction);
|
await widget.editorState.apply(transaction);
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,16 @@ impl Path {
|
|||||||
pub fn is_root(&self) -> bool {
|
pub fn is_root(&self) -> bool {
|
||||||
self.0.len() == 1 && self.0[0] == 0
|
self.0.len() == 1 && self.0[0] == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn next(&self) -> Self {
|
||||||
|
let mut cloned_self = self.clone();
|
||||||
|
if !self.is_valid() {
|
||||||
|
return cloned_self;
|
||||||
|
}
|
||||||
|
let last = cloned_self.pop();
|
||||||
|
cloned_self.push(last.unwrap() + 1);
|
||||||
|
cloned_self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Deref for Path {
|
impl std::ops::Deref for Path {
|
||||||
|
@ -293,7 +293,13 @@ impl NodeTree {
|
|||||||
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, changeset } => self.update(&path, changeset),
|
NodeOperation::Update { path, changeset } => self.update(&path, changeset),
|
||||||
NodeOperation::Delete { path, nodes: _ } => self.delete_node(&path),
|
NodeOperation::Delete { path, nodes } => {
|
||||||
|
if nodes.is_empty() {
|
||||||
|
self.delete_node(&path)
|
||||||
|
} else {
|
||||||
|
self.delete_nodes(&path, nodes)
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Inserts nodes at given path
|
/// Inserts nodes at given path
|
||||||
@ -456,6 +462,32 @@ impl NodeTree {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes a node and the consecutive nodes behide it
|
||||||
|
///
|
||||||
|
/// if the nodes is empty, it will remove the single node at the path.
|
||||||
|
/// else it will remove the nodes at the path and the consecutive nodes behind it.
|
||||||
|
fn delete_nodes(&mut self, path: &Path, nodes: Vec<NodeData>) -> Result<(), OTError> {
|
||||||
|
if !path.is_valid() {
|
||||||
|
return Err(OTErrorCode::InvalidPath.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let node_id = self.node_id_at_path(path).ok_or_else(|| {
|
||||||
|
tracing::warn!("Can't find any node at path: {:?}", path);
|
||||||
|
OTError::internal().context("Can't find any node at path")
|
||||||
|
});
|
||||||
|
|
||||||
|
if node_id.is_err() {
|
||||||
|
return Err(OTErrorCode::PathNotFound.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 0..nodes.len() {
|
||||||
|
let res = self.delete_node(path);
|
||||||
|
res?
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Update the node at path with the `changeset`
|
/// Update the node at path with the `changeset`
|
||||||
///
|
///
|
||||||
/// Do nothing if there is no node at the path.
|
/// Do nothing if there is no node at the path.
|
||||||
|
@ -31,6 +31,11 @@ pub enum NodeScript {
|
|||||||
path: Path,
|
path: Path,
|
||||||
rev_id: usize,
|
rev_id: usize,
|
||||||
},
|
},
|
||||||
|
DeleteNodes {
|
||||||
|
path: Path,
|
||||||
|
node_data_list: Vec<NodeData>,
|
||||||
|
rev_id: usize,
|
||||||
|
},
|
||||||
AssertNumberOfChildrenAtPath {
|
AssertNumberOfChildrenAtPath {
|
||||||
path: Option<Path>,
|
path: Option<Path>,
|
||||||
expected: usize,
|
expected: usize,
|
||||||
@ -137,7 +142,17 @@ impl NodeTest {
|
|||||||
self.transform_transaction_if_need(&mut transaction, rev_id);
|
self.transform_transaction_if_need(&mut transaction, rev_id);
|
||||||
self.apply_transaction(transaction);
|
self.apply_transaction(transaction);
|
||||||
},
|
},
|
||||||
|
NodeScript::DeleteNodes {
|
||||||
|
path,
|
||||||
|
node_data_list,
|
||||||
|
rev_id,
|
||||||
|
} => {
|
||||||
|
let mut transaction = TransactionBuilder::new()
|
||||||
|
.delete_nodes_at_path(&self.node_tree, &path, node_data_list.len())
|
||||||
|
.build();
|
||||||
|
self.transform_transaction_if_need(&mut transaction, rev_id);
|
||||||
|
self.apply_transaction(transaction);
|
||||||
|
},
|
||||||
NodeScript::AssertNode { path, expected } => {
|
NodeScript::AssertNode { path, expected } => {
|
||||||
let node = self.node_tree.get_node_data_at_path(&path);
|
let node = self.node_tree.get_node_data_at_path(&path);
|
||||||
assert_eq!(node, expected.map(|e| e.into()));
|
assert_eq!(node, expected.map(|e| e.into()));
|
||||||
|
@ -349,6 +349,44 @@ fn node_delete_test() {
|
|||||||
test.run_scripts(scripts);
|
test.run_scripts(scripts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nodes_delete_test() {
|
||||||
|
let mut test = NodeTest::new();
|
||||||
|
let node_1 = NodeData::new("a");
|
||||||
|
let node_2 = NodeData::new("b");
|
||||||
|
let node_3 = NodeData::new("c");
|
||||||
|
let node_data_list = vec![node_1, node_2, node_3];
|
||||||
|
let path: Path = 0.into();
|
||||||
|
let scripts = vec![
|
||||||
|
InsertNodes {
|
||||||
|
path: path.clone(),
|
||||||
|
node_data_list: node_data_list.clone(),
|
||||||
|
rev_id: 1,
|
||||||
|
},
|
||||||
|
DeleteNodes {
|
||||||
|
path: path.clone(),
|
||||||
|
node_data_list: node_data_list.clone(),
|
||||||
|
rev_id: 2,
|
||||||
|
},
|
||||||
|
AssertNode {
|
||||||
|
path: path.clone(),
|
||||||
|
expected: None,
|
||||||
|
},
|
||||||
|
AssertNode {
|
||||||
|
path: path.next(),
|
||||||
|
expected: None,
|
||||||
|
},
|
||||||
|
AssertNode {
|
||||||
|
path: path.next().next(),
|
||||||
|
expected: None,
|
||||||
|
},
|
||||||
|
AssertTreeJSON {
|
||||||
|
expected: r#""""#.to_string(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
test.run_scripts(scripts);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn node_delete_node_from_list_test() {
|
fn node_delete_node_from_list_test() {
|
||||||
let mut test = NodeTest::new();
|
let mut test = NodeTest::new();
|
||||||
|
Reference in New Issue
Block a user