From 619e5e5123a39003c9fbc22072ee8c81f92754aa Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Tue, 31 Mar 2026 15:14:01 +0200 Subject: [PATCH] Refactor death log handling in UserCharacterWorker: Introduced a new function `optional_linked_names` to streamline the retrieval of linked names (spouses, children, lovers) in the death context. This change enhances error handling and maintains the integrity of the deceased character's data in JSON format. Updated the `handle_character_death` method to utilize the new function, improving code readability and maintainability. --- src/worker/death_log.rs | 65 +++++++++++++++++++++++++++--------- src/worker/user_character.rs | 26 ++++++++++----- 2 files changed, 68 insertions(+), 23 deletions(-) diff --git a/src/worker/death_log.rs b/src/worker/death_log.rs index ce0ea94..74054a0 100644 --- a/src/worker/death_log.rs +++ b/src/worker/death_log.rs @@ -31,6 +31,28 @@ fn collect_display_names(rows: Vec, key: &str) -> Vec { out } +/// Verknüpfte Namen (Ehe, Kinder, Geliebte): optional — bei Schema-/SQL-Fehlern leere Liste, +/// damit der **Kern** (`deceased`) trotzdem als JSON in `notification.tr` landet. +fn optional_linked_names( + conn: &mut DbConnection, + log_label: &'static str, + stmt: &'static str, + query: &str, + deceased_character_id: i32, +) -> Vec { + if let Err(e) = conn.prepare(stmt, query) { + eprintln!("[death_log] {log_label} prepare: {e}"); + return Vec::new(); + } + match conn.execute(stmt, &[&deceased_character_id]) { + Ok(rows) => collect_display_names(rows, "display_name"), + Err(e) => { + eprintln!("[death_log] {log_label} execute: {e}"); + Vec::new() + } + } +} + /// Lädt Verstorbenen + Ehepartner, Kinder, **aktive Geliebte** (`tr = 'lover'`, `active IS NOT FALSE`). /// Muss ausgeführt werden, bevor Beziehungen aus der DB gelöscht werden. pub fn build_deceased_context(conn: &mut DbConnection, deceased_character_id: i32) -> Result { @@ -62,21 +84,34 @@ pub fn build_deceased_context(conn: &mut DbConnection, deceased_character_id: i3 .and_then(|v| v.parse::().ok()) .unwrap_or(0); - conn.prepare("death_spouse", QUERY_DEATH_LOG_SPOUSE_DISPLAY_NAMES)?; - let spouse_rows = conn.execute("death_spouse", &[&deceased_character_id])?; - let spouses = collect_display_names(spouse_rows, "display_name"); - - conn.prepare("death_child", QUERY_DEATH_LOG_CHILD_DISPLAY_NAMES)?; - let child_rows = conn.execute("death_child", &[&deceased_character_id])?; - let children = collect_display_names(child_rows, "display_name"); - - conn.prepare("death_child_lover_birth", QUERY_DEATH_LOG_CHILD_LOVER_BIRTH_DISPLAY_NAMES)?; - let child_lover_rows = conn.execute("death_child_lover_birth", &[&deceased_character_id])?; - let lover_birth_children = collect_display_names(child_lover_rows, "display_name"); - - conn.prepare("death_lover", QUERY_DEATH_LOG_LOVER_DISPLAY_NAMES)?; - let lover_rows = conn.execute("death_lover", &[&deceased_character_id])?; - let lovers = collect_display_names(lover_rows, "display_name"); + let spouses = optional_linked_names( + conn, + "spouse", + "death_spouse", + QUERY_DEATH_LOG_SPOUSE_DISPLAY_NAMES, + deceased_character_id, + ); + let children = optional_linked_names( + conn, + "child", + "death_child", + QUERY_DEATH_LOG_CHILD_DISPLAY_NAMES, + deceased_character_id, + ); + let lover_birth_children = optional_linked_names( + conn, + "child_lover_birth", + "death_child_lover_birth", + QUERY_DEATH_LOG_CHILD_LOVER_BIRTH_DISPLAY_NAMES, + deceased_character_id, + ); + let lovers = optional_linked_names( + conn, + "lover", + "death_lover", + QUERY_DEATH_LOG_LOVER_DISPLAY_NAMES, + deceased_character_id, + ); Ok(json!({ "deceased": { diff --git a/src/worker/user_character.rs b/src/worker/user_character.rs index 6360876..a371e2d 100644 --- a/src/worker/user_character.rs +++ b/src/worker/user_character.rs @@ -806,6 +806,24 @@ impl UserCharacterWorker { // Todes- und Erb-Logik fn handle_character_death(&mut self, character_id: i32) -> Result<(), DbError> { + // Todes-Kontext **vor** Erbfolge und vor allen DELETEs (wie EventsWorker / CharacterCreationWorker). + // So ist der Charakter garantiert noch in `character`, und bei Race mit anderem Worker schlägt + // spätestens hier fehl — nicht erst nach `set_heir`. + let death_ctx = { + let mut conn = self + .base + .pool + .get() + .map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?; + match death_log::build_deceased_context(&mut conn, character_id) { + Ok(c) => Some(c), + Err(e) => { + eprintln!("[UserCharacterWorker] Todes-Log Kontext: {e}"); + None + } + } + }; + self.set_heir(character_id)?; let death_event = format!( @@ -830,14 +848,6 @@ impl UserCharacterWorker { conn.prepare("delete_election_candidate", QUERY_DELETE_ELECTION_CANDIDATE)?; conn.prepare("insert_notification", QUERY_INSERT_NOTIFICATION)?; - let death_ctx = match death_log::build_deceased_context(&mut conn, character_id) { - Ok(c) => Some(c), - Err(e) => { - eprintln!("[UserCharacterWorker] Todes-Log Kontext: {e}"); - None - } - }; - let dir_result = conn.execute("delete_director", &[&character_id])?; for row in dir_result { if let Some(user_id) = row