-- Migration: Convertir users.id de BIGINT vers UUID -- CRITIQUE: Cette migration doit être exécutée AVANT tout déploiement utilisant les nouveaux modèles UUID -- Date: 2024-11-27 -- Impact: BREAKING CHANGE - Toutes les FK doivent être migrées -- ===================================================== -- ÉTAPE 1: Créer une colonne temporaire UUID -- ===================================================== -- Activer l'extension UUID si pas déjà fait CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE EXTENSION IF NOT EXISTS "pgcrypto"; -- Pour gen_random_uuid() -- Ajouter une colonne temporaire pour stocker les nouveaux UUIDs ALTER TABLE users ADD COLUMN IF NOT EXISTS id_uuid UUID; -- Générer un UUID pour chaque utilisateur existant (mapping déterministe depuis l'ID) -- Note: On utilise uuid_generate_v5 pour créer un UUID déterministe basé sur l'ID existant UPDATE users SET id_uuid = uuid_generate_v5( '6ba7b810-9dad-11d1-80b4-00c04fd430c8'::uuid, -- Namespace UUID arbitraire mais fixe id::text ) WHERE id_uuid IS NULL; -- ===================================================== -- ÉTAPE 2: Migrer les tables dépendantes (FK) -- ===================================================== -- Pour chaque table avec user_id en BIGINT, créer une colonne temporaire UUID -- user_roles ALTER TABLE user_roles ADD COLUMN IF NOT EXISTS user_id_uuid UUID; UPDATE user_roles ur SET user_id_uuid = u.id_uuid FROM users u WHERE ur.user_id = u.id AND ur.user_id_uuid IS NULL; -- tracks ALTER TABLE tracks ADD COLUMN IF NOT EXISTS user_id_uuid UUID; UPDATE tracks t SET user_id_uuid = u.id_uuid FROM users u WHERE t.user_id = u.id AND t.user_id_uuid IS NULL; -- playlists ALTER TABLE playlists ADD COLUMN IF NOT EXISTS user_id_uuid UUID; UPDATE playlists p SET user_id_uuid = u.id_uuid FROM users u WHERE p.user_id = u.id AND p.user_id_uuid IS NULL; -- refresh_tokens ALTER TABLE refresh_tokens ADD COLUMN IF NOT EXISTS user_id_uuid UUID; UPDATE refresh_tokens rt SET user_id_uuid = u.id_uuid FROM users u WHERE rt.user_id = u.id AND rt.user_id_uuid IS NULL; -- sessions (déjà en UUID, mais vérifier cohérence) -- Si sessions.user_id est déjà UUID, créer un mapping inverse -- Note: Cette table semble déjà utiliser UUID, donc on va juste s'assurer de la cohérence -- UPDATE sessions s SET user_id = u.id_uuid FROM users u WHERE ... (si nécessaire) -- messages ALTER TABLE messages ADD COLUMN IF NOT EXISTS sender_id_uuid UUID; UPDATE messages m SET sender_id_uuid = u.id_uuid FROM users u WHERE m.sender_id = u.id AND m.sender_id_uuid IS NULL; -- rooms (owner_id) ALTER TABLE rooms ADD COLUMN IF NOT EXISTS owner_id_uuid UUID; UPDATE rooms r SET owner_id_uuid = u.id_uuid FROM users u WHERE r.owner_id = u.id AND r.owner_id_uuid IS NULL; -- room_members ALTER TABLE room_members ADD COLUMN IF NOT EXISTS user_id_uuid UUID; UPDATE room_members rm SET user_id_uuid = u.id_uuid FROM users u WHERE rm.user_id = u.id AND rm.user_id_uuid IS NULL; -- track_likes ALTER TABLE track_likes ADD COLUMN IF NOT EXISTS user_id_uuid UUID; UPDATE track_likes tl SET user_id_uuid = u.id_uuid FROM users u WHERE tl.user_id = u.id AND tl.user_id_uuid IS NULL; -- track_comments ALTER TABLE track_comments ADD COLUMN IF NOT EXISTS user_id_uuid UUID; UPDATE track_comments tc SET user_id_uuid = u.id_uuid FROM users u WHERE tc.user_id = u.id AND tc.user_id_uuid IS NULL; -- track_shares ALTER TABLE track_shares ADD COLUMN IF NOT EXISTS user_id_uuid UUID; UPDATE track_shares ts SET user_id_uuid = u.id_uuid FROM users u WHERE ts.user_id = u.id AND ts.user_id_uuid IS NULL; -- playlist_collaborators ALTER TABLE playlist_collaborators ADD COLUMN IF NOT EXISTS user_id_uuid UUID; UPDATE playlist_collaborators pc SET user_id_uuid = u.id_uuid FROM users u WHERE pc.user_id = u.id AND pc.user_id_uuid IS NULL; -- playlist_follows ALTER TABLE playlist_follows ADD COLUMN IF NOT EXISTS user_id_uuid UUID; UPDATE playlist_follows pf SET user_id_uuid = u.id_uuid FROM users u WHERE pf.user_id = u.id AND pf.user_id_uuid IS NULL; -- user_settings ALTER TABLE user_settings ADD COLUMN IF NOT EXISTS user_id_uuid UUID; UPDATE user_settings us SET user_id_uuid = u.id_uuid FROM users u WHERE us.user_id = u.id AND us.user_id_uuid IS NULL; -- ===================================================== -- ÉTAPE 3: Supprimer anciennes colonnes et renommer UUID -- ===================================================== -- NOTE: Ces étapes sont DESTRUCTIVES et ne peuvent être annulées sans backup -- En production, exécuter avec précaution et APRÈS validation complète -- Supprimer les anciennes FK constraints ALTER TABLE user_roles DROP CONSTRAINT IF EXISTS user_roles_user_id_fkey; ALTER TABLE tracks DROP CONSTRAINT IF EXISTS tracks_user_id_fkey; ALTER TABLE playlists DROP CONSTRAINT IF EXISTS playlists_user_id_fkey; ALTER TABLE refresh_tokens DROP CONSTRAINT IF EXISTS refresh_tokens_user_id_fkey; ALTER TABLE messages DROP CONSTRAINT IF EXISTS messages_sender_id_fkey; ALTER TABLE rooms DROP CONSTRAINT IF EXISTS rooms_owner_id_fkey; ALTER TABLE room_members DROP CONSTRAINT IF EXISTS room_members_user_id_fkey; ALTER TABLE track_likes DROP CONSTRAINT IF EXISTS track_likes_user_id_fkey; ALTER TABLE track_comments DROP CONSTRAINT IF EXISTS track_comments_user_id_fkey; ALTER TABLE track_shares DROP CONSTRAINT IF EXISTS track_shares_user_id_fkey; ALTER TABLE playlist_collaborators DROP CONSTRAINT IF EXISTS playlist_collaborators_user_id_fkey; ALTER TABLE playlist_follows DROP CONSTRAINT IF EXISTS playlist_follows_user_id_fkey; ALTER TABLE user_settings DROP CONSTRAINT IF EXISTS user_settings_user_id_fkey; -- Supprimer anciennes colonnes INT ALTER TABLE user_roles DROP COLUMN IF EXISTS user_id; ALTER TABLE tracks DROP COLUMN IF EXISTS user_id; ALTER TABLE playlists DROP COLUMN IF EXISTS user_id; ALTER TABLE refresh_tokens DROP COLUMN IF EXISTS user_id; ALTER TABLE messages DROP COLUMN IF EXISTS sender_id; ALTER TABLE rooms DROP COLUMN IF EXISTS owner_id; ALTER TABLE room_members DROP COLUMN IF EXISTS user_id; ALTER TABLE track_likes DROP COLUMN IF EXISTS user_id; ALTER TABLE track_comments DROP COLUMN IF EXISTS user_id; ALTER TABLE track_shares DROP COLUMN IF EXISTS user_id; ALTER TABLE playlist_collaborators DROP COLUMN IF EXISTS user_id; ALTER TABLE playlist_follows DROP COLUMN IF EXISTS user_id; ALTER TABLE user_settings DROP COLUMN IF EXISTS user_id; -- Renommer colonnes UUID vers le nom standard ALTER TABLE user_roles RENAME COLUMN user_id_uuid TO user_id; ALTER TABLE tracks RENAME COLUMN user_id_uuid TO user_id; ALTER TABLE playlists RENAME COLUMN user_id_uuid TO user_id; ALTER TABLE refresh_tokens RENAME COLUMN user_id_uuid TO user_id; ALTER TABLE messages RENAME COLUMN sender_id_uuid TO sender_id; ALTER TABLE rooms RENAME COLUMN owner_id_uuid TO owner_id; ALTER TABLE room_members RENAME COLUMN user_id_uuid TO user_id; ALTER TABLE track_likes RENAME COLUMN user_id_uuid TO user_id; ALTER TABLE track_comments RENAME COLUMN user_id_uuid TO user_id; ALTER TABLE track_shares RENAME COLUMN user_id_uuid TO user_id; ALTER TABLE playlist_collaborators RENAME COLUMN user_id_uuid TO user_id; ALTER TABLE playlist_follows RENAME COLUMN user_id_uuid TO user_id; ALTER TABLE user_settings RENAME COLUMN user_id_uuid TO user_id; -- Définir NOT NULL sur les colonnes ALTER TABLE user_roles ALTER COLUMN user_id SET NOT NULL; ALTER TABLE tracks ALTER COLUMN user_id SET NOT NULL; ALTER TABLE playlists ALTER COLUMN user_id SET NOT NULL; ALTER TABLE refresh_tokens ALTER COLUMN user_id SET NOT NULL; ALTER TABLE messages ALTER COLUMN sender_id SET NOT NULL; ALTER TABLE rooms ALTER COLUMN owner_id SET NOT NULL; ALTER TABLE room_members ALTER COLUMN user_id SET NOT NULL; ALTER TABLE track_likes ALTER COLUMN user_id SET NOT NULL; ALTER TABLE track_comments ALTER COLUMN user_id SET NOT NULL; ALTER TABLE track_shares ALTER COLUMN user_id SET NOT NULL; ALTER TABLE playlist_collaborators ALTER COLUMN user_id SET NOT NULL; ALTER TABLE playlist_follows ALTER COLUMN user_id SET NOT NULL; ALTER TABLE user_settings ALTER COLUMN user_id SET NOT NULL; -- ===================================================== -- ÉTAPE 4: Migrer users.id vers UUID -- ===================================================== -- Supprimer l'ancienne colonne id (BIGINT) ALTER TABLE users DROP CONSTRAINT IF EXISTS users_pkey; ALTER TABLE users DROP COLUMN IF EXISTS id; -- Renommer id_uuid vers id ALTER TABLE users RENAME COLUMN id_uuid TO id; -- Définir comme PRIMARY KEY ALTER TABLE users ADD PRIMARY KEY (id); -- ===================================================== -- ÉTAPE 5: Recréer les FK constraints avec UUID -- ===================================================== ALTER TABLE user_roles ADD CONSTRAINT fk_user_roles_users FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; ALTER TABLE tracks ADD CONSTRAINT fk_tracks_users FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; ALTER TABLE playlists ADD CONSTRAINT fk_playlists_users FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; ALTER TABLE refresh_tokens ADD CONSTRAINT fk_refresh_tokens_users FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; ALTER TABLE messages ADD CONSTRAINT fk_messages_users FOREIGN KEY (sender_id) REFERENCES users(id) ON DELETE CASCADE; ALTER TABLE rooms ADD CONSTRAINT fk_rooms_users FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE CASCADE; ALTER TABLE room_members ADD CONSTRAINT fk_room_members_users FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; ALTER TABLE track_likes ADD CONSTRAINT fk_track_likes_users FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; ALTER TABLE track_comments ADD CONSTRAINT fk_track_comments_users FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; ALTER TABLE track_shares ADD CONSTRAINT fk_track_shares_users FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; ALTER TABLE playlist_collaborators ADD CONSTRAINT fk_playlist_collaborators_users FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; ALTER TABLE playlist_follows ADD CONSTRAINT fk_playlist_follows_users FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; ALTER TABLE user_settings ADD CONSTRAINT fk_user_settings_users FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; -- ===================================================== -- ÉTAPE 6: Recréer les indexes -- ===================================================== CREATE INDEX IF NOT EXISTS idx_user_roles_user_id ON user_roles(user_id); CREATE INDEX IF NOT EXISTS idx_tracks_user_id ON tracks(user_id); CREATE INDEX IF NOT EXISTS idx_playlists_user_id ON playlists(user_id); CREATE INDEX IF NOT EXISTS idx_refresh_tokens_user_id ON refresh_tokens(user_id); CREATE INDEX IF NOT EXISTS idx_messages_sender_id ON messages(sender_id); CREATE INDEX IF NOT EXISTS idx_rooms_owner_id ON rooms(owner_id); CREATE INDEX IF NOT EXISTS idx_room_members_user_id ON room_members(user_id); CREATE INDEX IF NOT EXISTS idx_track_likes_user_id ON track_likes(user_id); CREATE INDEX IF NOT EXISTS idx_track_comments_user_id ON track_comments(user_id); CREATE INDEX IF NOT EXISTS idx_track_shares_user_id ON track_shares(user_id); CREATE INDEX IF NOT EXISTS idx_playlist_collaborators_user_id ON playlist_collaborators(user_id); CREATE INDEX IF NOT EXISTS idx_playlist_follows_user_id ON playlist_follows(user_id); CREATE INDEX IF NOT EXISTS idx_user_settings_user_id ON user_settings(user_id); -- ===================================================== -- VERIFICATION -- ===================================================== -- Vérifier que tous les users ont un UUID valide DO $$ DECLARE user_count INT; null_uuid_count INT; BEGIN SELECT COUNT(*) INTO user_count FROM users; SELECT COUNT(*) INTO null_uuid_count FROM users WHERE id IS NULL; RAISE NOTICE 'Migration UUID - Total users: %, Users avec UUID NULL: %', user_count, null_uuid_count; IF null_uuid_count > 0 THEN RAISE EXCEPTION 'Migration échouée: % utilisateurs ont un UUID NULL', null_uuid_count; END IF; END $$; -- Vérifier l'intégrité référentielle -- TODO: Ajouter des checks supplémentaires si nécessaire COMMENT ON COLUMN users.id IS 'UUID unique de l''utilisateur (migré de BIGINT)';