diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/0-53/0-53-copy-typeorm-migrations.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/0-53/0-53-copy-typeorm-migrations.command.ts new file mode 100644 index 000000000..03be096dc --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/0-53/0-53-copy-typeorm-migrations.command.ts @@ -0,0 +1,91 @@ +import { InjectRepository } from '@nestjs/typeorm'; + +import { Command } from 'nest-commander'; +import { Repository } from 'typeorm'; + +import { + ActiveOrSuspendedWorkspacesMigrationCommandRunner, + RunOnWorkspaceArgs, +} from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; +import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; + +@Command({ + name: 'upgrade:0-53:copy-typeorm-migrations', + description: 'Copy _typeorm_migrations from metadata schema to core schema', +}) +export class CopyTypeormMigrationsCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { + constructor( + @InjectRepository(Workspace, 'core') + protected readonly workspaceRepository: Repository, + protected readonly twentyORMGlobalManager: TwentyORMGlobalManager, + ) { + super(workspaceRepository, twentyORMGlobalManager); + } + + async runOnWorkspace(args: RunOnWorkspaceArgs): Promise { + // This command doesn't need to run per workspace, only once + if (args.index !== 0) { + return; + } + + this.logger.log( + 'Starting to copy _typeorm_migrations from metadata to core', + ); + + const queryRunner = + this.workspaceRepository.manager.connection.createQueryRunner(); + + try { + await queryRunner.connect(); + await queryRunner.startTransaction(); + + const metadataMigrations = await queryRunner.query( + 'SELECT * FROM metadata._typeorm_migrations ORDER BY id ASC', + ); + + this.logger.log( + `Found ${metadataMigrations.length} migrations in metadata schema`, + ); + + if (args.options?.dryRun) { + this.logger.log('Dry run mode - no changes will be applied'); + + return; + } + + const existingCoreMigrations = await queryRunner.query( + 'SELECT name FROM core._typeorm_migrations', + ); + + const existingMigrationNames = new Set( + existingCoreMigrations.map((migration) => migration.name), + ); + + for (const migration of metadataMigrations) { + if (!existingMigrationNames.has(migration.name)) { + await queryRunner.query( + 'INSERT INTO core._typeorm_migrations ("timestamp", name) VALUES ($1, $2)', + [migration.timestamp, migration.name], + ); + this.logger.log(`Copied migration: ${migration.name}`); + } else { + this.logger.log( + `Migration ${migration.name} already exists in core schema`, + ); + } + } + + await queryRunner.commitTransaction(); + this.logger.log( + 'Successfully copied all migrations from metadata to core schema', + ); + } catch (error) { + await queryRunner.rollbackTransaction(); + this.logger.error(`Failed to copy migrations: ${error.message}`); + throw error; + } finally { + await queryRunner.release(); + } + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/0-53/0-53-upgrade-version-command.module.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/0-53/0-53-upgrade-version-command.module.ts index f153e98ee..c2bcac09f 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/0-53/0-53-upgrade-version-command.module.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/0-53/0-53-upgrade-version-command.module.ts @@ -2,6 +2,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { BackfillWorkflowNextStepIdsCommand } from 'src/database/commands/upgrade-version-command/0-53/0-53-backfill-workflow-next-step-ids.command'; +import { CopyTypeormMigrationsCommand } from 'src/database/commands/upgrade-version-command/0-53/0-53-copy-typeorm-migrations.command'; import { MigrateWorkflowEventListenersToAutomatedTriggersCommand } from 'src/database/commands/upgrade-version-command/0-53/0-53-migrate-workflow-event-listeners-to-automated-triggers.command'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; @@ -14,10 +15,12 @@ import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/works providers: [ MigrateWorkflowEventListenersToAutomatedTriggersCommand, BackfillWorkflowNextStepIdsCommand, + CopyTypeormMigrationsCommand, ], exports: [ MigrateWorkflowEventListenersToAutomatedTriggersCommand, BackfillWorkflowNextStepIdsCommand, + CopyTypeormMigrationsCommand, ], }) export class V0_53_UpgradeVersionCommandModule {} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade.command.ts index 45746e5a0..0a08d5fa6 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade.command.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade.command.ts @@ -19,6 +19,7 @@ import { UpgradeCreatedByEnumCommand } from 'src/database/commands/upgrade-versi import { MigrateRelationsToFieldMetadataCommand } from 'src/database/commands/upgrade-version-command/0-52/0-52-migrate-relations-to-field-metadata.command'; import { UpgradeDateAndDateTimeFieldsSettingsJsonCommand } from 'src/database/commands/upgrade-version-command/0-52/0-52-upgrade-settings-field'; import { BackfillWorkflowNextStepIdsCommand } from 'src/database/commands/upgrade-version-command/0-53/0-53-backfill-workflow-next-step-ids.command'; +import { CopyTypeormMigrationsCommand } from 'src/database/commands/upgrade-version-command/0-53/0-53-copy-typeorm-migrations.command'; import { MigrateWorkflowEventListenersToAutomatedTriggersCommand } from 'src/database/commands/upgrade-version-command/0-53/0-53-migrate-workflow-event-listeners-to-automated-triggers.command'; import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; @@ -60,6 +61,7 @@ export class UpgradeCommand extends UpgradeCommandRunner { // 0.53 Commands protected readonly migrateWorkflowEventListenersToAutomatedTriggersCommand: MigrateWorkflowEventListenersToAutomatedTriggersCommand, protected readonly backfillWorkflowNextStepIdsCommand: BackfillWorkflowNextStepIdsCommand, + protected readonly copyTypeormMigrationsCommand: CopyTypeormMigrationsCommand, ) { super( workspaceRepository, @@ -111,6 +113,7 @@ export class UpgradeCommand extends UpgradeCommandRunner { afterSyncMetadata: [ this.migrateWorkflowEventListenersToAutomatedTriggersCommand, this.backfillWorkflowNextStepIdsCommand, + this.copyTypeormMigrationsCommand, ], };