veza/veza-backend-api/migrations/047_migrate_users_id_to_uuid.sql
2025-12-03 20:29:37 +01:00

307 lines
12 KiB
SQL

-- 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)';