You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
senzapaura_es/scripts/db/probar-migracion.mjs

75 lines
2.6 KiB

/**
* Ejecuta la migración en una transacción y la deshace.
*
* `drizzle-kit migrate` se queda colgado sin decir por qué, así que hay que
* preguntarle directamente a Postgres.
*
* El progreso se escribe a disco de forma SÍNCRONA. La salida normal de Node
* se acumula en un buffer cuando va a un pipe o a un archivo, y si el proceso
* se mata por tiempo ese buffer se pierde entero: es justo lo que hacía que
* pareciera que no llegaba a arrancar.
*/
import fs from 'node:fs';
import pg from 'pg';
const ARCHIVO = 'drizzle/0002_catalogo_en_la_base.sql';
const DIARIO = '.diario-migracion.txt';
const APLICAR = process.argv.includes('--aplicar');
fs.writeFileSync(DIARIO, '');
const apuntar = (linea) => fs.appendFileSync(DIARIO, linea + '\n');
const sql = fs.readFileSync(ARCHIVO, 'utf8');
const sentencias = sql
.split('--> statement-breakpoint')
.map((s) => s.trim())
// Sin expresión regular. `(--[^\n]*\n?)+` tarda catorce segundos en un
// comentario de quinientos caracteres: cuando no encaja, puede repartir el
// mismo texto de exponencialmente muchas formas antes de rendirse. Línea a
// línea es lineal, y además se lee.
.filter((s) => s && s.split('\n').some((l) => l.trim() && !l.trim().startsWith('--')));
apuntar(`${sentencias.length} sentencias`);
const cliente = new pg.Client({
connectionString: process.env.DATABASE_URL,
// Que no se quede esperando eternamente si el servidor no contesta.
connectionTimeoutMillis: 10_000,
query_timeout: 30_000
});
apuntar('conectando...');
await cliente.connect();
apuntar('conectado');
await cliente.query('BEGIN');
// Que falle rápido en vez de colgarse esperando un bloqueo que no llega.
await cliente.query("SET LOCAL lock_timeout = '5s'");
await cliente.query("SET LOCAL statement_timeout = '30s'");
apuntar('transacción abierta');
let hechas = 0;
let rota = null;
for (const [i, sentencia] of sentencias.entries()) {
const resumen = sentencia.split('\n').find((l) => l.trim() && !l.trim().startsWith('--')) ?? '';
apuntar(`[${i + 1}/${sentencias.length}] ${resumen.trim().slice(0, 80)}`);
try {
await cliente.query(sentencia);
hechas++;
} catch (fallo) {
rota = { i, sentencia, fallo };
apuntar(`\n FALLA: ${fallo.message}`);
if (fallo.hint) apuntar(` pista: ${fallo.hint}`);
if (fallo.position) apuntar(` posición: ${fallo.position}`);
apuntar('\n' + sentencia.slice(0, 600));
break;
}
}
const completa = !rota && hechas === sentencias.length;
await cliente.query(APLICAR && completa ? 'COMMIT' : 'ROLLBACK');
apuntar(completa ? `\nLas ${hechas} sentencias pasan.` : `\nParó en la ${hechas + 1}.`);
apuntar(APLICAR && completa ? 'APLICADA.' : '(deshecha)');
await cliente.end();

Powered by TurnKey Linux.