diff --git a/inventory-server/scripts/reset-metrics.js b/inventory-server/scripts/reset-metrics.js index f05fd64..10499d0 100644 --- a/inventory-server/scripts/reset-metrics.js +++ b/inventory-server/scripts/reset-metrics.js @@ -21,7 +21,7 @@ function outputProgress(data) { console.log(JSON.stringify(data)); } -// Explicitly define all metrics-related tables +// Explicitly define all metrics-related tables in dependency order const METRICS_TABLES = [ 'brand_metrics', 'brand_time_metrics', @@ -40,23 +40,6 @@ const METRICS_TABLES = [ 'vendor_details' ]; -// Config tables that must exist -const CONFIG_TABLES = [ - 'stock_thresholds', - 'lead_time_thresholds', - 'sales_velocity_config', - 'abc_classification_config', - 'safety_stock_config', - 'turnover_config' -]; - -// Core tables that must exist -const REQUIRED_CORE_TABLES = [ - 'products', - 'orders', - 'purchase_orders' -]; - // Split SQL into individual statements function splitSQLStatements(sql) { sql = sql.replace(/\r\n/g, '\n'); @@ -118,55 +101,44 @@ async function resetMetrics() { connection = await mysql.createConnection(dbConfig); await connection.beginTransaction(); - // Verify required core tables exist - outputProgress({ - operation: 'Verifying core tables', - message: 'Checking required tables exist...' - }); - - const [tables] = await connection.query(` + // First verify current state + const [initialTables] = await connection.query(` SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name IN (?) - `, [REQUIRED_CORE_TABLES]); + `, [METRICS_TABLES]); - const existingCoreTables = tables.map(t => t.table_name); - const missingCoreTables = REQUIRED_CORE_TABLES.filter(t => !existingCoreTables.includes(t)); - - if (missingCoreTables.length > 0) { - throw new Error(`Required core tables missing: ${missingCoreTables.join(', ')}`); - } - - // Verify config tables exist outputProgress({ - operation: 'Verifying config tables', - message: 'Checking configuration tables exist...' + operation: 'Initial state', + message: `Found ${initialTables.length} existing metrics tables: ${initialTables.map(t => t.table_name).join(', ')}` }); - const [configTables] = await connection.query(` - SELECT table_name - FROM information_schema.tables - WHERE table_schema = DATABASE() - AND table_name IN (?) - `, [CONFIG_TABLES]); + // Disable foreign key checks at the start + await connection.query('SET FOREIGN_KEY_CHECKS = 0'); - const existingConfigTables = configTables.map(t => t.table_name); - const missingConfigTables = CONFIG_TABLES.filter(t => !existingConfigTables.includes(t)); - - if (missingConfigTables.length > 0) { - throw new Error(`Required config tables missing: ${missingConfigTables.join(', ')}`); - } - - // Drop all metrics tables + // Drop all metrics tables in reverse order to handle dependencies outputProgress({ operation: 'Dropping metrics tables', message: 'Removing existing metrics tables...' }); - for (const table of METRICS_TABLES) { + for (const table of [...METRICS_TABLES].reverse()) { try { await connection.query(`DROP TABLE IF EXISTS ${table}`); + + // Verify the table was actually dropped + const [checkDrop] = await connection.query(` + SELECT COUNT(*) as count + FROM information_schema.tables + WHERE table_schema = DATABASE() + AND table_name = ? + `, [table]); + + if (checkDrop[0].count > 0) { + throw new Error(`Failed to drop table ${table} - table still exists`); + } + outputProgress({ operation: 'Table dropped', message: `Successfully dropped table: ${table}` @@ -181,6 +153,18 @@ async function resetMetrics() { } } + // Verify all tables were dropped + const [afterDrop] = await connection.query(` + SELECT table_name + FROM information_schema.tables + WHERE table_schema = DATABASE() + AND table_name IN (?) + `, [METRICS_TABLES]); + + if (afterDrop.length > 0) { + throw new Error(`Failed to drop all tables. Remaining tables: ${afterDrop.map(t => t.table_name).join(', ')}`); + } + // Read metrics schema outputProgress({ operation: 'Reading schema', @@ -212,9 +196,29 @@ async function resetMetrics() { outputProgress({ status: 'warning', operation: 'SQL Warning', - message: warnings + message: { + statement: i + 1, + warnings: warnings + } }); } + + // If this is a CREATE TABLE statement, verify the table was created + if (stmt.trim().toLowerCase().startsWith('create table')) { + const tableName = stmt.match(/create\s+table\s+(?:if\s+not\s+exists\s+)?`?(\w+)`?/i)?.[1]; + if (tableName) { + const [checkCreate] = await connection.query(` + SELECT COUNT(*) as count + FROM information_schema.tables + WHERE table_schema = DATABASE() + AND table_name = ? + `, [tableName]); + + if (checkCreate[0].count === 0) { + throw new Error(`Failed to create table ${tableName} - table does not exist after CREATE statement`); + } + } + } outputProgress({ operation: 'SQL Progress', @@ -241,6 +245,9 @@ async function resetMetrics() { } } + // Re-enable foreign key checks after all tables are created + await connection.query('SET FOREIGN_KEY_CHECKS = 1'); + // Verify metrics tables were created outputProgress({ operation: 'Verifying metrics tables', @@ -248,12 +255,19 @@ async function resetMetrics() { }); const [metricsTablesResult] = await connection.query(` - SELECT table_name + SELECT table_name, table_rows, create_time FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name IN (?) `, [METRICS_TABLES]); + outputProgress({ + operation: 'Tables found', + message: `Found ${metricsTablesResult.length} tables: ${metricsTablesResult.map(t => + `${t.table_name} (created: ${t.create_time})` + ).join(', ')}` + }); + const existingMetricsTables = metricsTablesResult.map(t => t.table_name); const missingMetricsTables = METRICS_TABLES.filter(t => !existingMetricsTables.includes(t)); @@ -278,10 +292,14 @@ async function resetMetrics() { if (connection) { await connection.rollback(); + // Make sure to re-enable foreign key checks even if there's an error + await connection.query('SET FOREIGN_KEY_CHECKS = 1').catch(() => {}); } throw error; } finally { if (connection) { + // One final attempt to ensure foreign key checks are enabled + await connection.query('SET FOREIGN_KEY_CHECKS = 1').catch(() => {}); await connection.end(); } }