diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-create-view-kanban-field-metadata-id-foreign-key-migration.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-create-view-kanban-field-metadata-id-foreign-key-migration.command.ts new file mode 100644 index 0000000000..9cca7beb5d --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-create-view-kanban-field-metadata-id-foreign-key-migration.command.ts @@ -0,0 +1,57 @@ +import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; + +import { Command } from 'nest-commander'; +import { DataSource, Repository } from 'typeorm'; + +import { + ActiveOrSuspendedWorkspacesMigrationCommandRunner, + type RunOnWorkspaceArgs, +} from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; +import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; +import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; + +@Command({ + name: '1-10-create-view-kanban-field-metadata-id-foreign-key-migration', + description: + 'Create FK_b3cc95732479f7a1337350c398f foreign key on view kanban field metadata id column', +}) +export class CreateViewKanbanFieldMetadataIdForeignKeyMigrationCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { + private hasRunOnce = false; + + constructor( + @InjectRepository(WorkspaceEntity) + protected readonly workspaceRepository: Repository, + protected readonly twentyORMGlobalManager: TwentyORMGlobalManager, + @InjectDataSource() + private readonly coreDataSource: DataSource, + ) { + super(workspaceRepository, twentyORMGlobalManager); + } + + override async runOnWorkspace({ + options, + }: RunOnWorkspaceArgs): Promise { + if (this.hasRunOnce) { + this.logger.log('Skipping kanban field metadata id foreign key creation'); + + return; + } + + if (!options.dryRun) { + try { + await this.coreDataSource.query( + `ALTER TABLE "core"."view" ADD CONSTRAINT "FK_b3cc95732479f7a1337350c398f" FOREIGN KEY ("kanbanAggregateOperationFieldMetadataId") REFERENCES "core"."fieldMetadata"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + this.logger.log( + 'Successfully added foreign key constraint for kanbanAggregateOperationFieldMetadataId', + ); + } catch (error) { + this.logger.log( + `Foreign key constraint already exists or could not be created (this is expected for subsequent workspaces): ${error.message}`, + ); + } + } + + this.hasRunOnce = true; + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-upgrade-version-command.module.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-upgrade-version-command.module.ts index 74899a66cf..ef3bfba996 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-upgrade-version-command.module.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-upgrade-version-command.module.ts @@ -3,6 +3,7 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { AddWorkflowRunStopStatusesCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-add-workflow-run-stop-statuses.command'; import { CleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-clean-orphaned-kanban-aggregate-operation-field-metadata-id.command'; +import { CreateViewKanbanFieldMetadataIdForeignKeyMigrationCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-create-view-kanban-field-metadata-id-foreign-key-migration.command'; import { MigrateAttachmentAuthorToCreatedByCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-attachment-author-to-created-by.command'; import { MigrateAttachmentTypeToFileCategoryCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-attachment-type-to-file-category.command'; import { MigrateChannelPartialFullSyncStagesCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-channel-partial-full-sync-stages.command'; @@ -32,6 +33,7 @@ import { WorkspaceSchemaManagerModule } from 'src/engine/twenty-orm/workspace-sc RegenerateSearchVectorsCommand, AddWorkflowRunStopStatusesCommand, CleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand, + CreateViewKanbanFieldMetadataIdForeignKeyMigrationCommand, ], exports: [ MigrateAttachmentAuthorToCreatedByCommand, @@ -40,6 +42,7 @@ import { WorkspaceSchemaManagerModule } from 'src/engine/twenty-orm/workspace-sc AddWorkflowRunStopStatusesCommand, CleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand, MigrateChannelPartialFullSyncStagesCommand, + CreateViewKanbanFieldMetadataIdForeignKeyMigrationCommand, ], }) export class V1_10_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 a7d0180efb..882acb1080 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 @@ -11,6 +11,7 @@ import { } from 'src/database/commands/command-runners/upgrade.command-runner'; import { AddWorkflowRunStopStatusesCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-add-workflow-run-stop-statuses.command'; import { CleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-clean-orphaned-kanban-aggregate-operation-field-metadata-id.command'; +import { CreateViewKanbanFieldMetadataIdForeignKeyMigrationCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-create-view-kanban-field-metadata-id-foreign-key-migration.command'; import { MigrateAttachmentAuthorToCreatedByCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-attachment-author-to-created-by.command'; import { MigrateAttachmentTypeToFileCategoryCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-attachment-type-to-file-category.command'; import { MigrateChannelPartialFullSyncStagesCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-channel-partial-full-sync-stages.command'; @@ -61,6 +62,7 @@ export class UpgradeCommand extends UpgradeCommandRunner { protected readonly addWorkflowRunStopStatusesCommand: AddWorkflowRunStopStatusesCommand, protected readonly cleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand: CleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand, protected readonly migrateChannelPartialFullSyncStagesCommand: MigrateChannelPartialFullSyncStagesCommand, + protected readonly createViewKanbanFieldMetadataIdForeignKeyMigrationCommand: CreateViewKanbanFieldMetadataIdForeignKeyMigrationCommand, ) { super( workspaceRepository, @@ -97,6 +99,7 @@ export class UpgradeCommand extends UpgradeCommandRunner { this.regenerateSearchVectorsCommand, this.addWorkflowRunStopStatusesCommand, this.cleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand, + this.createViewKanbanFieldMetadataIdForeignKeyMigrationCommand, this.migrateChannelPartialFullSyncStagesCommand, ], afterSyncMetadata: [ diff --git a/packages/twenty-server/src/database/typeorm/core/migrations/common/1760965667836-kanbanFieldMetadataIdentifierView.ts b/packages/twenty-server/src/database/typeorm/core/migrations/common/1760965667836-kanbanFieldMetadataIdentifierView.ts index c13d555a48..acafd11154 100644 --- a/packages/twenty-server/src/database/typeorm/core/migrations/common/1760965667836-kanbanFieldMetadataIdentifierView.ts +++ b/packages/twenty-server/src/database/typeorm/core/migrations/common/1760965667836-kanbanFieldMetadataIdentifierView.ts @@ -6,9 +6,18 @@ export class KanbanFieldMetadataIdentifierView1760965667836 name = 'KanbanFieldMetadataIdentifierView1760965667836'; public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "core"."view" ADD CONSTRAINT "FK_b3cc95732479f7a1337350c398f" FOREIGN KEY ("kanbanAggregateOperationFieldMetadataId") REFERENCES "core"."fieldMetadata"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, - ); + // Swallowing any exceptions here + // 1-10-clean-orphaned-kanban-aggregate-operation-field-metadata-id.command.ts upgrade command handles fallback for existing workspaces + try { + await queryRunner.query( + `ALTER TABLE "core"."view" ADD CONSTRAINT "FK_b3cc95732479f7a1337350c398f" FOREIGN KEY ("kanbanAggregateOperationFieldMetadataId") REFERENCES "core"."fieldMetadata"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + } catch (error) { + // eslint-disable-next-line no-console + console.error( + `Swallowing KanbanFieldMetadataIdentifierView1760965667836 error: ${error.message}. Upgrade:1-10:clean-orphaned-kanban-aggregate-operation-field-metadata-id upgrade command will handle fallback`, + ); + } } public async down(queryRunner: QueryRunner): Promise {