feat: client cascade delete with dependency counts

This commit is contained in:
Your Name
2026-02-20 15:01:33 +02:00
parent eb58794555
commit 0ddf8aa14e
2 changed files with 58 additions and 2 deletions

View File

@@ -110,11 +110,66 @@ pub fn update_client(state: State<AppState>, client: Client) -> Result<(), Strin
Ok(()) Ok(())
} }
#[tauri::command]
pub fn get_client_dependents(state: State<AppState>, client_id: i64) -> Result<serde_json::Value, String> {
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] #[tauri::command]
pub fn delete_client(state: State<AppState>, id: i64) -> Result<(), String> { pub fn delete_client(state: State<AppState>, id: i64) -> Result<(), String> {
let conn = state.db.lock().map_err(|e| e.to_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<i64> = {
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 // Project commands

View File

@@ -45,6 +45,7 @@ pub fn run() {
commands::create_client, commands::create_client,
commands::update_client, commands::update_client,
commands::delete_client, commands::delete_client,
commands::get_client_dependents,
commands::get_projects, commands::get_projects,
commands::create_project, commands::create_project,
commands::update_project, commands::update_project,