la version ya no es PK
This commit is contained in:
139
src/index.ts
139
src/index.ts
@@ -1,6 +1,5 @@
|
|||||||
#!/usr/bin/node
|
#!/usr/bin/node
|
||||||
|
|
||||||
import { constants } from 'buffer';
|
|
||||||
import { existsSync } from 'fs';
|
import { existsSync } from 'fs';
|
||||||
import fs from 'fs/promises';
|
import fs from 'fs/promises';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
@@ -60,19 +59,25 @@ function getArgs() {
|
|||||||
type: "string",
|
type: "string",
|
||||||
description: "Path del directorio de migrations"
|
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 {
|
.parse() as {
|
||||||
target: string,
|
target: string,
|
||||||
env: string,
|
env: string,
|
||||||
migrations: string
|
migrations: string,
|
||||||
|
versionTable: "db_versions" | string
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("args", argv)
|
//console.log("args", argv)
|
||||||
/* Antiguo */
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
target: argv.target,
|
target: argv.target,
|
||||||
env: argv.env,
|
env: argv.env,
|
||||||
migrations: argv.migrations
|
migrations: argv.migrations,
|
||||||
|
versionTable: argv.versionTable
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,17 +111,89 @@ function compareVersions(va: string, vb: string) {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getCurrentVersion(db: Pool) {
|
async function getCurrentVersion(db: Pool, versionTable: string) {
|
||||||
try {
|
try {
|
||||||
const lastVersion = await db.query<DBVersion>(`
|
const lastVersion = await db.query<DBVersion>(`
|
||||||
SELECT * FROM db_versions
|
SELECT * FROM ${versionTable}
|
||||||
ORDER BY creation_date DESC
|
ORDER BY creation_date DESC
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
`)
|
`)
|
||||||
return lastVersion.rows[0]
|
return lastVersion.rows[0]
|
||||||
} catch (e) {
|
} 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)
|
console.error(e)
|
||||||
} finally {
|
} 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: {
|
async function runMigrations(args: {
|
||||||
targetVersion: string,
|
targetVersion: string,
|
||||||
currentVersion?: string,
|
currentVersion?: string,
|
||||||
migrationDir: string
|
migrationDir: string,
|
||||||
|
versionTable: string
|
||||||
}) {
|
}) {
|
||||||
let db;
|
let db;
|
||||||
try {
|
try {
|
||||||
@@ -147,16 +225,19 @@ async function runMigrations(args: {
|
|||||||
|
|
||||||
const dbClient = await db.connect()
|
const dbClient = await db.connect()
|
||||||
try {
|
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
|
// 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) {
|
if (versionBdd == undefined) {
|
||||||
console.log("[x] Error buscando la ultima version de la base de datos")
|
console.log("[x] Error buscando la ultima version de la base de datos")
|
||||||
}
|
}
|
||||||
const currentVersion = args.currentVersion ?? versionBdd ?? "0.0.0"
|
const currentVersion = args.currentVersion ?? versionBdd ?? "0.0.0"
|
||||||
console.log("[i] Migrando desde la version " + currentVersion + " a la version " + args.targetVersion)
|
console.log("[i] Migrando desde la version " + currentVersion + " a la version " + args.targetVersion)
|
||||||
const files = await fs.readdir(args.migrationDir);
|
const files = await fs.readdir(args.migrationDir);
|
||||||
console.log("Directorio de migraciones", args.migrationDir)
|
|
||||||
console.log("Archivos de migraciones", files)
|
|
||||||
const pendingMigrations: MigrationFile[] = files
|
const pendingMigrations: MigrationFile[] = files
|
||||||
.map(f => (<MigrationFile>{
|
.map(f => (<MigrationFile>{
|
||||||
version: path.parse(f).name,
|
version: path.parse(f).name,
|
||||||
@@ -173,11 +254,10 @@ async function runMigrations(args: {
|
|||||||
console.log("[o] La base de datos ya está actualizada.");
|
console.log("[o] La base de datos ya está actualizada.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("[i] Migraciones pendietes", pendingMigrations)
|
console.log("[i] Migraciones pendietes", pendingMigrations.map(e => e.version))
|
||||||
console.log(`[i] Aplicando ${pendingMigrations.length} migraciones...`);
|
console.log(`[i] Aplicando ${pendingMigrations.length} migraciones...`);
|
||||||
|
|
||||||
// Iniciamos Transacción (Ejemplo conceptual con un cliente genérico)
|
// Iniciamos Transacción (Ejemplo conceptual con un cliente genérico)
|
||||||
// await db.query('BEGIN');
|
|
||||||
await dbClient.query("BEGIN")
|
await dbClient.query("BEGIN")
|
||||||
for (const migration of pendingMigrations) {
|
for (const migration of pendingMigrations) {
|
||||||
const sql = await fs.readFile(migration.fullPath, 'utf8');
|
const sql = await fs.readFile(migration.fullPath, 'utf8');
|
||||||
@@ -185,29 +265,19 @@ async function runMigrations(args: {
|
|||||||
|
|
||||||
// Ejecutar SQL
|
// Ejecutar SQL
|
||||||
await dbClient.query(sql);
|
await dbClient.query(sql);
|
||||||
|
console.log(` -> Aplicado correctamente: ${migration.fileName}`);
|
||||||
// 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'
|
|
||||||
);
|
|
||||||
`)
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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] Migraciones completadas con éxito.");
|
||||||
|
console.log("[o] Última version aplicada: ", ultimaVersion.version);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[x] Error durante la migración. Se ha realizado un rollback automático.");
|
console.error("[x] Error durante la migración. Se ha realizado un rollback automático.");
|
||||||
console.error(error);
|
console.error(error);
|
||||||
await db.query("ROLLBACK")
|
await dbClient.query("ROLLBACK")
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
} finally {
|
} finally {
|
||||||
dbClient.release()
|
dbClient.release()
|
||||||
@@ -216,13 +286,18 @@ async function runMigrations(args: {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* *******************************************************************
|
* *******************************************************************
|
||||||
|
* MAIN
|
||||||
* *******************************************************************
|
* *******************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const args = getArgs();
|
const args = getArgs();
|
||||||
await loadEnv(args.env);
|
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)
|
main().then(e => console.log(e)).catch(console.error)
|
||||||
|
|||||||
Reference in New Issue
Block a user