From 069afe8d5e7d9344cb9d0f71d99ad7ca25f5c9a9 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 25 Apr 2026 07:26:56 +0000 Subject: [PATCH] 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). --- apps/tauri/src-tauri/src/lib.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/tauri/src-tauri/src/lib.rs b/apps/tauri/src-tauri/src/lib.rs index d71e981..eae1c25 100644 --- a/apps/tauri/src-tauri/src/lib.rs +++ b/apps/tauri/src-tauri/src/lib.rs @@ -455,12 +455,23 @@ fn delete_task( // so deleting a parent can't leave grandchildren orphaned with a // parent_id pointing at a deleted task. 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> = + 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 = std::collections::HashSet::new(); let mut frontier: Vec = vec![tid]; while let Some(parent) = frontier.pop() { - for t in &all_tasks { - if t.parent_id == Some(parent) && to_delete.insert(t.id) { - frontier.push(t.id); + if let Some(children) = children_by_parent.get(&parent) { + for &child_id in children { + if to_delete.insert(child_id) { + frontier.push(child_id); + } } } }