diff --git a/src/client/client.ts b/src/client/client.ts index bd3bed31..7bb12279 100644 --- a/src/client/client.ts +++ b/src/client/client.ts @@ -12,7 +12,8 @@ import { } from 'discord.js' import { type AnyFunction, constants } from '../utils' import { type BaseHandler, SettingProvider, WebSocketManager } from '.' -import { decorate, inject, injectable, type interfaces, optional } from 'inversify' +import { decorate, inject, injectable, type interfaces, multiInject, optional } from 'inversify' +import type { BaseMigration } from './migrations' import applicationConfig from '../configs/application' const { TYPES } = constants @@ -48,6 +49,9 @@ export default class AroraClient extends Client @optional() private readonly aroraWs?: WebSocketManager + @multiInject(TYPES.Migration) + private readonly migrations!: BaseMigration[] + public mainGuild: Guild | null = null private currentActivity: number = 0 @@ -61,6 +65,7 @@ export default class AroraClient extends Client private async ready (): Promise { await this.settingProvider.init(this) + await this.runMigrations() const mainGuildId = process.env.NODE_ENV === 'production' ? applicationConfig.productionMainGuildId @@ -132,6 +137,14 @@ export default class AroraClient extends Client return usedToken } + private async runMigrations (): Promise { + for (const migration of this.migrations) { + if (await migration.shouldRun?.(this as AroraClient) ?? true) { + await migration.run(this as AroraClient) + } + } + } + private bindEvent (eventName: keyof ClientEvents): void { const handler = this.eventHandlerFactory(eventName) this.on(eventName, handler.handle.bind(handler)) diff --git a/src/client/index.ts b/src/client/index.ts index 9a44f08a..20984562 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -1,5 +1,7 @@ +export * from './migrations' export * from './websocket' export * as eventHandlers from './events' +export * as migrations from './migrations' export type { default as BaseHandler } from './base' export { default as AroraClient } from './client' export { default as Dispatcher } from './dispatcher' diff --git a/src/client/migrations/base.ts b/src/client/migrations/base.ts new file mode 100644 index 00000000..e43e304e --- /dev/null +++ b/src/client/migrations/base.ts @@ -0,0 +1,8 @@ +import type { AroraClient } from '..' +import type { QueryRunner } from 'typeorm' + +export default interface BaseMigration { + shouldRun? (client: AroraClient, queryRunner?: QueryRunner): boolean | Promise + run (client: AroraClient, queryRunner?: QueryRunner): void | Promise + revert (client: AroraClient, queryRunner?: QueryRunner): void | Promise +} diff --git a/src/client/migrations/index.ts b/src/client/migrations/index.ts new file mode 100644 index 00000000..63660818 --- /dev/null +++ b/src/client/migrations/index.ts @@ -0,0 +1 @@ +export type { default as BaseMigration } from './base' diff --git a/src/configs/container.ts b/src/configs/container.ts index 4e9ddae7..58094a73 100644 --- a/src/configs/container.ts +++ b/src/configs/container.ts @@ -8,6 +8,7 @@ import { Argument, type ArgumentOptions, type BaseCommand } from '../interaction import { AroraClient, type BaseHandler, + type BaseMigration, Dispatcher, SettingProvider, WebSocketManager, @@ -292,6 +293,21 @@ bind } ) +// Migrations +container.onActivation(TYPES.Migration, (_context: interfaces.Context, migration: BaseMigration) => { + const handler = { + apply: function (target: (...args: any[]) => any, thisArgument: BaseMigration, argumentsList: any[]) { + return target.apply(thisArgument, [...argumentsList, dataSource.createQueryRunner()]) + } + } + if (typeof migration.shouldRun !== 'undefined') { + migration.shouldRun = new Proxy(migration.shouldRun, handler) + } + migration.run = new Proxy(migration.run, handler) + migration.revert = new Proxy(migration.revert, handler) + return migration +}) + // Structures bind(TYPES.Structure).to(structures.ChannelGroup) .whenTargetNamed('ChannelGroup') diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 0ba5db67..59b72a69 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -25,6 +25,8 @@ export const TYPES = { Manager: Symbol.for('Manager'), ManagerFactory: Symbol.for('ManagerFactory'), + Migration: Symbol.for('Migration'), + Structure: Symbol.for('Structure'), StructureFactory: Symbol.for('StructureFactory'),