- Hinzufügen eines zentralen Skripts zum Laden von Umgebungsvariablen aus einer .env-Datei. - Implementierung von Start- und Entwicklungs-Skripten in der package.json für eine vereinfachte Ausführung der Anwendung. - Bereinigung und Entfernung nicht mehr benötigter Minigame-Modelle und -Services zur Verbesserung der Codebasis. - Anpassungen an den Datenbankmodellen zur Unterstützung von neuen Assoziationen und zur Verbesserung der Lesbarkeit.
370 lines
17 KiB
JavaScript
370 lines
17 KiB
JavaScript
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;
|