Refactor error handling in sequelize.js to skip model synchronization for cases with duplicate pg_description entries or multiple tables with the same name. Update logging to provide clearer feedback on sync failures and the reasons for skipping models, enhancing user understanding of potential issues.

This commit is contained in:
Torsten Schulz (local)
2025-12-19 08:13:52 +01:00
parent 48110e9a6f
commit 73acf1d1cd

View File

@@ -565,51 +565,17 @@ const syncModelsAlways = async (models) => {
await model.sync({ alter: true, force: false, constraints: false }); await model.sync({ alter: true, force: false, constraints: false });
} catch (syncError) { } catch (syncError) {
// Wenn Sequelize einen "mehr als eine Zeile" Fehler hat, versuche pg_description zu bereinigen // Wenn Sequelize einen "mehr als eine Zeile" Fehler hat, überspringe das Model
// Dies kann durch doppelte pg_description Einträge oder mehrere Tabellen mit demselben Namen verursacht werden
if (syncError.message && (syncError.message.includes('mehr als eine Zeile') || syncError.message.includes('more than one row'))) { if (syncError.message && (syncError.message.includes('mehr als eine Zeile') || syncError.message.includes('more than one row'))) {
console.log(` ⚠️ Sequelize encountered duplicate pg_description entries for ${model.name}`);
console.log(` ⚠️ This requires manual cleanup by a database administrator with superuser privileges.`);
console.log(` ⚠️ SQL to fix (run as superuser):`);
const tableName = model.tableName; const tableName = model.tableName;
const schema = model.options?.schema || 'public'; const schema = model.options?.schema || 'public';
console.log(` ⚠️ DELETE FROM pg_catalog.pg_description d1 WHERE d1.objoid IN (SELECT c.oid FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relname = '${tableName}' AND n.nspname = '${schema}') AND EXISTS (SELECT 1 FROM pg_catalog.pg_description d2 WHERE d2.objoid = d1.objoid AND d2.objsubid = d1.objsubid AND d2.ctid < d1.ctid);`); console.error(` ❌ Cannot sync ${model.name} (${schema}.${tableName}) due to Sequelize describeTable error`);
console.error(` ❌ This is likely caused by multiple tables with the same name in different schemas`);
// Versuche trotzdem zu bereinigen (falls Berechtigung vorhanden) console.error(` ❌ or duplicate pg_description entries (requires superuser to fix)`);
try { console.error(` ⚠️ Skipping sync for ${model.name} - Schema is likely already correct`);
await sequelize.query(` // Überspringe dieses Model und fahre mit dem nächsten fort
DELETE FROM pg_catalog.pg_description d1 continue;
WHERE d1.objoid IN (
SELECT c.oid
FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname = '${tableName.replace(/'/g, "''")}'
AND n.nspname = '${schema.replace(/'/g, "''")}'
)
AND EXISTS (
SELECT 1
FROM pg_catalog.pg_description d2
WHERE d2.objoid = d1.objoid
AND d2.objsubid = d1.objsubid
AND d2.ctid < d1.ctid
)
`);
// Versuche Sync erneut nach Bereinigung
console.log(` 🔄 Retrying sync after cleaning duplicate pg_description entries...`);
await model.sync({ alter: true, force: false, constraints: false });
} catch (retryError) {
// Wenn Berechtigungsfehler, informiere den Benutzer
if (retryError.message && retryError.message.includes('Berechtigung')) {
console.error(` ❌ Cannot clean up pg_description entries - requires superuser privileges`);
console.error(` ❌ Please run the SQL command above as a database superuser, then retry the sync`);
throw syncError; // Wirf den ursprünglichen Fehler
} else {
console.error(` ❌ Retry after pg_description cleanup failed:`, retryError.message);
const combinedError = new Error(`Sync failed: ${syncError.message}. Retry after pg_description cleanup also failed: ${retryError.message}`);
combinedError.originalError = syncError;
combinedError.retryError = retryError;
throw combinedError;
}
}
} }
// Wenn Sequelize versucht, Foreign Keys zu erstellen, entferne sie nach dem Fehler // Wenn Sequelize versucht, Foreign Keys zu erstellen, entferne sie nach dem Fehler
else if (syncError.message && syncError.message.includes('REFERENCES')) { else if (syncError.message && syncError.message.includes('REFERENCES')) {