434 lines
18 KiB
JavaScript
434 lines
18 KiB
JavaScript
// syncDatabase.js
|
|
|
|
import { initializeDatabase, syncModelsWithUpdates, syncModelsAlways, sequelize } from './sequelize.js';
|
|
import initializeTypes from './initializeTypes.js';
|
|
import initializeSettings from './initializeSettings.js';
|
|
import initializeUserRights from './initializeUserRights.js';
|
|
import initializeImageTypes from './initializeImageTypes.js';
|
|
import initializeFalukant from './initializeFalukant.js';
|
|
import setupAssociations from '../models/associations.js';
|
|
import models from '../models/index.js';
|
|
import { createTriggers } from '../models/trigger.js';
|
|
import initializeForum from './initializeForum.js';
|
|
import initializeChat from './initializeChat.js';
|
|
import initializeMatch3Data from './initializeMatch3.js';
|
|
import updateExistingMatch3Levels from './updateExistingMatch3Levels.js';
|
|
import initializeTaxi from './initializeTaxi.js';
|
|
|
|
// Normale Synchronisation (nur bei STAGE=dev Schema-Updates)
|
|
const syncDatabase = async () => {
|
|
try {
|
|
// Zeige den aktuellen Stage an
|
|
const currentStage = process.env.STAGE || 'nicht gesetzt';
|
|
console.log(`🚀 Starte Datenbank-Synchronisation (Stage: ${currentStage})`);
|
|
|
|
if (currentStage !== 'dev') {
|
|
console.log('⚠️ WARNUNG: Automatische Schema-Updates sind deaktiviert');
|
|
console.log('💡 Setze STAGE=dev in der .env Datei für automatische Schema-Updates');
|
|
console.log('🔒 Produktionsmodus: Nur normale Synchronisation ohne Schema-Änderungen');
|
|
} else {
|
|
console.log('✅ Entwicklungsmodus aktiv - Schema-Updates sind aktiviert');
|
|
}
|
|
|
|
console.log("Initializing database schemas...");
|
|
await initializeDatabase();
|
|
|
|
// Vorab: Stelle kritische Spalten sicher, damit Index-Erstellung nicht fehlschlägt
|
|
console.log("Pre-ensure Taxi columns (traffic_light) ...");
|
|
try {
|
|
await sequelize.query(`
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM information_schema.columns
|
|
WHERE table_schema = 'taxi' AND table_name = 'taxi_map_tile' AND column_name = 'traffic_light'
|
|
) THEN
|
|
ALTER TABLE taxi.taxi_map_tile
|
|
ADD COLUMN traffic_light BOOLEAN NOT NULL DEFAULT false;
|
|
END IF;
|
|
END
|
|
$$;
|
|
`);
|
|
console.log("✅ traffic_light-Spalte ist vorhanden");
|
|
} catch (e) {
|
|
console.warn('⚠️ Konnte traffic_light-Spalte nicht vorab sicherstellen:', e?.message || e);
|
|
}
|
|
|
|
// Cleanup: Entferne verwaiste Einträge vor Schema-Updates (nur wenn Schema-Updates aktiviert)
|
|
if (currentStage === 'dev') {
|
|
console.log("Cleaning up orphaned entries...");
|
|
try {
|
|
// Cleanup user_param_visibility
|
|
const result1 = await sequelize.query(`
|
|
DELETE FROM community.user_param_visibility
|
|
WHERE param_id NOT IN (
|
|
SELECT id FROM community.user_param
|
|
);
|
|
`);
|
|
const deletedCount1 = result1[1] || 0;
|
|
if (deletedCount1 > 0) {
|
|
console.log(`✅ ${deletedCount1} verwaiste user_param_visibility Einträge entfernt`);
|
|
}
|
|
|
|
// Cleanup stock mit ungültigen branch_id (0 oder nicht existierend)
|
|
const result2 = await sequelize.query(`
|
|
DELETE FROM falukant_data.stock
|
|
WHERE branch_id = 0 OR branch_id NOT IN (
|
|
SELECT id FROM falukant_data.branch
|
|
);
|
|
`);
|
|
const deletedCount2 = result2[1] || 0;
|
|
if (deletedCount2 > 0) {
|
|
console.log(`✅ ${deletedCount2} verwaiste stock Einträge entfernt`);
|
|
}
|
|
|
|
// Cleanup knowledge mit ungültigen character_id oder product_id
|
|
const result3 = await sequelize.query(`
|
|
DELETE FROM falukant_data.knowledge
|
|
WHERE character_id NOT IN (
|
|
SELECT id FROM falukant_data.character
|
|
) OR product_id NOT IN (
|
|
SELECT id FROM falukant_type.product
|
|
);
|
|
`);
|
|
const deletedCount3 = result3[1] || 0;
|
|
if (deletedCount3 > 0) {
|
|
console.log(`✅ ${deletedCount3} verwaiste knowledge Einträge entfernt`);
|
|
}
|
|
|
|
// Cleanup notification mit ungültigen user_id
|
|
const result4 = await sequelize.query(`
|
|
DELETE FROM falukant_log.notification
|
|
WHERE user_id NOT IN (
|
|
SELECT id FROM falukant_data.falukant_user
|
|
);
|
|
`);
|
|
const deletedCount4 = result4[1] || 0;
|
|
if (deletedCount4 > 0) {
|
|
console.log(`✅ ${deletedCount4} verwaiste notification Einträge entfernt`);
|
|
}
|
|
|
|
// Cleanup promotional_gift mit ungültigen sender_character_id oder recipient_character_id
|
|
const result5 = await sequelize.query(`
|
|
DELETE FROM falukant_log.promotional_gift
|
|
WHERE sender_character_id NOT IN (
|
|
SELECT id FROM falukant_data.character
|
|
) OR recipient_character_id NOT IN (
|
|
SELECT id FROM falukant_data.character
|
|
);
|
|
`);
|
|
const deletedCount5 = result5[1] || 0;
|
|
if (deletedCount5 > 0) {
|
|
console.log(`✅ ${deletedCount5} verwaiste promotional_gift Einträge entfernt`);
|
|
}
|
|
|
|
// Cleanup user_house mit ungültigen house_type_id oder user_id
|
|
const result6 = await sequelize.query(`
|
|
DELETE FROM falukant_data.user_house
|
|
WHERE house_type_id NOT IN (
|
|
SELECT id FROM falukant_type.house
|
|
) OR user_id NOT IN (
|
|
SELECT id FROM falukant_data.falukant_user
|
|
);
|
|
`);
|
|
const deletedCount6 = result6[1] || 0;
|
|
if (deletedCount6 > 0) {
|
|
console.log(`✅ ${deletedCount6} verwaiste user_house Einträge entfernt`);
|
|
}
|
|
|
|
// Cleanup child_relation mit ungültigen father_character_id, mother_character_id oder child_character_id
|
|
const result7 = await sequelize.query(`
|
|
DELETE FROM falukant_data.child_relation
|
|
WHERE father_character_id NOT IN (
|
|
SELECT id FROM falukant_data.character
|
|
) OR mother_character_id NOT IN (
|
|
SELECT id FROM falukant_data.character
|
|
) OR child_character_id NOT IN (
|
|
SELECT id FROM falukant_data.character
|
|
);
|
|
`);
|
|
const deletedCount7 = result7[1] || 0;
|
|
if (deletedCount7 > 0) {
|
|
console.log(`✅ ${deletedCount7} verwaiste child_relation Einträge entfernt`);
|
|
}
|
|
|
|
if (deletedCount1 === 0 && deletedCount2 === 0 && deletedCount3 === 0 && deletedCount4 === 0 && deletedCount5 === 0 && deletedCount6 === 0 && deletedCount7 === 0) {
|
|
console.log("✅ Keine verwaisten Einträge gefunden");
|
|
}
|
|
} catch (e) {
|
|
console.warn('⚠️ Konnte verwaiste Einträge nicht bereinigen:', e?.message || e);
|
|
}
|
|
}
|
|
|
|
console.log("Setting up associations...");
|
|
setupAssociations();
|
|
|
|
console.log("Synchronizing models...");
|
|
await syncModelsWithUpdates(models);
|
|
|
|
console.log("Initializing settings...");
|
|
await initializeSettings();
|
|
|
|
console.log("Initializing types...");
|
|
await initializeTypes();
|
|
|
|
console.log("Initializing user rights...");
|
|
await initializeUserRights();
|
|
|
|
console.log("Initializing image types...");
|
|
await initializeImageTypes();
|
|
|
|
console.log("Initializing forums...");
|
|
await initializeForum();
|
|
|
|
console.log("Initializing Falukant...");
|
|
await initializeFalukant();
|
|
|
|
console.log("Creating triggers...");
|
|
await createTriggers();
|
|
|
|
console.log("Initializing chat...");
|
|
await initializeChat();
|
|
|
|
// Match3-Initialisierung NACH der Model-Synchronisation
|
|
console.log("Initializing Match3...");
|
|
await initializeMatch3Data();
|
|
|
|
// Match3-Levels aktualisieren NACH der Initialisierung
|
|
console.log("Updating existing Match3 levels...");
|
|
await updateExistingMatch3Levels();
|
|
|
|
console.log("Initializing Taxi...");
|
|
await initializeTaxi();
|
|
|
|
console.log('Database synchronization complete.');
|
|
} catch (error) {
|
|
console.error('Unable to synchronize the database:', error);
|
|
}
|
|
};
|
|
|
|
// Deployment-Synchronisation (immer Schema-Updates)
|
|
const syncDatabaseForDeployment = async () => {
|
|
try {
|
|
// Zeige den aktuellen Stage an
|
|
const currentStage = process.env.STAGE || 'nicht gesetzt';
|
|
console.log(`🚀 Starte Datenbank-Synchronisation für Deployment (Stage: ${currentStage})`);
|
|
console.log('✅ Deployment-Modus: Schema-Updates sind immer aktiviert');
|
|
|
|
console.log("Initializing database schemas...");
|
|
await initializeDatabase();
|
|
|
|
// Vorab: Stelle kritische Spalten sicher, damit Index-Erstellung nicht fehlschlägt
|
|
console.log("Pre-ensure Taxi columns (traffic_light) ...");
|
|
try {
|
|
await sequelize.query(`
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM information_schema.columns
|
|
WHERE table_schema = 'taxi' AND table_name = 'taxi_map_tile' AND column_name = 'traffic_light'
|
|
) THEN
|
|
ALTER TABLE taxi.taxi_map_tile
|
|
ADD COLUMN traffic_light BOOLEAN NOT NULL DEFAULT false;
|
|
END IF;
|
|
END
|
|
$$;
|
|
`);
|
|
console.log("✅ traffic_light-Spalte ist vorhanden");
|
|
} catch (e) {
|
|
console.warn('⚠️ Konnte traffic_light-Spalte nicht vorab sicherstellen:', e?.message || e);
|
|
}
|
|
|
|
// Migration: Transport product_id und size nullable machen
|
|
console.log("Making transport product_id and size nullable...");
|
|
try {
|
|
await sequelize.query(`
|
|
DO $$
|
|
BEGIN
|
|
-- Prüfe ob product_id NOT NULL Constraint existiert
|
|
IF EXISTS (
|
|
SELECT 1 FROM information_schema.columns
|
|
WHERE table_schema = 'falukant_data'
|
|
AND table_name = 'transport'
|
|
AND column_name = 'product_id'
|
|
AND is_nullable = 'NO'
|
|
) THEN
|
|
ALTER TABLE falukant_data.transport
|
|
ALTER COLUMN product_id DROP NOT NULL;
|
|
RAISE NOTICE 'product_id NOT NULL Constraint entfernt';
|
|
END IF;
|
|
|
|
-- Prüfe ob size NOT NULL Constraint existiert
|
|
IF EXISTS (
|
|
SELECT 1 FROM information_schema.columns
|
|
WHERE table_schema = 'falukant_data'
|
|
AND table_name = 'transport'
|
|
AND column_name = 'size'
|
|
AND is_nullable = 'NO'
|
|
) THEN
|
|
ALTER TABLE falukant_data.transport
|
|
ALTER COLUMN size DROP NOT NULL;
|
|
RAISE NOTICE 'size NOT NULL Constraint entfernt';
|
|
END IF;
|
|
END
|
|
$$;
|
|
`);
|
|
console.log("✅ Transport product_id und size sind jetzt nullable");
|
|
} catch (e) {
|
|
console.warn('⚠️ Konnte Transport-Spalten nicht nullable machen:', e?.message || e);
|
|
}
|
|
|
|
// Cleanup: Entferne verwaiste Einträge vor Schema-Updates
|
|
console.log("Cleaning up orphaned entries...");
|
|
try {
|
|
// Cleanup user_param_visibility
|
|
const result1 = await sequelize.query(`
|
|
DELETE FROM community.user_param_visibility
|
|
WHERE param_id NOT IN (
|
|
SELECT id FROM community.user_param
|
|
);
|
|
`);
|
|
const deletedCount1 = result1[1] || 0;
|
|
if (deletedCount1 > 0) {
|
|
console.log(`✅ ${deletedCount1} verwaiste user_param_visibility Einträge entfernt`);
|
|
}
|
|
|
|
// Cleanup stock mit ungültigen branch_id (0 oder nicht existierend)
|
|
const result2 = await sequelize.query(`
|
|
DELETE FROM falukant_data.stock
|
|
WHERE branch_id = 0 OR branch_id NOT IN (
|
|
SELECT id FROM falukant_data.branch
|
|
);
|
|
`);
|
|
const deletedCount2 = result2[1] || 0;
|
|
if (deletedCount2 > 0) {
|
|
console.log(`✅ ${deletedCount2} verwaiste stock Einträge entfernt`);
|
|
}
|
|
|
|
// Cleanup knowledge mit ungültigen character_id oder product_id
|
|
const result3 = await sequelize.query(`
|
|
DELETE FROM falukant_data.knowledge
|
|
WHERE character_id NOT IN (
|
|
SELECT id FROM falukant_data.character
|
|
) OR product_id NOT IN (
|
|
SELECT id FROM falukant_type.product
|
|
);
|
|
`);
|
|
const deletedCount3 = result3[1] || 0;
|
|
if (deletedCount3 > 0) {
|
|
console.log(`✅ ${deletedCount3} verwaiste knowledge Einträge entfernt`);
|
|
}
|
|
|
|
// Cleanup notification mit ungültigen user_id
|
|
const result4 = await sequelize.query(`
|
|
DELETE FROM falukant_log.notification
|
|
WHERE user_id NOT IN (
|
|
SELECT id FROM falukant_data.falukant_user
|
|
);
|
|
`);
|
|
const deletedCount4 = result4[1] || 0;
|
|
if (deletedCount4 > 0) {
|
|
console.log(`✅ ${deletedCount4} verwaiste notification Einträge entfernt`);
|
|
}
|
|
|
|
// Cleanup promotional_gift mit ungültigen sender_character_id oder recipient_character_id
|
|
const result5 = await sequelize.query(`
|
|
DELETE FROM falukant_log.promotional_gift
|
|
WHERE sender_character_id NOT IN (
|
|
SELECT id FROM falukant_data.character
|
|
) OR recipient_character_id NOT IN (
|
|
SELECT id FROM falukant_data.character
|
|
);
|
|
`);
|
|
const deletedCount5 = result5[1] || 0;
|
|
if (deletedCount5 > 0) {
|
|
console.log(`✅ ${deletedCount5} verwaiste promotional_gift Einträge entfernt`);
|
|
}
|
|
|
|
// Cleanup user_house mit ungültigen house_type_id oder user_id
|
|
const result6 = await sequelize.query(`
|
|
DELETE FROM falukant_data.user_house
|
|
WHERE house_type_id NOT IN (
|
|
SELECT id FROM falukant_type.house
|
|
) OR user_id NOT IN (
|
|
SELECT id FROM falukant_data.falukant_user
|
|
);
|
|
`);
|
|
const deletedCount6 = result6[1] || 0;
|
|
if (deletedCount6 > 0) {
|
|
console.log(`✅ ${deletedCount6} verwaiste user_house Einträge entfernt`);
|
|
}
|
|
|
|
// Cleanup child_relation mit ungültigen father_character_id, mother_character_id oder child_character_id
|
|
const result7 = await sequelize.query(`
|
|
DELETE FROM falukant_data.child_relation
|
|
WHERE father_character_id NOT IN (
|
|
SELECT id FROM falukant_data.character
|
|
) OR mother_character_id NOT IN (
|
|
SELECT id FROM falukant_data.character
|
|
) OR child_character_id NOT IN (
|
|
SELECT id FROM falukant_data.character
|
|
);
|
|
`);
|
|
const deletedCount7 = result7[1] || 0;
|
|
if (deletedCount7 > 0) {
|
|
console.log(`✅ ${deletedCount7} verwaiste child_relation Einträge entfernt`);
|
|
}
|
|
|
|
if (deletedCount1 === 0 && deletedCount2 === 0 && deletedCount3 === 0 && deletedCount4 === 0 && deletedCount5 === 0 && deletedCount6 === 0 && deletedCount7 === 0) {
|
|
console.log("✅ Keine verwaisten Einträge gefunden");
|
|
}
|
|
} catch (e) {
|
|
console.warn('⚠️ Konnte verwaiste Einträge nicht bereinigen:', e?.message || e);
|
|
}
|
|
|
|
console.log("Setting up associations...");
|
|
setupAssociations();
|
|
|
|
console.log("Synchronizing models with schema updates...");
|
|
await syncModelsAlways(models);
|
|
|
|
console.log("Initializing settings...");
|
|
await initializeSettings();
|
|
|
|
console.log("Initializing types...");
|
|
await initializeTypes();
|
|
|
|
console.log("Initializing user rights...");
|
|
await initializeUserRights();
|
|
|
|
console.log("Initializing image types...");
|
|
await initializeImageTypes();
|
|
|
|
console.log("Initializing forums...");
|
|
await initializeForum();
|
|
|
|
console.log("Initializing Falukant...");
|
|
await initializeFalukant();
|
|
|
|
console.log("Creating triggers...");
|
|
await createTriggers();
|
|
|
|
console.log("Initializing chat...");
|
|
await initializeChat();
|
|
|
|
// Match3-Initialisierung NACH der Model-Synchronisation UND nach der Erstellung aller Tabellen
|
|
console.log("Initializing Match3...");
|
|
await initializeMatch3Data();
|
|
|
|
// Match3-Levels aktualisieren NACH der Initialisierung
|
|
console.log("Updating existing Match3 levels...");
|
|
await updateExistingMatch3Levels();
|
|
|
|
console.log("Initializing Taxi...");
|
|
await initializeTaxi();
|
|
|
|
console.log('Database synchronization for deployment complete.');
|
|
} catch (error) {
|
|
console.error('Unable to synchronize the database for deployment:', error);
|
|
throw error; // Fehler weiterwerfen
|
|
}
|
|
};
|
|
|
|
export { syncDatabase, syncDatabaseForDeployment };
|