From ea8b9e661d1d71ebd0cc7bdd1f8c46455f322616 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Thu, 18 Dec 2025 15:37:52 +0100 Subject: [PATCH] Refactor VIRTUAL field detection logic in sequelize.js to improve accuracy and add special handling for Notification model's characterName field, addressing a Sequelize bug related to field mapping. --- backend/utils/sequelize.js | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/backend/utils/sequelize.js b/backend/utils/sequelize.js index d81f18f..dc1d387 100644 --- a/backend/utils/sequelize.js +++ b/backend/utils/sequelize.js @@ -428,33 +428,29 @@ const syncModelsAlways = async (models) => { let isVirtual = false; if (attr.type) { - // Method 1: Direct comparison with DataTypes.VIRTUAL - if (attr.type === DataTypes.VIRTUAL) { + // Method 1: Check if type key is VIRTUAL (most reliable) + if (attr.type.key === 'VIRTUAL') { isVirtual = true; } - // Method 2: Check constructor name - else if (attr.type.constructor && attr.type.constructor.name === 'VIRTUAL') { + // Method 2: Direct comparison with DataTypes.VIRTUAL + else if (attr.type === DataTypes.VIRTUAL) { isVirtual = true; } - // Method 3: Check if type key is VIRTUAL - else if (attr.type.key === 'VIRTUAL') { - isVirtual = true; - } - // Method 4: Check toString representation + // Method 3: Check toString representation else if (typeof attr.type.toString === 'function') { const typeStr = attr.type.toString(); - if (typeStr.includes('VIRTUAL') || typeStr === 'VIRTUAL') { + if (typeStr === 'VIRTUAL' || typeStr.includes('VIRTUAL')) { isVirtual = true; } } - // Method 5: Check if it's an instance of VIRTUAL type - else if (attr.type instanceof DataTypes.VIRTUAL || - (attr.type.constructor && attr.type.constructor === DataTypes.VIRTUAL.constructor)) { + // Method 4: Check constructor name + else if (attr.type.constructor && attr.type.constructor.name === 'VIRTUAL') { isVirtual = true; } } - // Also check if field has a getter but no setter (common pattern for VIRTUAL fields) + // Also check if field has a getter but no setter and no field mapping (common pattern for VIRTUAL fields) + // But only if it doesn't have a 'field' property, which means it's not mapped to a database column if (!isVirtual && attr.get && !attr.set && !attr.field) { // This might be a VIRTUAL field, but be careful not to remove real fields // Only remove if we're certain it's VIRTUAL @@ -467,6 +463,16 @@ const syncModelsAlways = async (models) => { } } + // Special handling for Notification model: ensure characterName VIRTUAL field is removed + // This is a workaround for Sequelize bug where it confuses characterName (VIRTUAL) with character_name (STRING) + if (model.name === 'Notification' && model.rawAttributes.characterName) { + if (!virtualFields.characterName) { + virtualFields.characterName = model.rawAttributes.characterName; + delete model.rawAttributes.characterName; + console.log(` ⚠️ Explicitly removed VIRTUAL field: characterName from Notification model`); + } + } + try { await model.sync({ alter: true, force: false }); } finally {