CleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand (#15344)
## Context We want to introduce a FK between view and fieldMetadata through KanbanAggregateOperationFieldMetadataId so we need to clean up orphan ones
This commit is contained in:
+114
@@ -0,0 +1,114 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Command } from 'nest-commander';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { In, IsNull, Not, 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 { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
import { ViewType } from 'src/engine/metadata-modules/view/enums/view-type.enum';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
|
||||
@Command({
|
||||
name: 'upgrade:1-10:clean-orphaned-kanban-aggregate-operation-field-metadata-id',
|
||||
description:
|
||||
"Delete all kanbanAggregateOperationFieldMetadataId in views that don't map to a real fieldMetadata (this is because we want to introduce a FK later)",
|
||||
})
|
||||
export class CleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner {
|
||||
constructor(
|
||||
@InjectRepository(WorkspaceEntity)
|
||||
protected readonly workspaceRepository: Repository<WorkspaceEntity>,
|
||||
protected readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||
@InjectRepository(ViewEntity)
|
||||
private readonly viewRepository: Repository<ViewEntity>,
|
||||
@InjectRepository(FieldMetadataEntity)
|
||||
private readonly fieldMetadataRepository: Repository<FieldMetadataEntity>,
|
||||
) {
|
||||
super(workspaceRepository, twentyORMGlobalManager);
|
||||
}
|
||||
|
||||
override async runOnWorkspace({
|
||||
workspaceId,
|
||||
index,
|
||||
total,
|
||||
options,
|
||||
}: RunOnWorkspaceArgs): Promise<void> {
|
||||
this.logger.log(
|
||||
`[${index + 1}/${total}] Cleaning orphaned kanbanAggregateOperationFieldMetadataId for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
const existingFieldMetadataIds = await this.fieldMetadataRepository.find({
|
||||
where: { workspaceId },
|
||||
select: ['id'],
|
||||
});
|
||||
|
||||
const existingFieldMetadataIdSet = new Set(
|
||||
existingFieldMetadataIds.map((fm) => fm.id),
|
||||
);
|
||||
|
||||
const viewsWithOrphanedFieldMetadata = await this.viewRepository.find({
|
||||
where: {
|
||||
workspaceId,
|
||||
kanbanAggregateOperationFieldMetadataId: Not(IsNull()),
|
||||
},
|
||||
select: ['id', 'kanbanAggregateOperationFieldMetadataId', 'type'],
|
||||
});
|
||||
|
||||
const orphanedViews = viewsWithOrphanedFieldMetadata.filter(
|
||||
(view) =>
|
||||
isDefined(view.kanbanAggregateOperationFieldMetadataId) &&
|
||||
!existingFieldMetadataIdSet.has(
|
||||
view.kanbanAggregateOperationFieldMetadataId,
|
||||
),
|
||||
);
|
||||
|
||||
if (orphanedViews.length === 0) {
|
||||
this.logger.log(
|
||||
'No orphaned kanbanAggregateOperationFieldMetadataId references found',
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const kanbanViewsToDelete = orphanedViews.filter(
|
||||
(view) => view.type === ViewType.KANBAN,
|
||||
);
|
||||
const otherViewsToUpdate = orphanedViews.filter(
|
||||
(view) => view.type !== ViewType.KANBAN,
|
||||
);
|
||||
|
||||
let deletedCount = 0;
|
||||
let updatedCount = 0;
|
||||
|
||||
if (!options.dryRun) {
|
||||
if (kanbanViewsToDelete.length > 0) {
|
||||
const kanbanViewIds = kanbanViewsToDelete.map((view) => view.id);
|
||||
|
||||
await this.viewRepository.delete({ id: In(kanbanViewIds) });
|
||||
deletedCount = kanbanViewsToDelete.length;
|
||||
}
|
||||
|
||||
if (otherViewsToUpdate.length > 0) {
|
||||
const otherViewIds = otherViewsToUpdate.map((view) => view.id);
|
||||
|
||||
await this.viewRepository.update(
|
||||
{ id: In(otherViewIds) },
|
||||
{ kanbanAggregateOperationFieldMetadataId: null },
|
||||
);
|
||||
updatedCount = otherViewsToUpdate.length;
|
||||
}
|
||||
} else {
|
||||
deletedCount = kanbanViewsToDelete.length;
|
||||
updatedCount = otherViewsToUpdate.length;
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`${options.dryRun ? 'DRY RUN - Would have' : ''}Deleted ${deletedCount} KANBAN views and updated ${updatedCount} other views with orphaned kanbanAggregateOperationFieldMetadataId references`,
|
||||
);
|
||||
}
|
||||
}
|
||||
+5
@@ -2,6 +2,7 @@ import { Module } from '@nestjs/common';
|
||||
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 { 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 { RegenerateSearchVectorsCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-regenerate-search-vectors.command';
|
||||
@@ -9,6 +10,7 @@ import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.ent
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
import { WorkspaceSchemaManagerModule } from 'src/engine/twenty-orm/workspace-schema-manager/workspace-schema-manager.module';
|
||||
|
||||
@Module({
|
||||
@@ -18,6 +20,7 @@ import { WorkspaceSchemaManagerModule } from 'src/engine/twenty-orm/workspace-sc
|
||||
ObjectMetadataEntity,
|
||||
FieldMetadataEntity,
|
||||
IndexMetadataEntity,
|
||||
ViewEntity,
|
||||
]),
|
||||
WorkspaceSchemaManagerModule,
|
||||
],
|
||||
@@ -26,12 +29,14 @@ import { WorkspaceSchemaManagerModule } from 'src/engine/twenty-orm/workspace-sc
|
||||
MigrateAttachmentTypeToFileCategoryCommand,
|
||||
RegenerateSearchVectorsCommand,
|
||||
AddWorkflowRunStopStatusesCommand,
|
||||
CleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand,
|
||||
],
|
||||
exports: [
|
||||
MigrateAttachmentAuthorToCreatedByCommand,
|
||||
MigrateAttachmentTypeToFileCategoryCommand,
|
||||
RegenerateSearchVectorsCommand,
|
||||
AddWorkflowRunStopStatusesCommand,
|
||||
CleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand,
|
||||
],
|
||||
})
|
||||
export class V1_10_UpgradeVersionCommandModule {}
|
||||
|
||||
+3
@@ -20,6 +20,7 @@ import { FixSchemaArrayTypeCommand } from 'src/database/commands/upgrade-version
|
||||
import { FixUpdateStandardFieldsIsLabelSyncedWithName } from 'src/database/commands/upgrade-version-command/1-1/1-1-fix-update-standard-field-is-label-synced-with-name.command';
|
||||
import { MigrateWorkflowRunStatesCommand } from 'src/database/commands/upgrade-version-command/1-1/1-1-migrate-workflow-run-state.command';
|
||||
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 { 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 { RegenerateSearchVectorsCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-regenerate-search-vectors.command';
|
||||
@@ -105,6 +106,7 @@ export class UpgradeCommand extends UpgradeCommandRunner {
|
||||
protected readonly migrateAttachmentTypeToFileCategoryCommand: MigrateAttachmentTypeToFileCategoryCommand,
|
||||
protected readonly regenerateSearchVectorsCommand: RegenerateSearchVectorsCommand,
|
||||
protected readonly addWorkflowRunStopStatusesCommand: AddWorkflowRunStopStatusesCommand,
|
||||
protected readonly cleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand: CleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand,
|
||||
) {
|
||||
super(
|
||||
workspaceRepository,
|
||||
@@ -213,6 +215,7 @@ export class UpgradeCommand extends UpgradeCommandRunner {
|
||||
beforeSyncMetadata: [
|
||||
this.regenerateSearchVectorsCommand,
|
||||
this.addWorkflowRunStopStatusesCommand,
|
||||
this.cleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand,
|
||||
],
|
||||
afterSyncMetadata: [
|
||||
this.migrateAttachmentAuthorToCreatedByCommand,
|
||||
|
||||
Reference in New Issue
Block a user