From e0d2388e95c83baead0bbfcca73f83fbc8e4ec35 Mon Sep 17 00:00:00 2001 From: yassinedorbozgithub Date: Sat, 4 Jan 2025 10:00:29 +0100 Subject: [PATCH] fix: unhance migration logic --- api/src/migration/migration.service.ts | 68 +++++++++++--------- api/src/migration/types.ts | 13 +++- api/src/setting/services/metadata.service.ts | 16 ++--- 3 files changed, 53 insertions(+), 44 deletions(-) diff --git a/api/src/migration/migration.service.ts b/api/src/migration/migration.service.ts index ae22c4f3..16e0d50d 100644 --- a/api/src/migration/migration.service.ts +++ b/api/src/migration/migration.service.ts @@ -28,6 +28,7 @@ import { MigrationAction, MigrationRunParams, MigrationSuccessCallback, + MigrationTrigger, } from './types'; @Injectable() @@ -146,23 +147,18 @@ module.exports = { }: MigrationRunParams) { if (!name) { if (isAutoMigrate) { - const newVersion = await this.runFromVersion(action, version); - - await this.metadataService.findOrCreate({ - name: 'db-version', - value: newVersion, - }); + await this.runFromVersion(action, version); } else { await this.runAll(action); this.exit(); } } else { - await this.runOne({ action, name }); + await this.runOne({ action, name, trigger: MigrationTrigger.CLI }); this.exit(); } } - private async runOne({ name, action }: MigrationRunParams) { + private async runOne({ name, action, trigger }: MigrationRunParams) { // verify DB status const { exist, migrationDocument } = await this.verifyStatus({ name, @@ -179,6 +175,7 @@ module.exports = { name, action, migrationDocument, + trigger, }); } catch (e) { this.failureCallback({ @@ -216,37 +213,27 @@ module.exports = { } private async runFromVersion(action: MigrationAction, version: string) { - const files = await this.getDirFiles(); - const migrationFiles = files - .filter((fileName) => fileName.endsWith('.migration.js')) - .map((fileName) => { - const [migrationFileName] = fileName.split('.'); - const [, , ...migrationVersion] = migrationFileName.split('-'); - return `v${migrationVersion.join('.')}`; - }) - .filter((v) => this.isNewerVersion(v, version)); - + const filenames = await this.getDirFiles(); + const versions = this.getVersionsFromFilenames(filenames); + const filteredVersions = versions.filter( + (v) => v === version || this.isNewerVersion(v, version), + ); let lastVersion = version; - for (const name of migrationFiles) { - await this.runOne({ name, action }); - lastVersion = name; + + for (const version of filteredVersions) { + await this.runOne({ name: version, action }); + lastVersion = version; } return lastVersion; } private async runAll(action: MigrationAction) { - const files = await this.getDirFiles(); - const migrationFiles = files - .filter((fileName) => fileName.includes('migration')) - .map((fileName) => { - const [migrationFileName] = fileName.split('.'); - const [, , ...migrationVersion] = migrationFileName.split('-'); - return `v${migrationVersion.join('.')}`; - }); + const filenames = await this.getDirFiles(); + const versions = this.getVersionsFromFilenames(filenames); - for (const name of migrationFiles) { - await this.runOne({ name, action }); + for (const version of versions) { + await this.runOne({ name: version, action }); } } @@ -285,6 +272,16 @@ module.exports = { return migrationName; } + private getVersionsFromFilenames(filenames: string[]) { + return filenames + .filter((fileName) => fileName.endsWith('.migration.js')) + .map((filename: string) => { + const [migrationFileName] = filename.split('.'); + const [, , ...migrationVersion] = migrationFileName.split('-'); + return `v${migrationVersion.join('.')}`; + }); + } + async findMigrationFileByName(name: string): Promise { const files = await this.getMigrationFiles(); return ( @@ -342,10 +339,19 @@ module.exports = { name, action, migrationDocument, + trigger, }: MigrationSuccessCallback) { await this.updateStatus({ name, action, migrationDocument }); const migrationDisplayName = `${name} [${action}]`; this.logger.log(`"${migrationDisplayName}" migration done`); + if (trigger === MigrationTrigger.CLI) { + const result = await this.metadataService.createOrUpdate({ + name: 'db-version', + value: name, + }); + const operation = result ? 'updated' : 'created'; + this.logger.log(`db-version metadata ${operation} "${name}"`); + } } private failureCallback({ name, action }: MigrationRunParams) { diff --git a/api/src/migration/types.ts b/api/src/migration/types.ts index 403a424c..da406ce9 100644 --- a/api/src/migration/types.ts +++ b/api/src/migration/types.ts @@ -13,15 +13,26 @@ enum MigrationAction { DOWN = 'down', } +enum MigrationTrigger { + CLI = 'cli', + PROGRAM = 'program', +} + interface MigrationRunParams { name?: string; action: MigrationAction; version?: string; isAutoMigrate?: boolean; + trigger?: MigrationTrigger; } interface MigrationSuccessCallback extends MigrationRunParams { migrationDocument: MigrationDocument; } -export { MigrationAction, MigrationRunParams, MigrationSuccessCallback }; +export { + MigrationAction, + MigrationRunParams, + MigrationSuccessCallback, + MigrationTrigger, +}; diff --git a/api/src/setting/services/metadata.service.ts b/api/src/setting/services/metadata.service.ts index dfcac8a4..cbea67cd 100644 --- a/api/src/setting/services/metadata.service.ts +++ b/api/src/setting/services/metadata.service.ts @@ -19,18 +19,10 @@ export class MetadataService { private readonly metadataModel: Model, ) {} - async createMetadata(dto: Partial) { - return await this.metadataModel.create(dto); - } - - async findOrCreate(dto: Partial) { - const metadata = await this.metadataModel.findOne({ name: dto.name }); - - if (metadata) { - await this.setMetadata(dto.name, dto.value); - } else { - await this.createMetadata(dto); - } + async createOrUpdate(dto: Metadata) { + return await this.metadataModel.findOneAndUpdate({ name: dto.name }, dto, { + upsert: true, + }); } async getMetadata(name: string) {