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:
parent
f76d722b4c
commit
b356354cd8
@ -285,7 +285,7 @@ class _AutoCompletionInputState extends State<_AutoCompletionInput> {
|
||||
final transaction = widget.editorState.transaction;
|
||||
transaction.deleteNodesAtPath(
|
||||
start,
|
||||
end.last - start.last,
|
||||
end.last - start.last + 1,
|
||||
);
|
||||
await widget.editorState.apply(transaction);
|
||||
}
|
||||
|
@ -43,6 +43,16 @@ impl Path {
|
||||
pub fn is_root(&self) -> bool {
|
||||
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 {
|
||||
|
@ -293,7 +293,13 @@ impl NodeTree {
|
||||
match op {
|
||||
NodeOperation::Insert { path, nodes } => self.insert_nodes(&path, nodes),
|
||||
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
|
||||
@ -456,14 +462,40 @@ impl NodeTree {
|
||||
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`
|
||||
///
|
||||
/// Do nothing if there is no node at the path.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `path`: references to the node that will be applied with the changeset
|
||||
/// * `changeset`: the change that will be applied to the node
|
||||
/// * `path`: references to the node that will be applied with the changeset
|
||||
/// * `changeset`: the change that will be applied to the node
|
||||
///
|
||||
/// returns: Result<(), OTError>
|
||||
fn update(&mut self, path: &Path, changeset: Changeset) -> Result<(), OTError> {
|
||||
|
@ -31,6 +31,11 @@ pub enum NodeScript {
|
||||
path: Path,
|
||||
rev_id: usize,
|
||||
},
|
||||
DeleteNodes {
|
||||
path: Path,
|
||||
node_data_list: Vec<NodeData>,
|
||||
rev_id: usize,
|
||||
},
|
||||
AssertNumberOfChildrenAtPath {
|
||||
path: Option<Path>,
|
||||
expected: usize,
|
||||
@ -137,7 +142,17 @@ impl NodeTest {
|
||||
self.transform_transaction_if_need(&mut transaction, rev_id);
|
||||
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 } => {
|
||||
let node = self.node_tree.get_node_data_at_path(&path);
|
||||
assert_eq!(node, expected.map(|e| e.into()));
|
||||
|
@ -349,6 +349,44 @@ fn node_delete_test() {
|
||||
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]
|
||||
fn node_delete_node_from_list_test() {
|
||||
let mut test = NodeTest::new();
|
||||
|
Loading…
Reference in New Issue
Block a user