Verbessere Fehlerbehandlung in SQL-Abfragen: Füge detaillierte Fehlermeldungen für Vorbereitungs- und Ausführungsfehler in den Director- und Politics-Workern hinzu.
This commit is contained in:
@@ -92,8 +92,32 @@ impl Database {
|
|||||||
.get(name)
|
.get(name)
|
||||||
.ok_or_else(|| DbError::new(format!("Unbekanntes Statement: {name}")))?;
|
.ok_or_else(|| DbError::new(format!("Unbekanntes Statement: {name}")))?;
|
||||||
|
|
||||||
let rows = self.client.query(sql.as_str(), params)?;
|
match self.client.query(sql.as_str(), params) {
|
||||||
Ok(rows.into_iter().map(Self::row_to_map).collect())
|
Ok(rows) => Ok(rows.into_iter().map(Self::row_to_map).collect()),
|
||||||
|
Err(err) => {
|
||||||
|
if let Some(db_err) = err.as_db_error() {
|
||||||
|
let code = db_err.code().code().to_string();
|
||||||
|
let message = db_err.message();
|
||||||
|
let detail = db_err.detail().unwrap_or_default();
|
||||||
|
let hint = db_err.hint().unwrap_or_default();
|
||||||
|
// SQL ggf. kürzen, um Log-Flut zu vermeiden
|
||||||
|
let mut sql_preview = sql.clone();
|
||||||
|
const MAX_SQL_PREVIEW: usize = 800;
|
||||||
|
if sql_preview.len() > MAX_SQL_PREVIEW {
|
||||||
|
sql_preview.truncate(MAX_SQL_PREVIEW);
|
||||||
|
sql_preview.push_str(" …");
|
||||||
|
}
|
||||||
|
Err(DbError::new(format!(
|
||||||
|
"Postgres-Fehler bei Statement '{name}': {} (SQLSTATE: {}, Detail: {}, Hint: {}) | SQL: {}",
|
||||||
|
message, code, detail, hint, sql_preview
|
||||||
|
)))
|
||||||
|
} else {
|
||||||
|
Err(DbError::new(format!(
|
||||||
|
"Postgres-Fehler (Client) bei Statement '{name}': {err}"
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn row_to_map(row: postgres::Row) -> Row {
|
fn row_to_map(row: postgres::Row) -> Row {
|
||||||
|
|||||||
@@ -740,13 +740,17 @@ impl DirectorWorker {
|
|||||||
// Default
|
// Default
|
||||||
let mut cumulative_tax_percent = DEFAULT_TAX_PERCENT;
|
let mut cumulative_tax_percent = DEFAULT_TAX_PERCENT;
|
||||||
|
|
||||||
conn.prepare("get_branch_region", QUERY_GET_BRANCH_REGION)?;
|
conn.prepare("get_branch_region", QUERY_GET_BRANCH_REGION)
|
||||||
let branch_rows = conn.execute("get_branch_region", &[&branch_id])?;
|
.map_err(|e| DbError::new(format!("[DirectorWorker] prepare get_branch_region: {e}")))?;
|
||||||
|
let branch_rows = conn.execute("get_branch_region", &[&branch_id])
|
||||||
|
.map_err(|e| DbError::new(format!("[DirectorWorker] exec get_branch_region branch_id={}: {e}", branch_id)))?;
|
||||||
let branch_region_id: Option<i32> = branch_rows.first().and_then(|r| r.get("region_id")).and_then(|v| v.parse().ok());
|
let branch_region_id: Option<i32> = branch_rows.first().and_then(|r| r.get("region_id")).and_then(|v| v.parse().ok());
|
||||||
|
|
||||||
if let Some(region_id) = branch_region_id {
|
if let Some(region_id) = branch_region_id {
|
||||||
conn.prepare("get_user_offices", QUERY_GET_USER_OFFICES)?;
|
conn.prepare("get_user_offices", QUERY_GET_USER_OFFICES)
|
||||||
let offices = conn.execute("get_user_offices", &[&user_id])?;
|
.map_err(|e| DbError::new(format!("[DirectorWorker] prepare get_user_offices: {e}")))?;
|
||||||
|
let offices = conn.execute("get_user_offices", &[&user_id])
|
||||||
|
.map_err(|e| DbError::new(format!("[DirectorWorker] exec get_user_offices user_id={}: {e}", user_id)))?;
|
||||||
|
|
||||||
let mut exempt_types: Vec<String> = Vec::new();
|
let mut exempt_types: Vec<String> = Vec::new();
|
||||||
let mut has_chancellor = false;
|
let mut has_chancellor = false;
|
||||||
@@ -768,17 +772,21 @@ impl DirectorWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if exempt_types.is_empty() {
|
if exempt_types.is_empty() {
|
||||||
conn.prepare("cumulative_tax_no_exempt", QUERY_CUMULATIVE_TAX_NO_EXEMPT)?;
|
conn.prepare("cumulative_tax_no_exempt", QUERY_CUMULATIVE_TAX_NO_EXEMPT)
|
||||||
let res = conn.execute("cumulative_tax_no_exempt", &[®ion_id])?;
|
.map_err(|e| DbError::new(format!("[DirectorWorker] prepare cumulative_tax_no_exempt: {e}")))?;
|
||||||
|
let res = conn.execute("cumulative_tax_no_exempt", &[®ion_id])
|
||||||
|
.map_err(|e| DbError::new(format!("[DirectorWorker] exec cumulative_tax_no_exempt region_id={}: {e}", region_id)))?;
|
||||||
if let Some(row) = res.first()
|
if let Some(row) = res.first()
|
||||||
&& let Some(tp) = row.get("total_percent")
|
&& let Some(tp) = row.get("total_percent")
|
||||||
{
|
{
|
||||||
cumulative_tax_percent = tp.parse::<f64>().unwrap_or(DEFAULT_TAX_PERCENT);
|
cumulative_tax_percent = tp.parse::<f64>().unwrap_or(DEFAULT_TAX_PERCENT);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
conn.prepare("cumulative_tax_with_exempt", QUERY_CUMULATIVE_TAX_WITH_EXEMPT)?;
|
conn.prepare("cumulative_tax_with_exempt", QUERY_CUMULATIVE_TAX_WITH_EXEMPT)
|
||||||
|
.map_err(|e| DbError::new(format!("[DirectorWorker] prepare cumulative_tax_with_exempt: {e}")))?;
|
||||||
let exempt_array: Vec<&str> = exempt_types.iter().map(|s| s.as_str()).collect();
|
let exempt_array: Vec<&str> = exempt_types.iter().map(|s| s.as_str()).collect();
|
||||||
let res = conn.execute("cumulative_tax_with_exempt", &[®ion_id, &exempt_array])?;
|
let res = conn.execute("cumulative_tax_with_exempt", &[®ion_id, &exempt_array])
|
||||||
|
.map_err(|e| DbError::new(format!("[DirectorWorker] exec cumulative_tax_with_exempt region_id={} exempt={:?}: {}", region_id, exempt_array, e)))?;
|
||||||
if let Some(row) = res.first() && let Some(tp) = row.get("total_percent") {
|
if let Some(row) = res.first() && let Some(tp) = row.get("total_percent") {
|
||||||
cumulative_tax_percent = tp.parse::<f64>().unwrap_or(DEFAULT_TAX_PERCENT);
|
cumulative_tax_percent = tp.parse::<f64>().unwrap_or(DEFAULT_TAX_PERCENT);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,8 +165,9 @@ impl PoliticsWorker {
|
|||||||
conn.prepare(
|
conn.prepare(
|
||||||
"count_offices_per_region",
|
"count_offices_per_region",
|
||||||
QUERY_COUNT_OFFICES_PER_REGION,
|
QUERY_COUNT_OFFICES_PER_REGION,
|
||||||
)?;
|
).map_err(|e| DbError::new(format!("[PoliticsWorker] prepare count_offices_per_region: {e}")))?;
|
||||||
let rows = conn.execute("count_offices_per_region", &[])?;
|
let rows = conn.execute("count_offices_per_region", &[])
|
||||||
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] exec count_offices_per_region: {e}")))?;
|
||||||
|
|
||||||
let mut result = Vec::with_capacity(rows.len());
|
let mut result = Vec::with_capacity(rows.len());
|
||||||
for row in rows {
|
for row in rows {
|
||||||
@@ -202,7 +203,7 @@ impl PoliticsWorker {
|
|||||||
conn.prepare(
|
conn.prepare(
|
||||||
"trim_excess_offices_global",
|
"trim_excess_offices_global",
|
||||||
QUERY_TRIM_EXCESS_OFFICES_GLOBAL,
|
QUERY_TRIM_EXCESS_OFFICES_GLOBAL,
|
||||||
)?;
|
).map_err(|e| DbError::new(format!("[PoliticsWorker] prepare trim_excess_offices_global: {e}")))?;
|
||||||
|
|
||||||
if let Err(err) = conn.execute("trim_excess_offices_global", &[]) {
|
if let Err(err) = conn.execute("trim_excess_offices_global", &[]) {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
@@ -229,8 +230,10 @@ impl PoliticsWorker {
|
|||||||
.get()
|
.get()
|
||||||
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
||||||
|
|
||||||
conn.prepare("find_office_gaps", QUERY_FIND_OFFICE_GAPS)?;
|
conn.prepare("find_office_gaps", QUERY_FIND_OFFICE_GAPS)
|
||||||
let rows = conn.execute("find_office_gaps", &[])?;
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] prepare find_office_gaps: {e}")))?;
|
||||||
|
let rows = conn.execute("find_office_gaps", &[])
|
||||||
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] exec find_office_gaps: {e}")))?;
|
||||||
|
|
||||||
if rows.is_empty() {
|
if rows.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -312,8 +315,10 @@ impl PoliticsWorker {
|
|||||||
.get()
|
.get()
|
||||||
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
||||||
|
|
||||||
conn.prepare("select_needed_elections", QUERY_SELECT_NEEDED_ELECTIONS)?;
|
conn.prepare("select_needed_elections", QUERY_SELECT_NEEDED_ELECTIONS)
|
||||||
let rows = conn.execute("select_needed_elections", &[])?;
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] prepare select_needed_elections: {e}")))?;
|
||||||
|
let rows = conn.execute("select_needed_elections", &[])
|
||||||
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] exec select_needed_elections: {e}")))?;
|
||||||
|
|
||||||
let mut elections = Vec::with_capacity(rows.len());
|
let mut elections = Vec::with_capacity(rows.len());
|
||||||
for row in rows {
|
for row in rows {
|
||||||
@@ -342,8 +347,9 @@ impl PoliticsWorker {
|
|||||||
conn.prepare(
|
conn.prepare(
|
||||||
"select_elections_needing_candidates",
|
"select_elections_needing_candidates",
|
||||||
QUERY_SELECT_ELECTIONS_NEEDING_CANDIDATES,
|
QUERY_SELECT_ELECTIONS_NEEDING_CANDIDATES,
|
||||||
)?;
|
).map_err(|e| DbError::new(format!("[PoliticsWorker] prepare select_elections_needing_candidates: {e}")))?;
|
||||||
let rows = conn.execute("select_elections_needing_candidates", &[])?;
|
let rows = conn.execute("select_elections_needing_candidates", &[])
|
||||||
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] exec select_elections_needing_candidates: {e}")))?;
|
||||||
|
|
||||||
let mut elections = Vec::with_capacity(rows.len());
|
let mut elections = Vec::with_capacity(rows.len());
|
||||||
for row in rows {
|
for row in rows {
|
||||||
@@ -370,13 +376,14 @@ impl PoliticsWorker {
|
|||||||
.get()
|
.get()
|
||||||
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
||||||
|
|
||||||
conn.prepare("insert_candidates", QUERY_INSERT_CANDIDATES)?;
|
conn.prepare("insert_candidates", QUERY_INSERT_CANDIDATES)
|
||||||
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] prepare insert_candidates: {e}")))?;
|
||||||
|
|
||||||
for e in elections {
|
for e in elections {
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"insert_candidates",
|
"insert_candidates",
|
||||||
&[&e.election_id, &e.region_id, &e.posts_to_fill],
|
&[&e.election_id, &e.region_id, &e.posts_to_fill],
|
||||||
)?;
|
).map_err(|err| DbError::new(format!("[PoliticsWorker] exec insert_candidates eid={} rid={}: {}", e.election_id, e.region_id, err)))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -389,8 +396,10 @@ impl PoliticsWorker {
|
|||||||
.get()
|
.get()
|
||||||
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
||||||
|
|
||||||
conn.prepare("process_expired_and_fill", QUERY_PROCESS_EXPIRED_AND_FILL)?;
|
conn.prepare("process_expired_and_fill", QUERY_PROCESS_EXPIRED_AND_FILL)
|
||||||
let rows = conn.execute("process_expired_and_fill", &[])?;
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] prepare process_expired_and_fill: {e}")))?;
|
||||||
|
let rows = conn.execute("process_expired_and_fill", &[])
|
||||||
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] exec process_expired_and_fill: {e}")))?;
|
||||||
|
|
||||||
Ok(rows
|
Ok(rows
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -433,14 +442,17 @@ impl PoliticsWorker {
|
|||||||
.get()
|
.get()
|
||||||
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
||||||
|
|
||||||
conn.prepare("notify_office_expiration", QUERY_NOTIFY_OFFICE_EXPIRATION)?;
|
conn.prepare("notify_office_expiration", QUERY_NOTIFY_OFFICE_EXPIRATION)
|
||||||
conn.execute("notify_office_expiration", &[])?;
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] prepare notify_office_expiration: {e}")))?;
|
||||||
|
conn.execute("notify_office_expiration", &[])
|
||||||
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] exec notify_office_expiration: {e}")))?;
|
||||||
|
|
||||||
conn.prepare(
|
conn.prepare(
|
||||||
"get_users_with_expiring_offices",
|
"get_users_with_expiring_offices",
|
||||||
QUERY_GET_USERS_WITH_EXPIRING_OFFICES,
|
QUERY_GET_USERS_WITH_EXPIRING_OFFICES,
|
||||||
)?;
|
).map_err(|e| DbError::new(format!("[PoliticsWorker] prepare get_users_with_expiring_offices: {e}")))?;
|
||||||
let rows = conn.execute("get_users_with_expiring_offices", &[])?;
|
let rows = conn.execute("get_users_with_expiring_offices", &[])
|
||||||
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] exec get_users_with_expiring_offices: {e}")))?;
|
||||||
|
|
||||||
for row in rows {
|
for row in rows {
|
||||||
if let Some(user_id) = row.get("user_id").and_then(|v| v.parse::<i32>().ok()) {
|
if let Some(user_id) = row.get("user_id").and_then(|v| v.parse::<i32>().ok()) {
|
||||||
@@ -462,17 +474,20 @@ impl PoliticsWorker {
|
|||||||
.get()
|
.get()
|
||||||
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
||||||
|
|
||||||
conn.prepare("notify_election_created", QUERY_NOTIFY_ELECTION_CREATED)?;
|
conn.prepare("notify_election_created", QUERY_NOTIFY_ELECTION_CREATED)
|
||||||
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] prepare notify_election_created: {e}")))?;
|
||||||
|
|
||||||
for uid in user_ids {
|
for uid in user_ids {
|
||||||
conn.execute("notify_election_created", &[uid])?;
|
conn.execute("notify_election_created", &[uid])
|
||||||
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] exec notify_election_created uid={}: {}", uid, e)))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.prepare(
|
conn.prepare(
|
||||||
"get_users_in_regions_with_elections",
|
"get_users_in_regions_with_elections",
|
||||||
QUERY_GET_USERS_IN_REGIONS_WITH_ELECTIONS,
|
QUERY_GET_USERS_IN_REGIONS_WITH_ELECTIONS,
|
||||||
)?;
|
).map_err(|e| DbError::new(format!("[PoliticsWorker] prepare get_users_in_regions_with_elections: {e}")))?;
|
||||||
let rows = conn.execute("get_users_in_regions_with_elections", &[])?;
|
let rows = conn.execute("get_users_in_regions_with_elections", &[])
|
||||||
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] exec get_users_in_regions_with_elections: {e}")))?;
|
||||||
|
|
||||||
for row in rows {
|
for row in rows {
|
||||||
if let Some(user_id) = row.get("user_id").and_then(|v| v.parse::<i32>().ok()) {
|
if let Some(user_id) = row.get("user_id").and_then(|v| v.parse::<i32>().ok()) {
|
||||||
@@ -494,7 +509,8 @@ impl PoliticsWorker {
|
|||||||
.get()
|
.get()
|
||||||
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
||||||
|
|
||||||
conn.prepare("notify_office_filled", QUERY_NOTIFY_OFFICE_FILLED)?;
|
conn.prepare("notify_office_filled", QUERY_NOTIFY_OFFICE_FILLED)
|
||||||
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] prepare notify_office_filled: {e}")))?;
|
||||||
|
|
||||||
for office in new_offices {
|
for office in new_offices {
|
||||||
// Debug-Logging mit allen Feldern, damit sie aktiv genutzt werden
|
// Debug-Logging mit allen Feldern, damit sie aktiv genutzt werden
|
||||||
@@ -502,14 +518,16 @@ impl PoliticsWorker {
|
|||||||
"[PoliticsWorker] Office filled: id={}, type={}, character={}, region={}",
|
"[PoliticsWorker] Office filled: id={}, type={}, character={}, region={}",
|
||||||
office.office_id, office.office_type_id, office.character_id, office.region_id
|
office.office_id, office.office_type_id, office.character_id, office.region_id
|
||||||
);
|
);
|
||||||
conn.execute("notify_office_filled", &[&office.character_id])?;
|
conn.execute("notify_office_filled", &[&office.character_id])
|
||||||
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] exec notify_office_filled office_id={} character_id={}: {}", office.office_id, office.character_id, e)))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.prepare(
|
conn.prepare(
|
||||||
"get_users_with_filled_offices",
|
"get_users_with_filled_offices",
|
||||||
QUERY_GET_USERS_WITH_FILLED_OFFICES,
|
QUERY_GET_USERS_WITH_FILLED_OFFICES,
|
||||||
)?;
|
).map_err(|e| DbError::new(format!("[PoliticsWorker] prepare get_users_with_filled_offices: {e}")))?;
|
||||||
let rows = conn.execute("get_users_with_filled_offices", &[])?;
|
let rows = conn.execute("get_users_with_filled_offices", &[])
|
||||||
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] exec get_users_with_filled_offices: {e}")))?;
|
||||||
|
|
||||||
for row in rows {
|
for row in rows {
|
||||||
if let Some(user_id) = row.get("user_id").and_then(|v| v.parse::<i32>().ok()) {
|
if let Some(user_id) = row.get("user_id").and_then(|v| v.parse::<i32>().ok()) {
|
||||||
|
|||||||
@@ -265,7 +265,9 @@ FROM falukant_data.political_office po
|
|||||||
JOIN falukant_type.political_office_type pot ON pot.id = po.office_type_id
|
JOIN falukant_type.political_office_type pot ON pot.id = po.office_type_id
|
||||||
JOIN falukant_data.region r ON r.id = po.region_id
|
JOIN falukant_data.region r ON r.id = po.region_id
|
||||||
JOIN falukant_type.region rt ON rt.id = r.region_type_id
|
JOIN falukant_type.region rt ON rt.id = r.region_type_id
|
||||||
WHERE po.holder_id = $1 AND (po.end_date IS NULL OR po.end_date > NOW());
|
JOIN falukant_data.character ch ON ch.id = po.character_id
|
||||||
|
WHERE ch.user_id = $1
|
||||||
|
AND (po.created_at + (pot.term_length * INTERVAL '1 day')) > NOW();
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
pub const QUERY_CUMULATIVE_TAX_NO_EXEMPT: &str = r#"
|
pub const QUERY_CUMULATIVE_TAX_NO_EXEMPT: &str = r#"
|
||||||
|
|||||||
Reference in New Issue
Block a user