From 529461f12c26948bd696498aa36d1507bfade8bf Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 20 Feb 2026 15:01:33 +0200 Subject: [PATCH] feat: client cascade delete with dependency counts --- src-tauri/src/commands.rs | 59 +++++++++++++++++++++++++++++++++++++-- src-tauri/src/lib.rs | 1 + 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 5b94b09..f7ad4b6 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -110,11 +110,66 @@ pub fn update_client(state: State, client: Client) -> Result<(), Strin Ok(()) } +#[tauri::command] +pub fn get_client_dependents(state: State, client_id: i64) -> Result { + let conn = state.db.lock().map_err(|e| e.to_string())?; + let project_count: i64 = conn.query_row( + "SELECT COUNT(*) FROM projects WHERE client_id = ?1", params![client_id], |row| row.get(0) + ).map_err(|e| e.to_string())?; + let invoice_count: i64 = conn.query_row( + "SELECT COUNT(*) FROM invoices WHERE client_id = ?1", params![client_id], |row| row.get(0) + ).map_err(|e| e.to_string())?; + let expense_count: i64 = conn.query_row( + "SELECT COUNT(*) FROM expenses WHERE client_id = ?1", params![client_id], |row| row.get(0) + ).map_err(|e| e.to_string())?; + Ok(serde_json::json!({ + "projects": project_count, + "invoices": invoice_count, + "expenses": expense_count + })) +} + #[tauri::command] pub fn delete_client(state: State, id: i64) -> Result<(), String> { let conn = state.db.lock().map_err(|e| e.to_string())?; - conn.execute("DELETE FROM clients WHERE id = ?1", params![id]).map_err(|e| e.to_string())?; - Ok(()) + + conn.execute_batch("BEGIN TRANSACTION").map_err(|e| e.to_string())?; + + let result = (|| -> Result<(), rusqlite::Error> { + let project_ids: Vec = { + let mut stmt = conn.prepare("SELECT id FROM projects WHERE client_id = ?1")?; + let rows = stmt.query_map(params![id], |row| row.get(0))?; + rows.filter_map(|r| r.ok()).collect() + }; + + for pid in &project_ids { + conn.execute("DELETE FROM entry_tags WHERE entry_id IN (SELECT id FROM time_entries WHERE project_id = ?1)", params![pid])?; + conn.execute("DELETE FROM time_entries WHERE project_id = ?1", params![pid])?; + conn.execute("DELETE FROM tasks WHERE project_id = ?1", params![pid])?; + conn.execute("DELETE FROM tracked_apps WHERE project_id = ?1", params![pid])?; + conn.execute("DELETE FROM favorites WHERE project_id = ?1", params![pid])?; + conn.execute("DELETE FROM recurring_entries WHERE project_id = ?1", params![pid])?; + conn.execute("DELETE FROM timeline_events WHERE project_id = ?1", params![pid])?; + } + + conn.execute("DELETE FROM expenses WHERE client_id = ?1", params![id])?; + conn.execute("DELETE FROM invoice_items WHERE invoice_id IN (SELECT id FROM invoices WHERE client_id = ?1)", params![id])?; + conn.execute("DELETE FROM invoices WHERE client_id = ?1", params![id])?; + conn.execute("DELETE FROM projects WHERE client_id = ?1", params![id])?; + conn.execute("DELETE FROM clients WHERE id = ?1", params![id])?; + Ok(()) + })(); + + match result { + Ok(()) => { + conn.execute_batch("COMMIT").map_err(|e| e.to_string())?; + Ok(()) + } + Err(e) => { + conn.execute_batch("ROLLBACK").ok(); + Err(e.to_string()) + } + } } // Project commands diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index dc6be9d..de96642 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -45,6 +45,7 @@ pub fn run() { commands::create_client, commands::update_client, commands::delete_client, + commands::get_client_dependents, commands::get_projects, commands::create_project, commands::update_project,