diff --git a/backend/package.json b/backend/package.json index 3b8a2ea..a767177 100644 --- a/backend/package.json +++ b/backend/package.json @@ -6,7 +6,8 @@ "scripts": { "postinstall": "cd ../frontend && npm install && npm run build", "dev": "nodemon server.js", - "cleanup:usertoken": "node ./scripts/cleanupUserTokenKeys.js" + "cleanup:usertoken": "node ./scripts/cleanupUserTokenKeys.js", + "cleanup:indexes": "node ./scripts/cleanupAllIndexes.js" }, "keywords": [], "author": "", diff --git a/backend/scripts/cleanupAllIndexes.js b/backend/scripts/cleanupAllIndexes.js new file mode 100644 index 0000000..2e556f7 --- /dev/null +++ b/backend/scripts/cleanupAllIndexes.js @@ -0,0 +1,100 @@ +import mysql from 'mysql2/promise'; +import dotenv from 'dotenv'; + +dotenv.config(); + +const dbConfig = { + host: process.env.DB_HOST || 'localhost', + user: process.env.DB_USER || 'root', + password: process.env.DB_PASSWORD || '', + database: process.env.DB_NAME || 'trainingdiary', +}; + +async function getTables(connection) { + const [rows] = await connection.execute( + `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_TYPE='BASE TABLE'`, + [dbConfig.database] + ); + return rows.map(r => r.TABLE_NAME); +} + +async function getIndexSummary(connection, table) { + const [rows] = await connection.execute(`SHOW INDEX FROM \`${table}\``); + const byName = rows.reduce((acc, r) => { + const key = r.Key_name; + if (!acc[key]) acc[key] = { nonUnique: r.Non_unique === 1, seqMap: {}, columns: [] }; + acc[key].seqMap[r.Seq_in_index] = r.Column_name; + return acc; + }, {}); + // normalize columns order by seq + for (const name of Object.keys(byName)) { + const cols = Object.keys(byName[name].seqMap) + .sort((a, b) => Number(a) - Number(b)) + .map(k => byName[name].seqMap[k]); + byName[name].columns = cols; + } + return byName; +} + +async function cleanupDuplicates(connection, table) { + const before = await getIndexSummary(connection, table); + const keepSignatureToName = new Map(); + const dropNames = []; + + for (const [name, info] of Object.entries(before)) { + if (name === 'PRIMARY') continue; // niemals Primary droppen + const uniqueFlag = info.nonUnique ? 'N' : 'U'; + const sig = `${uniqueFlag}|${info.columns.join(',')}`; + if (!keepSignatureToName.has(sig)) { + keepSignatureToName.set(sig, name); + } else { + // doppelter Index mit gleicher Spaltenliste und gleicher Einzigartigkeit + dropNames.push(name); + } + } + + for (const idxName of dropNames) { + try { + await connection.execute(`DROP INDEX \`${idxName}\` ON \`${table}\``); + console.log(`[drop] ${table}: ${idxName}`); + } catch (e) { + console.warn(`[warn] ${table}: konnte Index ${idxName} nicht löschen: ${e.code || e.message}`); + } + } + + const after = await getIndexSummary(connection, table); + return { beforeCount: Object.keys(before).length, afterCount: Object.keys(after).length, dropped: dropNames.length }; +} + +async function main() { + let connection; + try { + console.log('Connecting to DB:', dbConfig); + connection = await mysql.createConnection(dbConfig); + + const tables = await getTables(connection); + console.log(`Found ${tables.length} tables`); + + let totalBefore = 0; + let totalAfter = 0; + let totalDropped = 0; + + for (const table of tables) { + const { beforeCount, afterCount, dropped } = await cleanupDuplicates(connection, table); + totalBefore += beforeCount; + totalAfter += afterCount; + totalDropped += dropped; + } + + console.log('Summary:', { totalBefore, totalAfter, totalDropped }); + } catch (e) { + console.error('Cleanup failed:', e); + process.exitCode = 1; + } finally { + if (connection) await connection.end(); + } +} + +main(); + + diff --git a/backend/services/diaryDateActivityService.js b/backend/services/diaryDateActivityService.js index 2b1d70d..f546a0c 100644 --- a/backend/services/diaryDateActivityService.js +++ b/backend/services/diaryDateActivityService.js @@ -22,7 +22,7 @@ class DiaryDateActivityService { } restData.predefinedActivityId = predefinedActivity.id; const maxOrderId = await DiaryDateActivity.max('orderId', { - where: { diaryDateId: data.diaryDateId } + where: { diaryDateId: data.diaryDateId } }); const newOrderId = maxOrderId !== null ? maxOrderId + 1 : 1; restData.orderId = newOrderId;