import { sequelize } from './sequelize.js'; /** * Bereinigt doppelte Constraints und Indexe in der Datenbank * Dies sollte nur einmal ausgeführt werden, um bestehende Probleme zu beheben */ async function cleanupDatabaseConstraints() { try { console.log('🧹 Starte Bereinigung der Datenbank-Constraints...'); // 1. Spezielle Bereinigung für community.user Tabelle console.log('🔍 Spezielle Bereinigung für community.user Tabelle...'); await cleanupUserTableConstraints(); // 2. Doppelte UNIQUE Constraints entfernen console.log('🔍 Suche nach doppelten UNIQUE Constraints...'); const duplicateUniqueConstraints = await sequelize.query(` SELECT tc.table_schema, tc.table_name, kcu.column_name, COUNT(*) as constraint_count, array_agg(tc.constraint_name) as constraint_names FROM information_schema.table_constraints tc JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name WHERE tc.constraint_type = 'UNIQUE' AND tc.table_schema IN ('match3', 'community', 'falukant_data', 'falukant_type', 'falukant_predefine', 'falukant_log', 'chat', 'forum', 'logs', 'type', 'service') GROUP BY tc.table_schema, tc.table_name, kcu.column_name HAVING COUNT(*) > 1 ORDER BY tc.table_name, kcu.column_name; `, { type: sequelize.QueryTypes.SELECT }); console.log(`📊 Gefunden: ${duplicateUniqueConstraints.length} Spalten mit doppelten UNIQUE Constraints`); // Entferne doppelte UNIQUE Constraints for (const duplicate of duplicateUniqueConstraints) { console.log(`🗑️ Entferne doppelte UNIQUE Constraints für ${duplicate.table_schema}.${duplicate.table_name}.${duplicate.column_name}`); // Behalte den ersten Constraint, entferne die anderen const constraintNames = duplicate.constraint_names; for (let i = 1; i < constraintNames.length; i++) { const constraintName = constraintNames[i]; try { await sequelize.query(` ALTER TABLE ${duplicate.table_schema}.${duplicate.table_name} DROP CONSTRAINT IF EXISTS "${constraintName}" `); console.log(` ✅ Entfernt: ${constraintName}`); } catch (error) { console.log(` ⚠️ Konnte nicht entfernen: ${constraintName} - ${error.message}`); } } } // 3. Entferne alle Constraints mit numerischen Suffixen console.log('🔍 Entferne alle Constraints mit numerischen Suffixen...'); await removeNumericalSuffixConstraints(); // 4. Doppelte CHECK Constraints entfernen (korrigierte Abfrage) console.log('🔍 Suche nach doppelten CHECK Constraints...'); try { const duplicateCheckConstraints = await sequelize.query(` SELECT ttc.table_schema, ttc.table_name, tc.constraint_name, tc.check_clause FROM information_schema.check_constraints tc JOIN information_schema.table_constraints ttc ON tc.constraint_name = ttc.constraint_name WHERE ttc.table_schema IN ('match3', 'community', 'falukant_data', 'falukant_type', 'falukant_predefine', 'falukant_log', 'chat', 'forum', 'logs', 'type', 'service') ORDER BY ttc.table_name, tc.constraint_name; `, { type: sequelize.QueryTypes.SELECT }); console.log(`📊 Gefunden: ${duplicateCheckConstraints.length} CHECK Constraints`); } catch (error) { console.log(`⚠️ Konnte CHECK Constraints nicht abfragen: ${error.message}`); } // 5. Doppelte Foreign Key Constraints entfernen console.log('🔍 Suche nach doppelten Foreign Key Constraints...'); const duplicateFKs = await sequelize.query(` SELECT tc.constraint_name, tc.table_name, tc.table_schema, kcu.column_name, ccu.table_name AS foreign_table_name, ccu.column_name AS foreign_column_name FROM information_schema.table_constraints tc JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name JOIN information_schema.constraint_column_usage ccu ON ccu.constraint_name = tc.constraint_name WHERE tc.constraint_type = 'FOREIGN KEY' AND tc.table_schema IN ('match3', 'community', 'falukant_data', 'falukant_type', 'falukant_predefine', 'falukant_log', 'chat', 'forum', 'logs', 'type', 'service') ORDER BY tc.table_name, tc.constraint_name; `, { type: sequelize.QueryTypes.SELECT }); console.log(`📊 Gefunden: ${duplicateFKs.length} Foreign Key Constraints`); // 6. Doppelte Indexe entfernen console.log('🔍 Suche nach doppelten Indexen...'); const duplicateIndexes = await sequelize.query(` SELECT schemaname, tablename, indexname, indexdef FROM pg_indexes WHERE schemaname IN ('match3', 'community', 'falukant_data', 'falukant_type', 'falukant_predefine', 'falukant_log', 'chat', 'forum', 'logs', 'type', 'service') AND indexname LIKE '%_index_%' ORDER BY tablename, indexname; `, { type: sequelize.QueryTypes.SELECT }); console.log(`📊 Gefunden: ${duplicateIndexes.length} potenziell doppelte Indexe`); // 7. Spezifische Match3-Constraints prüfen console.log('🔍 Prüfe Match3-spezifische Constraints...'); const match3Constraints = await sequelize.query(` SELECT constraint_name, table_name, constraint_type FROM information_schema.table_constraints WHERE table_schema = 'match3' ORDER BY table_name, constraint_type; `, { type: sequelize.QueryTypes.SELECT }); console.log(`📊 Match3 Constraints: ${match3Constraints.length} gefunden`); match3Constraints.forEach(constraint => { console.log(` - ${constraint.table_name}: ${constraint.constraint_type} (${constraint.constraint_name})`); }); // 8. Spezifische Chat-Constraints prüfen (da das Problem dort auftritt) console.log('🔍 Prüfe Chat-spezifische Constraints...'); try { const chatConstraints = await sequelize.query(` SELECT tc.constraint_name, tc.table_name, tc.constraint_type, kcu.column_name FROM information_schema.table_constraints tc LEFT JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name WHERE tc.table_schema = 'chat' ORDER BY tc.table_name, tc.constraint_type, kcu.column_name; `, { type: sequelize.QueryTypes.SELECT }); console.log(`📊 Chat Constraints: ${chatConstraints.length} gefunden`); chatConstraints.forEach(constraint => { console.log(` - ${constraint.table_name}: ${constraint.constraint_type} (${constraint.constraint_name}) auf Spalte: ${constraint.column_name}`); }); } catch (error) { console.log(`⚠️ Konnte Chat Constraints nicht abfragen: ${error.message}`); } // 9. Spezifische Überprüfung der chat.rights Tabelle console.log('🔍 Spezielle Überprüfung der chat.rights Tabelle...'); try { const rightsConstraints = await sequelize.query(` SELECT tc.constraint_name, tc.constraint_type, kcu.column_name FROM information_schema.table_constraints tc LEFT JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name WHERE tc.table_schema = 'chat' AND tc.table_name = 'rights' ORDER BY tc.constraint_type, kcu.column_name; `, { type: sequelize.QueryTypes.SELECT }); console.log(`📊 Chat Rights Constraints: ${rightsConstraints.length} gefunden`); rightsConstraints.forEach(constraint => { console.log(` - ${constraint.constraint_type} (${constraint.constraint_name}) auf Spalte: ${constraint.column_name}`); }); // Entferne alle doppelten UNIQUE Constraints auf der tr-Spalte const trUniqueConstraints = rightsConstraints.filter(c => c.constraint_type === 'UNIQUE' && c.column_name === 'tr' ); if (trUniqueConstraints.length > 1) { console.log(`🗑️ Entferne ${trUniqueConstraints.length - 1} doppelte UNIQUE Constraints auf chat.rights.tr`); // Behalte den ersten, entferne die anderen for (let i = 1; i < trUniqueConstraints.length; i++) { const constraintName = trUniqueConstraints[i].constraint_name; try { await sequelize.query(` ALTER TABLE chat.rights DROP CONSTRAINT IF EXISTS "${constraintName}" `); console.log(` ✅ Entfernt: ${constraintName}`); } catch (error) { console.log(` ⚠️ Konnte nicht entfernen: ${constraintName} - ${error.message}`); } } } } catch (error) { console.log(`⚠️ Konnte chat.rights Constraints nicht abfragen: ${error.message}`); } // 10. Empfehlungen ausgeben console.log('\n💡 Empfehlungen:'); console.log('1. Überprüfe die oben gelisteten Constraints auf Duplikate'); console.log('2. Verwende updateSchema() nur bei expliziten Schema-Änderungen'); console.log('3. Normale syncModels() läuft jetzt ohne alter: true'); console.log('4. Bei Problemen: Manuelle Bereinigung der doppelten Constraints'); console.log('✅ Datenbank-Constraint-Bereinigung abgeschlossen'); } catch (error) { console.error('❌ Fehler bei der Constraint-Bereinigung:', error); throw error; } } /** * Spezielle Bereinigung für die community.user Tabelle * Entfernt alle Constraints mit numerischen Suffixen */ async function cleanupUserTableConstraints() { try { console.log('🔍 Bereinige community.user Tabelle...'); // Finde alle Constraints der user Tabelle const userConstraints = await sequelize.query(` SELECT tc.constraint_name, tc.constraint_type, kcu.column_name FROM information_schema.table_constraints tc LEFT JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name WHERE tc.table_schema = 'community' AND tc.table_name = 'user' ORDER BY tc.constraint_type, kcu.column_name; `, { type: sequelize.QueryTypes.SELECT }); console.log(`📊 Community.user Constraints gefunden: ${userConstraints.length}`); // Gruppiere Constraints nach Spalte und Typ const constraintsByColumn = {}; userConstraints.forEach(constraint => { const key = `${constraint.constraint_type}_${constraint.column_name || 'general'}`; if (!constraintsByColumn[key]) { constraintsByColumn[key] = []; } constraintsByColumn[key].push(constraint.constraint_name); }); // Entferne doppelte Constraints, behalte nur einen pro Spalte/Typ for (const [key, constraintNames] of Object.entries(constraintsByColumn)) { if (constraintNames.length > 1) { console.log(`🗑️ Entferne ${constraintNames.length - 1} doppelte Constraints für ${key}`); // Sortiere nach Namen, um konsistente Ergebnisse zu erhalten constraintNames.sort(); // Behalte den ersten, entferne die anderen for (let i = 1; i < constraintNames.length; i++) { const constraintName = constraintNames[i]; try { await sequelize.query(` ALTER TABLE community."user" DROP CONSTRAINT IF EXISTS "${constraintName}" `); console.log(` ✅ Entfernt: ${constraintName}`); } catch (error) { console.log(` ⚠️ Konnte nicht entfernen: ${constraintName} - ${error.message}`); } } } } // Entferne alle Constraints mit numerischen Suffixen const numericalConstraints = userConstraints.filter(c => /\d+$/.test(c.constraint_name) && (c.constraint_name.includes('_key') || c.constraint_name.includes('_index')) ); if (numericalConstraints.length > 0) { console.log(`🗑️ Entferne ${numericalConstraints.length} Constraints mit numerischen Suffixen`); for (const constraint of numericalConstraints) { try { await sequelize.query(` ALTER TABLE community."user" DROP CONSTRAINT IF EXISTS "${constraint.constraint_name}" `); console.log(` ✅ Entfernt: ${constraint.constraint_name}`); } catch (error) { console.log(` ⚠️ Konnte nicht entfernen: ${constraint.constraint_name} - ${error.message}`); } } } } catch (error) { console.log(`⚠️ Konnte community.user Constraints nicht bereinigen: ${error.message}`); } } /** * Entfernt alle Constraints mit numerischen Suffixen aus allen Tabellen */ async function removeNumericalSuffixConstraints() { try { console.log('🔍 Entferne alle Constraints mit numerischen Suffixen...'); // Finde alle Constraints mit numerischen Suffixen const numericalConstraints = await sequelize.query(` SELECT tc.table_schema, tc.table_name, tc.constraint_name, tc.constraint_type FROM information_schema.table_constraints tc WHERE tc.table_schema IN ('match3', 'community', 'falukant_data', 'falukant_type', 'falukant_predefine', 'falukant_log', 'chat', 'forum', 'logs', 'type', 'service') AND tc.constraint_name ~ '.*\\d+$' AND (tc.constraint_name LIKE '%_key%' OR tc.constraint_name LIKE '%_index%') ORDER BY tc.table_schema, tc.table_name, tc.constraint_name; `, { type: sequelize.QueryTypes.SELECT }); console.log(`📊 Gefunden: ${numericalConstraints.length} Constraints mit numerischen Suffixen`); if (numericalConstraints.length > 0) { for (const constraint of numericalConstraints) { try { await sequelize.query(` ALTER TABLE ${constraint.table_schema}.${constraint.table_name} DROP CONSTRAINT IF EXISTS "${constraint.constraint_name}" `); console.log(` ✅ Entfernt: ${constraint.table_schema}.${constraint.table_name}.${constraint.constraint_name}`); } catch (error) { console.log(` ⚠️ Konnte nicht entfernen: ${constraint.constraint_name} - ${error.message}`); } } } } catch (error) { console.log(`⚠️ Konnte numerische Suffix-Constraints nicht entfernen: ${error.message}`); } } // Führe das Skript aus, wenn es direkt aufgerufen wird if (import.meta.url === `file://${process.argv[1]}`) { cleanupDatabaseConstraints() .then(() => { console.log('🎯 Datenbank-Constraint-Bereinigung abgeschlossen'); process.exit(0); }) .catch((error) => { console.error('💥 Datenbank-Constraint-Bereinigung fehlgeschlagen:', error); process.exit(1); }); } export default cleanupDatabaseConstraints;