Implement election candidate table readiness check in character deletion process: Added a new SQL query to verify the existence of the election candidate table before attempting to delete associated records. Updated the deletion logic in both EventsWorker and UserCharacterWorker to conditionally execute the deletion of election candidates based on the table's readiness, improving robustness and preventing errors in environments where the table may not exist.
All checks were successful
Deploy yourpart (blue-green) / deploy (push) Successful in 1m39s

This commit is contained in:
Torsten Schulz (local)
2026-04-21 11:48:53 +02:00
parent a38beadb8e
commit 397b612bf1
4 changed files with 304 additions and 4 deletions

View File

@@ -0,0 +1,270 @@
-- Debug-Queries: Tod -> Erbwechsel -> Cleanup
-- Nutzung:
-- psql ... -f docs/DEBUG_DEATH_SUCCESSION_QUERIES.sql
-- Ersetze zuerst:
-- :character_id (verstorbener Charakter)
-- :user_id (falukant_user.id des Spielers)
-- :heir_id (optional; geplanter Erbe)
--
-- In psql z. B.:
-- \set character_id 123
-- \set user_id 45
-- \set heir_id 678
-- ============================================================
-- 0) Vorab: Existenz / Ausgangszustand prüfen
-- ============================================================
SELECT c.id, c.user_id, c.health, c.updated_at
FROM falukant_data.character c
WHERE c.id = :character_id;
SELECT fu.id, fu.user_id, fu.money, fu.certificate
FROM falukant_data.falukant_user fu
WHERE fu.id = :user_id;
-- Mögliche Erben (wie QUERY_GET_HEIR priorisiert)
SELECT child_character_id, is_heir, updated_at
FROM falukant_data.child_relation
WHERE father_character_id = :character_id
OR mother_character_id = :character_id
ORDER BY (is_heir IS TRUE) DESC, updated_at DESC
LIMIT 20;
-- Fallback-Erbe (entspricht QUERY_RANDOM_HEIR-Prinzip: nur Vorschau)
SELECT cr.child_character_id
FROM falukant_data.child_relation cr
JOIN falukant_data.character c ON c.id = cr.child_character_id
WHERE (cr.father_character_id = :character_id OR cr.mother_character_id = :character_id)
AND c.health > 0
ORDER BY RANDOM()
LIMIT 1;
-- ============================================================
-- 1) Queries, die der Daemon im Todespfad nutzt (Vorschau)
-- Reihenfolge entspricht Worker-Logik.
-- ============================================================
-- 1.1 get_falukant_user_id
SELECT user_id
FROM falukant_data.character
WHERE id = :character_id;
-- 1.2 get_heir (bevorzugt is_heir=true)
SELECT child_character_id
FROM falukant_data.child_relation
WHERE father_character_id = :character_id OR mother_character_id = :character_id
ORDER BY (is_heir IS TRUE) DESC, updated_at DESC
LIMIT 1;
-- 1.3 random_heir (wenn 1.2 leer)
SELECT cr.child_character_id
FROM falukant_data.child_relation cr
JOIN falukant_data.character c ON c.id = cr.child_character_id
WHERE (cr.father_character_id = :character_id OR cr.mother_character_id = :character_id)
AND c.health > 0
ORDER BY RANDOM()
LIMIT 1;
-- 1.4 set_character_user (nur wenn Erbe vorhanden)
-- UPDATE falukant_data.character
-- SET user_id = :user_id, updated_at = NOW()
-- WHERE id = :heir_id;
-- 1.5 Vermögensberechnung: Inputs
SELECT money FROM falukant_data.falukant_user WHERE id = :user_id;
SELECT COALESCE(SUM(h.cost), 0) AS sum
FROM falukant_data.user_house uh
JOIN falukant_type.house h ON uh.house_type_id = h.id
WHERE uh.user_id = :user_id;
SELECT COALESCE(SUM(b.base_cost), 0) AS sum
FROM falukant_data.branch br
JOIN falukant_type.branch b ON br.branch_type_id = b.id
WHERE br.falukant_user_id = :user_id;
SELECT COALESCE(SUM(i.quantity * p.sell_cost), 0) AS sum
FROM falukant_data.inventory i
JOIN falukant_type.product p ON i.product_id = p.id
JOIN falukant_data.stock s ON i.stock_id = s.id
JOIN falukant_data.branch br ON s.branch_id = br.id
WHERE br.falukant_user_id = :user_id;
SELECT COALESCE(SUM(remaining_amount), 0) AS sum
FROM falukant_data.credit
WHERE falukant_user_id = :user_id;
SELECT COUNT(DISTINCT cr.child_character_id) AS cnt
FROM falukant_data.child_relation cr
JOIN falukant_data.character parent
ON (parent.id = cr.father_character_id OR parent.id = cr.mother_character_id)
WHERE parent.user_id = :user_id;
-- 1.6 set_new_money (nur wenn du den errechneten Wert testen willst)
-- UPDATE falukant_data.falukant_user
-- SET money = '<NEW_MONEY_NUMERIC_STRING>', updated_at = NOW()
-- WHERE id = :user_id;
-- 1.7 delete_director
WITH deleted AS (
DELETE FROM falukant_data.director
WHERE director_character_id = :character_id
RETURNING employer_user_id
)
SELECT * FROM deleted;
-- 1.8 delete_relationship
WITH deleted AS (
DELETE FROM falukant_data.relationship
WHERE character1_id = :character_id OR character2_id = :character_id
RETURNING CASE WHEN character1_id = :character_id THEN character2_id ELSE character1_id END AS related_character_id
)
SELECT c.user_id AS related_user_id
FROM deleted d
JOIN falukant_data.character c ON c.id = d.related_character_id;
-- 1.9 delete_child_relation_by_parent
DELETE FROM falukant_data.child_relation
WHERE father_character_id = :character_id OR mother_character_id = :character_id;
-- 1.10 delete_child_relation (als Kind)
WITH deleted AS (
DELETE FROM falukant_data.child_relation
WHERE child_character_id = :character_id
RETURNING father_character_id, mother_character_id
)
SELECT cf.user_id AS father_user_id, cm.user_id AS mother_user_id
FROM deleted d
JOIN falukant_data.character cf ON cf.id = d.father_character_id
JOIN falukant_data.character cm ON cm.id = d.mother_character_id;
-- 1.11 zusätzliche Cleanup-Queries
DELETE FROM falukant_data.knowledge
WHERE character_id = :character_id;
DELETE FROM falukant_data.debtors_prism
WHERE character_id = :character_id;
WITH removed AS (
DELETE FROM falukant_data.political_office
WHERE character_id = :character_id
RETURNING character_id, office_type_id, region_id, created_at
),
archived_removed AS (
INSERT INTO falukant_log.political_office_history
(character_id, office_type_id, region_id, start_date, end_date)
SELECT character_id, office_type_id, region_id, created_at, NOW()
FROM removed
),
affected AS (
SELECT DISTINCT office_type_id, region_id
FROM removed
),
seats AS (
SELECT pot.id AS office_type_id, rt.id AS region_id, pot.seats_per_region AS seats_total
FROM falukant_type.political_office_type pot
JOIN falukant_type.region rt ON pot.region_type = rt.label_tr
JOIN affected a ON a.office_type_id = pot.id AND a.region_id = rt.id
),
ranked AS (
SELECT po.id, po.character_id, po.office_type_id, po.region_id, po.created_at, s.seats_total,
ROW_NUMBER() OVER (
PARTITION BY po.office_type_id, po.region_id
ORDER BY po.created_at DESC
) AS rn
FROM falukant_data.political_office po
JOIN seats s ON s.office_type_id = po.office_type_id AND s.region_id = po.region_id
),
to_delete AS (
SELECT id, character_id, office_type_id, region_id, created_at
FROM ranked
WHERE rn > seats_total
),
archived_trim AS (
INSERT INTO falukant_log.political_office_history
(character_id, office_type_id, region_id, start_date, end_date)
SELECT character_id, office_type_id, region_id, created_at, NOW()
FROM to_delete
)
DELETE FROM falukant_data.political_office
WHERE id IN (SELECT id FROM to_delete);
-- election_candidate ist nicht in allen Bestands-DBs vorhanden:
SELECT EXISTS (
SELECT 1
FROM information_schema.tables
WHERE table_schema = 'falukant_data'
AND table_name = 'election_candidate'
) AS election_candidate_table_ready;
-- Nur ausführen, wenn vorher TRUE:
-- DELETE FROM falukant_data.election_candidate
-- WHERE character_id = :character_id;
-- 1.12 final delete_character
DELETE FROM falukant_data.character
WHERE id = :character_id;
-- ============================================================
-- 2) Nachkontrolle (muss leer / 0 sein)
-- ============================================================
SELECT 1 AS character_still_exists
FROM falukant_data.character
WHERE id = :character_id;
SELECT COUNT(*) AS knowledge_left
FROM falukant_data.knowledge
WHERE character_id = :character_id;
SELECT COUNT(*) AS debtors_prism_left
FROM falukant_data.debtors_prism
WHERE character_id = :character_id;
SELECT COUNT(*) AS political_office_left
FROM falukant_data.political_office
WHERE character_id = :character_id;
SELECT COUNT(*) AS election_candidate_left
FROM falukant_data.election_candidate
WHERE character_id = :character_id;
SELECT *
FROM falukant_log.political_office_history
WHERE character_id = :character_id
ORDER BY end_date DESC
LIMIT 10;
-- Neuer aktiver Charakter des Users:
SELECT c.id, c.user_id, c.health, c.updated_at
FROM falukant_data.character c
WHERE c.user_id = :user_id
ORDER BY c.updated_at DESC, c.id DESC
LIMIT 10;
-- ============================================================
-- 3) Unabhängig: completion_count-Fehler für Zertifikat
-- ============================================================
-- 3.1 Existiert Spalte?
SELECT column_name, data_type, is_nullable, column_default
FROM information_schema.columns
WHERE table_schema = 'falukant_log'
AND table_name = 'production'
AND column_name = 'completion_count';
-- 3.2 Sofort-Fix (idempotent), falls Spalte fehlt oder unvollständig:
ALTER TABLE falukant_log.production
ADD COLUMN IF NOT EXISTS completion_count integer;
UPDATE falukant_log.production
SET completion_count = 1
WHERE completion_count IS NULL;
ALTER TABLE falukant_log.production
ALTER COLUMN completion_count SET DEFAULT 1,
ALTER COLUMN completion_count SET NOT NULL;
-- 3.3 Optional: Migration historisch sauber markieren/prüfen
-- (abhängig davon, wie ihr Migrationsstände verwaltet)