fix(migrate): robustecer parser SQL y no registrar migración si hubo errores

- Eliminar comentarios de bloque /* */ antes de parsear
- Limpiar líneas vacías y comentarios -- sentencia por sentencia
- Agregar 'Duplicate key name' y 'Multiple primary key defined' a errores ignorables
- Solo registrar en tabla migrations si no hubo errores reales
- Si una sentencia falla, continuar con las demás pero marcar had_error=true
This commit is contained in:
Lizandro Guarnizo
2026-03-12 09:27:46 -05:00
parent 28307f44d1
commit 7000464d36
+57 -24
View File
@@ -78,42 +78,75 @@ try {
try { try {
$sql = file_get_contents($file); $sql = file_get_contents($file);
// Dividir en sentencias individuales // Eliminar comentarios de bloque /* ... */
$statements = array_filter(array_map('trim', explode(';', $sql))); $sql = preg_replace('/\/\*.*?\*\//s', '', $sql);
$stmt_count = 0; // Dividir en sentencias por ; y limpiar
foreach ($statements as $stmt) { $rawStatements = explode(';', $sql);
// Saltar comentarios y líneas vacías $statements = [];
if (empty($stmt) || preg_match('/^--/', $stmt)) { foreach ($rawStatements as $stmt) {
continue; // Eliminar líneas de comentario -- y líneas vacías
$lines = explode("\n", $stmt);
$cleaned = [];
foreach ($lines as $line) {
$trimmed = trim($line);
if ($trimmed !== '' && strpos($trimmed, '--') !== 0) {
$cleaned[] = $line;
}
} }
$stmt = trim(implode("\n", $cleaned));
if ($stmt !== '') {
$statements[] = $stmt;
}
}
$stmt_count = 0;
$had_error = false;
foreach ($statements as $stmt) {
try { try {
$db->execute($stmt); $db->execute($stmt);
$stmt_count++; $stmt_count++;
} catch (Exception $e) { } catch (Exception $e) {
// Ignorar errores de "ya existe" (IF NOT EXISTS) $msg = $e->getMessage();
if (strpos($e->getMessage(), 'Duplicate column') !== false || // Ignorar errores de "ya existe" — son idempotentes
strpos($e->getMessage(), 'already exists') !== false) { $ignorable = [
// Columna ya existe, no es un error real 'Duplicate column',
'already exists',
'Duplicate key name',
'Multiple primary key defined',
];
$ignore = false;
foreach ($ignorable as $pattern) {
if (strpos($msg, $pattern) !== false) {
$ignore = true;
break;
}
}
if ($ignore) {
echo " ⚠ Ya existe (ignorado): " . substr($msg, 0, 80) . "\n";
continue; continue;
} }
throw $e; echo " ✗ Error en sentencia: $msg\n";
$had_error = true;
// Continuar con las demás sentencias del archivo
} }
} }
// Registrar migración como ejecutada if (!$had_error) {
$db->execute( // Registrar migración como ejecutada solo si no hubo errores reales
"INSERT INTO migrations (filename) VALUES (?)", $db->execute(
[$filename] "INSERT INTO migrations (filename) VALUES (?)",
); [$filename]
);
echo " ✓ Ejecutadas $stmt_count sentencias SQL\n"; echo " ✓ Ejecutadas $stmt_count sentencias SQL — registrada\n";
} else {
echo " ⚠ Migración con errores — NO registrada (se reintentará en el próximo deploy)\n";
}
$executed_count++; $executed_count++;
} catch (Exception $e) { } catch (Exception $e) {
echo " ✗ Error en $filename: " . $e->getMessage() . "\n"; echo " ✗ Error fatal en $filename: " . $e->getMessage() . "\n";
// Continuar con la siguiente migración // Continuar con la siguiente migración
} }
} }