perf(tauri): build child index once for cascade delete

`delete_task`'s descendant walk re-scanned the full task list on every
frontier pop, so the cost was O(n * depth) where n is the list size.
For a list of a few hundred tasks with even moderate nesting that's
already noticeable.

Index `parent_id -> [child_id]` once up-front; the BFS then visits each
descendant in O(1) amortised, dropping the total to O(n).
This commit is contained in:
Claude 2026-04-25 07:26:56 +00:00
parent 1cdf5dff90
commit 069afe8d5e
No known key found for this signature in database

View file

@ -455,12 +455,23 @@ fn delete_task(
// so deleting a parent can't leave grandchildren orphaned with a // so deleting a parent can't leave grandchildren orphaned with a
// parent_id pointing at a deleted task. // parent_id pointing at a deleted task.
let all_tasks = repo.list_tasks(lid).map_err(|e| e.to_string())?; let all_tasks = repo.list_tasks(lid).map_err(|e| e.to_string())?;
// Build a parent -> children index in one pass so the BFS below is O(n)
// instead of O(n * depth) scanning all tasks for each frontier pop.
let mut children_by_parent: std::collections::HashMap<Uuid, Vec<Uuid>> =
std::collections::HashMap::new();
for t in &all_tasks {
if let Some(pid) = t.parent_id {
children_by_parent.entry(pid).or_default().push(t.id);
}
}
let mut to_delete: std::collections::HashSet<Uuid> = std::collections::HashSet::new(); let mut to_delete: std::collections::HashSet<Uuid> = std::collections::HashSet::new();
let mut frontier: Vec<Uuid> = vec![tid]; let mut frontier: Vec<Uuid> = vec![tid];
while let Some(parent) = frontier.pop() { while let Some(parent) = frontier.pop() {
for t in &all_tasks { if let Some(children) = children_by_parent.get(&parent) {
if t.parent_id == Some(parent) && to_delete.insert(t.id) { for &child_id in children {
frontier.push(t.id); if to_delete.insert(child_id) {
frontier.push(child_id);
}
} }
} }
} }