la version ya no es PK

This commit is contained in:
2026-02-19 12:36:11 +01:00
parent f589132f37
commit 3c4c8b2037

View File

@@ -1,6 +1,5 @@
#!/usr/bin/node
import { constants } from 'buffer';
import { existsSync } from 'fs';
import fs from 'fs/promises';
import path from 'path';
@@ -60,19 +59,25 @@ function getArgs() {
type: "string",
description: "Path del directorio de migrations"
})
.option("versionTable", {
alias: "v",
type: "string",
description: "Nombre de la tabla donde se almacenan las versiones de la BDD, por defecto 'db_versions'",
default: "db_versions"
})
.parse() as {
target: string,
env: string,
migrations: string
migrations: string,
versionTable: "db_versions" | string
}
console.log("args", argv)
/* Antiguo */
//console.log("args", argv)
return {
target: argv.target,
env: argv.env,
migrations: argv.migrations
migrations: argv.migrations,
versionTable: argv.versionTable
};
}
@@ -106,17 +111,89 @@ function compareVersions(va: string, vb: string) {
return 0
}
async function getCurrentVersion(db: Pool) {
async function getCurrentVersion(db: Pool, versionTable: string) {
try {
const lastVersion = await db.query<DBVersion>(`
SELECT * FROM db_versions
SELECT * FROM ${versionTable}
ORDER BY creation_date DESC
LIMIT 1
`)
return lastVersion.rows[0]
} catch (e) {
console.error("Error leyendo la tabla de versiones ", versionTable, e)
}
}
/**
* Si se estuviese lanzando el script sin que exista una tabla con el regstro
* de versiones se crea una nueva con 0.0.0 como version inicial
*/
async function initVersionTable(db: Pool, versionTable: string) {
const client = await db.connect()
const ddlCreateVersionTable = `
CREATE TABLE IF NOT EXISTS ${versionTable} (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
version TEXT PRIMARY KEY, -- version semantica x.x.x,
notes TEXT,
creation_date TIMESTAMP NOT NULL DEFAULT (now() at time zone 'utc'),
stable BOOLEAN DEFAULT FALSE -- Si la version ha sido testada y se puede desplegar
);
`
const insertFistValue = `
INSERT INTO ${versionTable} (
version,
notes
)
VALUES (
'0.0.0',
'Versión base'
);
`
try {
await client.query("BEGIN")
await client.query(ddlCreateVersionTable)
await client.query(insertFistValue)
await client.query("COMMIT")
return 0
} catch (e) {
client.query("ROLLBACK")
console.error("[x] No se ha podido crear la tabla de versiones de la BDD")
console.error(e)
} finally {
client.release()
}
}
async function writeAppliedVersion(db: Pool, versionTable: string, version: MigrationFile) {
const client = await db.connect()
const insertVersion = `
INSERT INTO ${versionTable} (
version,
notes
)
VALUES (
$1,
$2
);
`
const parts = version.version.split("_")
try {
await client.query("BEGIN")
await client.query(insertVersion, parts)
await client.query("COMMIT")
return 0
} catch (e) {
client.query("ROLLBACK")
console.error("[x] No se ha podido insertar la nueva version de la BDD")
console.error(e)
} finally {
client.release()
}
}
@@ -128,7 +205,8 @@ async function getCurrentVersion(db: Pool) {
async function runMigrations(args: {
targetVersion: string,
currentVersion?: string,
migrationDir: string
migrationDir: string,
versionTable: string
}) {
let db;
try {
@@ -147,16 +225,19 @@ async function runMigrations(args: {
const dbClient = await db.connect()
try {
const versionBdd = (await getCurrentVersion(db, args.versionTable))?.version
if (versionBdd == undefined) {
await initVersionTable(db, args.versionTable)
}
// 1º La version explicita 2º La versión almacenada en BDD 3º 0.0.0 como version base
const versionBdd = (await getCurrentVersion(db))?.version
if (versionBdd == undefined) {
console.log("[x] Error buscando la ultima version de la base de datos")
}
const currentVersion = args.currentVersion ?? versionBdd ?? "0.0.0"
console.log("[i] Migrando desde la version " + currentVersion + " a la version " + args.targetVersion)
const files = await fs.readdir(args.migrationDir);
console.log("Directorio de migraciones", args.migrationDir)
console.log("Archivos de migraciones", files)
const pendingMigrations: MigrationFile[] = files
.map(f => (<MigrationFile>{
version: path.parse(f).name,
@@ -173,11 +254,10 @@ async function runMigrations(args: {
console.log("[o] La base de datos ya está actualizada.");
return;
}
console.log("[i] Migraciones pendietes", pendingMigrations)
console.log("[i] Migraciones pendietes", pendingMigrations.map(e => e.version))
console.log(`[i] Aplicando ${pendingMigrations.length} migraciones...`);
// Iniciamos Transacción (Ejemplo conceptual con un cliente genérico)
// await db.query('BEGIN');
await dbClient.query("BEGIN")
for (const migration of pendingMigrations) {
const sql = await fs.readFile(migration.fullPath, 'utf8');
@@ -185,29 +265,19 @@ async function runMigrations(args: {
// Ejecutar SQL
await dbClient.query(sql);
// Actualizar tabla de versión
// En principio esto se hace en el archivo pero estoy pensando en meterlo en el script para
// evitar olvidos
/* await dbClient.query(`
INSERT INTO db_versions (
version,
notes
)
VALUES (
$1,
'Fechas modificadas para que todas sean en base a UTC'
);
`)
*/
console.log(` -> Aplicado correctamente: ${migration.fileName}`);
}
await db.query("COMMIT")
await dbClient.query("COMMIT")
const ultimaVersion = pendingMigrations[pendingMigrations.length - 1]
await writeAppliedVersion(db, args.versionTable, ultimaVersion)
console.log("[o] Migraciones completadas con éxito.");
console.log("[o] Última version aplicada: ", ultimaVersion.version);
} catch (error) {
console.error("[x] Error durante la migración. Se ha realizado un rollback automático.");
console.error(error);
await db.query("ROLLBACK")
await dbClient.query("ROLLBACK")
process.exit(1);
} finally {
dbClient.release()
@@ -216,13 +286,18 @@ async function runMigrations(args: {
/**
* *******************************************************************
* MAIN
* *******************************************************************
*/
async function main() {
const args = getArgs();
await loadEnv(args.env);
runMigrations({ targetVersion: args.target, migrationDir: args.migrations })
await runMigrations({
targetVersion: args.target,
migrationDir: args.migrations,
versionTable: args.versionTable
})
}
main().then(e => console.log(e)).catch(console.error)