From 091b9ff70a8d2c2c400d6e5ee596f91ecd654a7e Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Thu, 18 Dec 2025 17:53:24 +0100 Subject: [PATCH] Enhance model synchronization in sequelize.js by adding logic to clean up duplicate pg_description entries before and after sync attempts. Implement error handling for potential sync failures related to duplicate entries, improving robustness and clarity in foreign key management during model synchronization. --- backend/utils/sequelize.js | 87 +++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/backend/utils/sequelize.js b/backend/utils/sequelize.js index 2dee9a6..fb608c1 100644 --- a/backend/utils/sequelize.js +++ b/backend/utils/sequelize.js @@ -530,10 +530,95 @@ const syncModelsAlways = async (models) => { console.log(` 🔄 Syncing model ${model.name} with constraints: false`); try { + // Bereinige doppelte pg_description Einträge vor dem Sync, um "mehr als eine Zeile" Fehler zu vermeiden + try { + const tableName = model.tableName; + const schema = model.options?.schema || 'public'; + await sequelize.query(` + DO $$ + DECLARE + table_oid oid; + dup_count integer; + BEGIN + -- Finde die OID der Tabelle + SELECT oid INTO table_oid + FROM pg_catalog.pg_class c + JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace + WHERE c.relname = $1 + AND n.nspname = $2; + + IF table_oid IS NOT NULL THEN + -- Entferne doppelte pg_description Einträge, behalte nur den ersten + DELETE FROM pg_catalog.pg_description d1 + WHERE d1.objoid = table_oid + 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 + ); + + GET DIAGNOSTICS dup_count = ROW_COUNT; + END IF; + END $$; + `, { + bind: [tableName, schema] + }); + } catch (descError) { + console.warn(` ⚠️ Could not clean up duplicate pg_description entries for ${model.name}:`, descError.message); + } + await model.sync({ alter: true, force: false, constraints: false }); } catch (syncError) { + // Wenn Sequelize einen "mehr als eine Zeile" Fehler hat, bereinige pg_description und versuche erneut + 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, cleaning up and retrying...`); + try { + const tableName = model.tableName; + const schema = model.options?.schema || 'public'; + await sequelize.query(` + DO $$ + DECLARE + table_oid oid; + BEGIN + -- Finde die OID der Tabelle + SELECT oid INTO table_oid + FROM pg_catalog.pg_class c + JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace + WHERE c.relname = $1 + AND n.nspname = $2; + + IF table_oid IS NOT NULL THEN + -- Entferne doppelte pg_description Einträge, behalte nur den ersten + DELETE FROM pg_catalog.pg_description d1 + WHERE d1.objoid = table_oid + 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 + ); + END IF; + END $$; + `, { + bind: [tableName, schema] + }); + // 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) { + console.error(` ❌ Retry after pg_description cleanup failed:`, retryError.message); + // Kombiniere beide Fehler für besseres Debugging + 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 - if (syncError.message && syncError.message.includes('REFERENCES')) { + else if (syncError.message && syncError.message.includes('REFERENCES')) { console.log(` ⚠️ Sequelize tried to create FK despite constraints: false, removing any created FKs...`); try { const tableName = model.tableName;