teach/db/015_user_fk_cascade.sql
Ramon e3036580ce
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 32s
fix: gebruiker verwijderen werkt weer (herstel foreign-key cascade) (v0.3.95-beta)
- Verwijderen gaf op de live-database een 500 "serverfout". Oorzaak: op databases die zijn ontstaan vóór alle foreign keys ON DELETE CASCADE waren, houdt een tabel de oude constraint (CREATE TABLE IF NOT EXISTS werkt een bestaande constraint nooit bij), waardoor DELETE FROM users een foreign-key-fout geeft
- Migratie 015: zoekt elke FK naar users(id) die niet cascade en niet set-null is en zet die alsnog op ON DELETE CASCADE (bewuste SET NULL-constraints blijven ongemoeid). Draait bij de volgende deploy en is idempotent
- Verwijderroute vangt een resterende FK-fout (23503) op als een begrijpelijke 409 i.p.v. een kale serverfout
- Geverifieerd: alle INSERT INTO users-paden vangen al 23505 op (gebruikersnaam uniek per school); dezelfde naam in verschillende scholen is bewust toegestaan (inloggen kiest de school) en staat sinds 0.3.94 per school gegroepeerd
- 3 nieuwe servertests (FK-fout -> 409, normale verwijdering, migratie-inhoud); 97 tests groen

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-17 21:39:29 +02:00

33 lines
1.4 KiB
SQL

-- v0.3.95-beta: een gebruiker moet altijd te verwijderen zijn.
--
-- Alle foreign keys die naar users(id) verwijzen horen ON DELETE CASCADE te
-- zijn (of bewust SET NULL, zoals site_content.updated_by). Databases die zijn
-- ontstaan vóór een tabel z'n cascade kreeg houden echter de oude constraint:
-- `CREATE TABLE IF NOT EXISTS` werkt een bestaande tabel nooit bij. Op zo'n
-- database geeft het verwijderen van een gebruiker een foreign-key-fout (500
-- "serverfout"). Deze migratie zoekt elke FK naar users die NIET cascade en
-- NIET set-null is, en zet die alsnog op ON DELETE CASCADE - de bewuste
-- SET NULL-constraints blijven ongemoeid.
DO $$
DECLARE
r RECORD;
BEGIN
FOR r IN
SELECT con.conname AS name,
con.conrelid::regclass::text AS tbl,
att.attname AS col
FROM pg_constraint con
JOIN pg_attribute att
ON att.attrelid = con.conrelid AND att.attnum = con.conkey[1]
WHERE con.contype = 'f'
AND con.confrelid = 'users'::regclass
AND array_length(con.conkey, 1) = 1 -- alle user-FK's zijn 1 kolom
AND con.confdeltype NOT IN ('c', 'n') -- niet cascade, niet set null
LOOP
EXECUTE format('ALTER TABLE %s DROP CONSTRAINT %I', r.tbl, r.name);
EXECUTE format(
'ALTER TABLE %s ADD CONSTRAINT %I FOREIGN KEY (%I) REFERENCES users(id) ON DELETE CASCADE',
r.tbl, r.name, r.col);
RAISE NOTICE 'FK % op %(%): ON DELETE CASCADE hersteld', r.name, r.tbl, r.col;
END LOOP;
END $$;