Improve metrics reset script with robust table management and error handling
This commit is contained in:
@@ -21,7 +21,7 @@ function outputProgress(data) {
|
|||||||
console.log(JSON.stringify(data));
|
console.log(JSON.stringify(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Explicitly define all metrics-related tables
|
// Explicitly define all metrics-related tables in dependency order
|
||||||
const METRICS_TABLES = [
|
const METRICS_TABLES = [
|
||||||
'brand_metrics',
|
'brand_metrics',
|
||||||
'brand_time_metrics',
|
'brand_time_metrics',
|
||||||
@@ -40,23 +40,6 @@ const METRICS_TABLES = [
|
|||||||
'vendor_details'
|
'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
|
// Split SQL into individual statements
|
||||||
function splitSQLStatements(sql) {
|
function splitSQLStatements(sql) {
|
||||||
sql = sql.replace(/\r\n/g, '\n');
|
sql = sql.replace(/\r\n/g, '\n');
|
||||||
@@ -118,55 +101,44 @@ async function resetMetrics() {
|
|||||||
connection = await mysql.createConnection(dbConfig);
|
connection = await mysql.createConnection(dbConfig);
|
||||||
await connection.beginTransaction();
|
await connection.beginTransaction();
|
||||||
|
|
||||||
// Verify required core tables exist
|
// First verify current state
|
||||||
outputProgress({
|
const [initialTables] = await connection.query(`
|
||||||
operation: 'Verifying core tables',
|
|
||||||
message: 'Checking required tables exist...'
|
|
||||||
});
|
|
||||||
|
|
||||||
const [tables] = await connection.query(`
|
|
||||||
SELECT table_name
|
SELECT table_name
|
||||||
FROM information_schema.tables
|
FROM information_schema.tables
|
||||||
WHERE table_schema = DATABASE()
|
WHERE table_schema = DATABASE()
|
||||||
AND table_name IN (?)
|
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({
|
outputProgress({
|
||||||
operation: 'Verifying config tables',
|
operation: 'Initial state',
|
||||||
message: 'Checking configuration tables exist...'
|
message: `Found ${initialTables.length} existing metrics tables: ${initialTables.map(t => t.table_name).join(', ')}`
|
||||||
});
|
});
|
||||||
|
|
||||||
const [configTables] = await connection.query(`
|
// Disable foreign key checks at the start
|
||||||
SELECT table_name
|
await connection.query('SET FOREIGN_KEY_CHECKS = 0');
|
||||||
FROM information_schema.tables
|
|
||||||
WHERE table_schema = DATABASE()
|
|
||||||
AND table_name IN (?)
|
|
||||||
`, [CONFIG_TABLES]);
|
|
||||||
|
|
||||||
const existingConfigTables = configTables.map(t => t.table_name);
|
// Drop all metrics tables in reverse order to handle dependencies
|
||||||
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
|
|
||||||
outputProgress({
|
outputProgress({
|
||||||
operation: 'Dropping metrics tables',
|
operation: 'Dropping metrics tables',
|
||||||
message: 'Removing existing metrics tables...'
|
message: 'Removing existing metrics tables...'
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const table of METRICS_TABLES) {
|
for (const table of [...METRICS_TABLES].reverse()) {
|
||||||
try {
|
try {
|
||||||
await connection.query(`DROP TABLE IF EXISTS ${table}`);
|
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({
|
outputProgress({
|
||||||
operation: 'Table dropped',
|
operation: 'Table dropped',
|
||||||
message: `Successfully dropped table: ${table}`
|
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
|
// Read metrics schema
|
||||||
outputProgress({
|
outputProgress({
|
||||||
operation: 'Reading schema',
|
operation: 'Reading schema',
|
||||||
@@ -212,9 +196,29 @@ async function resetMetrics() {
|
|||||||
outputProgress({
|
outputProgress({
|
||||||
status: 'warning',
|
status: 'warning',
|
||||||
operation: 'SQL 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({
|
outputProgress({
|
||||||
operation: 'SQL Progress',
|
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
|
// Verify metrics tables were created
|
||||||
outputProgress({
|
outputProgress({
|
||||||
operation: 'Verifying metrics tables',
|
operation: 'Verifying metrics tables',
|
||||||
@@ -248,12 +255,19 @@ async function resetMetrics() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [metricsTablesResult] = await connection.query(`
|
const [metricsTablesResult] = await connection.query(`
|
||||||
SELECT table_name
|
SELECT table_name, table_rows, create_time
|
||||||
FROM information_schema.tables
|
FROM information_schema.tables
|
||||||
WHERE table_schema = DATABASE()
|
WHERE table_schema = DATABASE()
|
||||||
AND table_name IN (?)
|
AND table_name IN (?)
|
||||||
`, [METRICS_TABLES]);
|
`, [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 existingMetricsTables = metricsTablesResult.map(t => t.table_name);
|
||||||
const missingMetricsTables = METRICS_TABLES.filter(t => !existingMetricsTables.includes(t));
|
const missingMetricsTables = METRICS_TABLES.filter(t => !existingMetricsTables.includes(t));
|
||||||
|
|
||||||
@@ -278,10 +292,14 @@ async function resetMetrics() {
|
|||||||
|
|
||||||
if (connection) {
|
if (connection) {
|
||||||
await connection.rollback();
|
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;
|
throw error;
|
||||||
} finally {
|
} finally {
|
||||||
if (connection) {
|
if (connection) {
|
||||||
|
// One final attempt to ensure foreign key checks are enabled
|
||||||
|
await connection.query('SET FOREIGN_KEY_CHECKS = 1').catch(() => {});
|
||||||
await connection.end();
|
await connection.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user