Add command line interface and allow rolling back migrations
This commit is contained in:
parent
91b9e51a7d
commit
499c66240b
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "wms-core",
|
"name": "wms-core",
|
||||||
"version": "0.6.0",
|
"version": "0.6.8",
|
||||||
"description": "Node web framework",
|
"description": "Node web framework",
|
||||||
"repository": "git@gitlab.com:ArisuOngaku/wms-core.git",
|
"repository": "git@gitlab.com:ArisuOngaku/wms-core.git",
|
||||||
"author": "Alice Gaudon <alice@gaudon.pro>",
|
"author": "Alice Gaudon <alice@gaudon.pro>",
|
||||||
|
@ -48,6 +48,12 @@ export default abstract class Application {
|
|||||||
// Register migrations
|
// Register migrations
|
||||||
MysqlConnectionManager.registerMigrations(this.getMigrations());
|
MysqlConnectionManager.registerMigrations(this.getMigrations());
|
||||||
|
|
||||||
|
// Process command line
|
||||||
|
if (await this.processCommandLine()) {
|
||||||
|
await this.stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Register all components and alike
|
// Register all components and alike
|
||||||
await this.init();
|
await this.init();
|
||||||
|
|
||||||
@ -118,6 +124,24 @@ export default abstract class Application {
|
|||||||
this.ready = true;
|
this.ready = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async processCommandLine(): Promise<boolean> {
|
||||||
|
const args = process.argv;
|
||||||
|
for (let i = 2; i < args.length; i++) {
|
||||||
|
switch (args[i]) {
|
||||||
|
case '--verbose':
|
||||||
|
Logger.verbose();
|
||||||
|
break;
|
||||||
|
case 'migration':
|
||||||
|
await MysqlConnectionManager.migrationCommand(args.slice(i + 1));
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
Logger.warn('Unrecognized argument', args[i]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
async stop(): Promise<void> {
|
async stop(): Promise<void> {
|
||||||
Logger.info('Stopping application...');
|
Logger.info('Stopping application...');
|
||||||
|
|
||||||
|
@ -2,10 +2,15 @@ import config from "config";
|
|||||||
import {v4 as uuid} from "uuid";
|
import {v4 as uuid} from "uuid";
|
||||||
import Log from "./models/Log";
|
import Log from "./models/Log";
|
||||||
|
|
||||||
const LOG_LEVEL: LogLevelKeys = <LogLevelKeys>config.get<string>('log_level');
|
|
||||||
const DB_LOG_LEVEL: LogLevelKeys = <LogLevelKeys>config.get<string>('db_log_level');
|
|
||||||
|
|
||||||
export default class Logger {
|
export default class Logger {
|
||||||
|
private static logLevel: LogLevelKeys = <LogLevelKeys>config.get<string>('log_level');
|
||||||
|
private static dbLogLevel: LogLevelKeys = <LogLevelKeys>config.get<string>('db_log_level');
|
||||||
|
|
||||||
|
public static verbose() {
|
||||||
|
this.logLevel = <LogLevelKeys>LogLevel[LogLevel[this.logLevel] + 1] || this.logLevel;
|
||||||
|
this.dbLogLevel = <LogLevelKeys>LogLevel[LogLevel[this.dbLogLevel] + 1] || this.dbLogLevel;
|
||||||
|
}
|
||||||
|
|
||||||
public static silentError(error: Error, ...message: any[]): string {
|
public static silentError(error: Error, ...message: any[]): string {
|
||||||
return this.log('ERROR', message, error, true) || '';
|
return this.log('ERROR', message, error, true) || '';
|
||||||
}
|
}
|
||||||
@ -32,7 +37,7 @@ export default class Logger {
|
|||||||
|
|
||||||
private static log(level: LogLevelKeys, message: any[], error?: Error, silent: boolean = false): string | null {
|
private static log(level: LogLevelKeys, message: any[], error?: Error, silent: boolean = false): string | null {
|
||||||
const levelIndex = LogLevel[level];
|
const levelIndex = LogLevel[level];
|
||||||
if (levelIndex <= LogLevel[LOG_LEVEL]) {
|
if (levelIndex <= LogLevel[this.logLevel]) {
|
||||||
if (error) {
|
if (error) {
|
||||||
if (levelIndex > LogLevel.ERROR) this.warn(`Wrong log level ${level} with attached error.`);
|
if (levelIndex > LogLevel.ERROR) this.warn(`Wrong log level ${level} with attached error.`);
|
||||||
} else {
|
} else {
|
||||||
@ -71,7 +76,7 @@ export default class Logger {
|
|||||||
|
|
||||||
let output = `[${level}] `;
|
let output = `[${level}] `;
|
||||||
let pad = output.length;
|
let pad = output.length;
|
||||||
if (levelIndex <= LogLevel[DB_LOG_LEVEL]) output += `${log.getLogID()} - `;
|
if (levelIndex <= LogLevel[this.dbLogLevel]) output += `${log.getLogID()} - `;
|
||||||
output += computedMsg.replace(/\n/g, '\n' + ' '.repeat(pad));
|
output += computedMsg.replace(/\n/g, '\n' + ' '.repeat(pad));
|
||||||
|
|
||||||
switch (level) {
|
switch (level) {
|
||||||
@ -94,7 +99,7 @@ export default class Logger {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (levelIndex <= LogLevel[DB_LOG_LEVEL]) {
|
if (levelIndex <= LogLevel[this.dbLogLevel]) {
|
||||||
log.save().catch(err => {
|
log.save().catch(err => {
|
||||||
if (!silent && err.message.indexOf('ECONNREFUSED') < 0) {
|
if (!silent && err.message.indexOf('ECONNREFUSED') < 0) {
|
||||||
console.error({save_err: err, error});
|
console.error({save_err: err, error});
|
||||||
|
@ -45,7 +45,7 @@ export default class Mail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static end() {
|
public static end() {
|
||||||
this.transporter.close();
|
if (this.transporter) this.transporter.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static parse(template: string, data: any, textOnly: boolean): string {
|
public static parse(template: string, data: any, textOnly: boolean): string {
|
||||||
|
@ -32,7 +32,7 @@ export default class MysqlConnectionManager {
|
|||||||
this.migrations.push(migration(this.migrations.length + 1));
|
this.migrations.push(migration(this.migrations.length + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async prepare() {
|
public static async prepare(runMigrations: boolean = true) {
|
||||||
if (config.get('mysql.create_database_automatically') === true) {
|
if (config.get('mysql.create_database_automatically') === true) {
|
||||||
const dbName = config.get('mysql.database');
|
const dbName = config.get('mysql.database');
|
||||||
Logger.info(`Creating database ${dbName}...`);
|
Logger.info(`Creating database ${dbName}...`);
|
||||||
@ -55,7 +55,7 @@ export default class MysqlConnectionManager {
|
|||||||
}
|
}
|
||||||
this.databaseReady = true;
|
this.databaseReady = true;
|
||||||
|
|
||||||
await this.handleMigrations();
|
if (runMigrations) await this.handleMigrations();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static get pool(): Pool {
|
public static get pool(): Pool {
|
||||||
@ -152,7 +152,7 @@ export default class MysqlConnectionManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async handleMigrations() {
|
public static async getCurrentMigrationVersion(): Promise<number> {
|
||||||
let currentVersion = 0;
|
let currentVersion = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -164,6 +164,11 @@ export default class MysqlConnectionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return currentVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async handleMigrations() {
|
||||||
|
const currentVersion = await this.getCurrentMigrationVersion();
|
||||||
for (const migration of this.migrations) {
|
for (const migration of this.migrations) {
|
||||||
if (await migration.shouldRun(currentVersion)) {
|
if (await migration.shouldRun(currentVersion)) {
|
||||||
Logger.info('Running migration ', migration.version, migration.constructor.name);
|
Logger.info('Running migration ', migration.version, migration.constructor.name);
|
||||||
@ -177,4 +182,37 @@ export default class MysqlConnectionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param migrationID what migration to rollback. Use with caution. default=0 is for last registered migration.
|
||||||
|
*/
|
||||||
|
public static async rollbackMigration(migrationID: number = 0): Promise<void> {
|
||||||
|
migrationID--;
|
||||||
|
const migration = this.migrations[migrationID];
|
||||||
|
Logger.info('Rolling back migration ', migration.version, migration.constructor.name);
|
||||||
|
await MysqlConnectionManager.wrapTransaction<void>(async c => {
|
||||||
|
await migration.rollback(c);
|
||||||
|
await query('DELETE FROM migrations WHERE id=?', [migration.version]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async migrationCommand(args: string[]): Promise<void> {
|
||||||
|
try {
|
||||||
|
Logger.info('Current migration:', await this.getCurrentMigrationVersion());
|
||||||
|
|
||||||
|
for (let i = 0; i < args.length; i++) {
|
||||||
|
if (args[i] === 'rollback') {
|
||||||
|
let migrationID = 0;
|
||||||
|
if (args.length > i + 1) {
|
||||||
|
migrationID = parseInt(args[i + 1]);
|
||||||
|
}
|
||||||
|
await this.prepare(false);
|
||||||
|
await this.rollbackMigration(migrationID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
await MysqlConnectionManager.endPool();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user