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.

This commit is contained in:
Torsten Schulz (local)
2025-12-18 17:53:24 +01:00
parent 86f753c745
commit 091b9ff70a

View File

@@ -530,10 +530,95 @@ const syncModelsAlways = async (models) => {
console.log(` 🔄 Syncing model ${model.name} with constraints: false`); console.log(` 🔄 Syncing model ${model.name} with constraints: false`);
try { 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 }); await model.sync({ alter: true, force: false, constraints: false });
} catch (syncError) { } 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 // 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...`); console.log(` ⚠️ Sequelize tried to create FK despite constraints: false, removing any created FKs...`);
try { try {
const tableName = model.tableName; const tableName = model.tableName;