224 lines
7.2 KiB
PL/PgSQL
224 lines
7.2 KiB
PL/PgSQL
-- Script de migration vers le schéma le plus récent avec liens courts
|
|
-- À exécuter dans votre base de données Supabase
|
|
|
|
-- ========================================
|
|
-- ÉTAPE 1: Ajout des colonnes manquantes
|
|
-- ========================================
|
|
|
|
-- Ajouter la colonne slug aux campagnes si elle n'existe pas
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM information_schema.columns
|
|
WHERE table_name = 'campaigns' AND column_name = 'slug'
|
|
) THEN
|
|
ALTER TABLE campaigns ADD COLUMN slug TEXT UNIQUE;
|
|
RAISE NOTICE 'Colonne slug ajoutée à la table campaigns';
|
|
ELSE
|
|
RAISE NOTICE 'Colonne slug existe déjà dans la table campaigns';
|
|
END IF;
|
|
END $$;
|
|
|
|
-- Ajouter la colonne short_id aux participants si elle n'existe pas
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM information_schema.columns
|
|
WHERE table_name = 'participants' AND column_name = 'short_id'
|
|
) THEN
|
|
ALTER TABLE participants ADD COLUMN short_id TEXT UNIQUE;
|
|
RAISE NOTICE 'Colonne short_id ajoutée à la table participants';
|
|
ELSE
|
|
RAISE NOTICE 'Colonne short_id existe déjà dans la table participants';
|
|
END IF;
|
|
END $$;
|
|
|
|
-- ========================================
|
|
-- ÉTAPE 2: Création des fonctions utilitaires
|
|
-- ========================================
|
|
|
|
-- Fonction pour générer un slug à partir d'un titre
|
|
CREATE OR REPLACE FUNCTION generate_slug(title TEXT)
|
|
RETURNS TEXT AS $$
|
|
DECLARE
|
|
generated_slug TEXT;
|
|
counter INTEGER := 0;
|
|
base_slug TEXT;
|
|
BEGIN
|
|
-- Convertir en minuscules et remplacer les caractères spéciaux
|
|
base_slug := lower(regexp_replace(title, '[^a-zA-Z0-9\s]', '', 'g'));
|
|
base_slug := regexp_replace(base_slug, '\s+', '-', 'g');
|
|
base_slug := trim(both '-' from base_slug);
|
|
|
|
-- Si le slug est vide, utiliser 'campagne'
|
|
IF base_slug = '' THEN
|
|
base_slug := 'campagne';
|
|
END IF;
|
|
|
|
generated_slug := base_slug;
|
|
|
|
-- Vérifier si le slug existe déjà et ajouter un numéro si nécessaire
|
|
WHILE EXISTS (SELECT 1 FROM campaigns WHERE campaigns.slug = generated_slug) LOOP
|
|
counter := counter + 1;
|
|
generated_slug := base_slug || '-' || counter;
|
|
END LOOP;
|
|
|
|
RETURN generated_slug;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- Fonction pour générer un short_id unique
|
|
CREATE OR REPLACE FUNCTION generate_short_id()
|
|
RETURNS TEXT AS $$
|
|
DECLARE
|
|
chars TEXT := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
|
result TEXT := '';
|
|
i INTEGER;
|
|
generated_short_id TEXT;
|
|
counter INTEGER := 0;
|
|
BEGIN
|
|
LOOP
|
|
-- Générer un identifiant de 6 caractères
|
|
result := '';
|
|
FOR i IN 1..6 LOOP
|
|
result := result || substr(chars, floor(random() * length(chars))::integer + 1, 1);
|
|
END LOOP;
|
|
|
|
generated_short_id := result;
|
|
|
|
-- Vérifier si le short_id existe déjà
|
|
IF NOT EXISTS (SELECT 1 FROM participants WHERE participants.short_id = generated_short_id) THEN
|
|
RETURN generated_short_id;
|
|
END IF;
|
|
|
|
-- Éviter les boucles infinies
|
|
counter := counter + 1;
|
|
IF counter > 100 THEN
|
|
RAISE EXCEPTION 'Impossible de générer un short_id unique après 100 tentatives';
|
|
END IF;
|
|
END LOOP;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- ========================================
|
|
-- ÉTAPE 3: Mise à jour des données existantes
|
|
-- ========================================
|
|
|
|
-- Générer des slugs pour les campagnes qui n'en ont pas
|
|
UPDATE campaigns
|
|
SET slug = generate_slug(title)
|
|
WHERE slug IS NULL;
|
|
|
|
-- Générer des short_ids pour les participants qui n'en ont pas
|
|
UPDATE participants
|
|
SET short_id = generate_short_id()
|
|
WHERE short_id IS NULL;
|
|
|
|
-- ========================================
|
|
-- ÉTAPE 4: Création des index manquants
|
|
-- ========================================
|
|
|
|
-- Index pour les slugs de campagnes
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM pg_indexes
|
|
WHERE indexname = 'idx_campaigns_slug'
|
|
) THEN
|
|
CREATE INDEX idx_campaigns_slug ON campaigns(slug);
|
|
RAISE NOTICE 'Index idx_campaigns_slug créé';
|
|
ELSE
|
|
RAISE NOTICE 'Index idx_campaigns_slug existe déjà';
|
|
END IF;
|
|
END $$;
|
|
|
|
-- Index pour les short_ids de participants
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM pg_indexes
|
|
WHERE indexname = 'idx_participants_short_id'
|
|
) THEN
|
|
CREATE INDEX idx_participants_short_id ON participants(short_id);
|
|
RAISE NOTICE 'Index idx_participants_short_id créé';
|
|
ELSE
|
|
RAISE NOTICE 'Index idx_participants_short_id existe déjà';
|
|
END IF;
|
|
END $$;
|
|
|
|
-- ========================================
|
|
-- ÉTAPE 5: Fonction pour remplacer les votes
|
|
-- ========================================
|
|
|
|
-- Fonction pour remplacer tous les votes d'un participant de manière atomique
|
|
CREATE OR REPLACE FUNCTION replace_participant_votes(
|
|
p_campaign_id UUID,
|
|
p_participant_id UUID,
|
|
p_votes JSONB
|
|
)
|
|
RETURNS VOID AS $$
|
|
DECLARE
|
|
vote_record RECORD;
|
|
BEGIN
|
|
-- Commencer une transaction
|
|
BEGIN
|
|
-- Supprimer tous les votes existants pour ce participant dans cette campagne
|
|
DELETE FROM votes
|
|
WHERE campaign_id = p_campaign_id
|
|
AND participant_id = p_participant_id;
|
|
|
|
-- Insérer les nouveaux votes
|
|
FOR vote_record IN
|
|
SELECT * FROM jsonb_array_elements(p_votes)
|
|
LOOP
|
|
INSERT INTO votes (campaign_id, participant_id, proposition_id, amount)
|
|
VALUES (
|
|
p_campaign_id,
|
|
p_participant_id,
|
|
(vote_record.value->>'proposition_id')::UUID,
|
|
(vote_record.value->>'amount')::INTEGER
|
|
);
|
|
END LOOP;
|
|
|
|
-- La transaction sera automatiquement commitée si tout va bien
|
|
EXCEPTION
|
|
WHEN OTHERS THEN
|
|
-- En cas d'erreur, la transaction sera automatiquement rollbackée
|
|
RAISE EXCEPTION 'Erreur lors du remplacement des votes: %', SQLERRM;
|
|
END;
|
|
END;
|
|
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
|
|
|
-- ========================================
|
|
-- ÉTAPE 6: Vérification et rapport
|
|
-- ========================================
|
|
|
|
-- Afficher un rapport de la migration
|
|
DO $$
|
|
DECLARE
|
|
campaign_count INTEGER;
|
|
participant_count INTEGER;
|
|
campaign_with_slug INTEGER;
|
|
participant_with_short_id INTEGER;
|
|
BEGIN
|
|
-- Compter les campagnes
|
|
SELECT COUNT(*) INTO campaign_count FROM campaigns;
|
|
SELECT COUNT(*) INTO campaign_with_slug FROM campaigns WHERE slug IS NOT NULL;
|
|
|
|
-- Compter les participants
|
|
SELECT COUNT(*) INTO participant_count FROM participants;
|
|
SELECT COUNT(*) INTO participant_with_short_id FROM participants WHERE short_id IS NOT NULL;
|
|
|
|
RAISE NOTICE '=== RAPPORT DE MIGRATION ===';
|
|
RAISE NOTICE 'Campagnes totales: %', campaign_count;
|
|
RAISE NOTICE 'Campagnes avec slug: %', campaign_with_slug;
|
|
RAISE NOTICE 'Participants totaux: %', participant_count;
|
|
RAISE NOTICE 'Participants avec short_id: %', participant_with_short_id;
|
|
|
|
IF campaign_count = campaign_with_slug AND participant_count = participant_with_short_id THEN
|
|
RAISE NOTICE '✅ Migration réussie ! Toutes les données ont été migrées.';
|
|
ELSE
|
|
RAISE NOTICE '⚠️ Attention: Certaines données n''ont pas été migrées.';
|
|
END IF;
|
|
END $$;
|