add db migration

This commit is contained in:
liuyi 2025-06-20 22:07:56 +08:00
parent 77e27a4b93
commit cecc96bbba
7 changed files with 144 additions and 7 deletions

View File

@ -0,0 +1,4 @@
export * from './migration.create.command';
export * from './migration.revert.command';
export * from './migration.generate.command';
export * from './migration.run.command';

View File

@ -0,0 +1,37 @@
import { Arguments } from 'yargs';
import { CommandItem } from '@/modules/core/types';
import { MigrationRevertHandler } from '@/modules/database/commands/migration.revert.handler';
import { MigrationRevertArguments } from '@/modules/database/commands/types';
export const RevertMigrationCommand: CommandItem<any, MigrationRevertArguments> = async ({
configure,
}) => ({
source: true,
command: ['db:migration:revert', 'dbmv'],
describe: 'Reverts last executed migration.',
builder: {
connection: {
type: 'string',
alias: 'c',
describe: 'Connection name of typeorm to connect database.',
},
transaction: {
type: 'string',
alias: 't',
describe:
'Indicates if transaction should be used or not for migration run/revert/reflash. Enabled by default.',
default: 'default',
},
fake: {
type: 'boolean',
alias: 'f',
describe:
'Fakes running the migrations if table schema has already been changed manually or externally ' +
'(e.g. through another project)',
},
} as const,
handler: async (args: Arguments<MigrationRevertArguments>) =>
MigrationRevertHandler(configure, args),
});

View File

@ -0,0 +1,62 @@
import { join } from 'path';
import chalk from 'chalk';
import { isNil } from 'lodash';
import ora from 'ora';
import { DataSource, DataSourceOptions } from 'typeorm';
import { Arguments } from 'yargs';
import { Configure } from '@/modules/config/configure';
import { panic } from '@/modules/core/helpers';
import { TypeormMigrationRevert } from '@/modules/database/commands/typeorm.migration.revert';
import { MigrationRevertArguments } from '@/modules/database/commands/types';
import { DBOptions } from '@/modules/database/types';
/**
*
* @param configure
* @param args
* @constructor
*/
export async function MigrationRevertHandler(
configure: Configure,
args: Arguments<MigrationRevertArguments>,
) {
const spinner = ora('Start to revert migration...');
const cname = args.connection ?? 'default';
let dataSource: DataSource | undefined;
try {
spinner.start();
const { connections = [] }: DBOptions = await configure.get<DBOptions>('database');
const dbConfig = connections.find(({ name }) => name === cname);
if (isNil(dbConfig)) {
await panic(`Database connection named ${cname} not exists!`);
}
console.log();
const runner = new TypeormMigrationRevert();
dataSource = new DataSource({ ...dbConfig } as DataSourceOptions);
dataSource.setOptions({
subscribers: [],
synchronize: false,
migrationsRun: false,
dropSchema: false,
logging: ['error'],
migrations: [
join(dbConfig.paths.migration, '**/*.ts'),
join(dbConfig.paths.migration, '**/*.js'),
],
});
await dataSource.initialize();
console.log();
await runner.handler({ dataSource, transaction: args.transaction, fake: args.fake });
spinner.succeed(chalk.greenBright.underline('\n 👍 Finished revert migrations'));
} catch (error) {
await panic({ spinner, message: 'revert migrations failed!', error });
} finally {
if (dataSource && dataSource.isInitialized) {
await dataSource.destroy();
}
}
}

View File

@ -0,0 +1,28 @@
import { DataSource } from 'typeorm';
import { MigrationRevertOptions } from '@/modules/database/commands/types';
type HandleOptions = MigrationRevertOptions & { dataSource: DataSource };
export class TypeormMigrationRevert {
async handler({ transaction, fake, dataSource }: HandleOptions) {
const options = {
transaction: dataSource.options.migrationsTransactionMode ?? 'all',
fake,
};
switch (transaction) {
case 'all':
options.transaction = 'all';
break;
case 'none':
case 'false':
options.transaction = 'none';
break;
case 'each':
options.transaction = 'each';
break;
default:
}
await dataSource.undoLastMigration(options);
}
}

View File

@ -55,3 +55,8 @@ export interface MigrationRevertOptions {
fake?: boolean;
}
/**
*
*/
export type MigrationRevertArguments = TypeOrmArguments & MigrationRevertOptions;

View File

@ -7,9 +7,9 @@ import { panic } from '../core/helpers';
@Module({})
export class MeiliModule {
static forRoot(configure: Configure): DynamicModule {
static async forRoot(configure: Configure): Promise<DynamicModule> {
if (!configure.has('meili')) {
panic({ message: 'MeilliSearch config not exists' });
await panic({ message: 'MeiliSearch config not exists' });
}
return {
global: true,

View File

@ -10,6 +10,7 @@ import { isNil } from 'lodash';
import * as configs from './config';
import { ContentModule } from './modules/content/content.module';
import { CreateOptions } from './modules/core/types';
import * as dbCommands from './modules/database/commands';
import { DatabaseModule } from './modules/database/database.module';
import { MeiliModule } from './modules/meilisearch/meili.module';
import { Restful } from './modules/restful/restful';
@ -17,13 +18,13 @@ import { RestfulModule } from './modules/restful/restful.module';
import { ApiConfig } from './modules/restful/types';
export const createOptions: CreateOptions = {
commands: () => [],
commands: () => [...Object.values(dbCommands)],
config: { factories: configs as any, storage: { enable: true } },
modules: async (configure) => [
DatabaseModule.forRoot(configure),
MeiliModule.forRoot(configure),
RestfulModule.forRoot(configure),
ContentModule.forRoot(configure),
await DatabaseModule.forRoot(configure),
await MeiliModule.forRoot(configure),
await RestfulModule.forRoot(configure),
await ContentModule.forRoot(configure),
],
globals: {},
builder: async ({ configure, BootModule }) => {