diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-migrate-workflow-step-filter-operand-value.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-migrate-workflow-step-filter-operand-value.ts new file mode 100644 index 0000000000..874a444c30 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-migrate-workflow-step-filter-operand-value.ts @@ -0,0 +1,210 @@ +import { InjectRepository } from '@nestjs/typeorm'; + +import { isString } from 'class-validator'; +import { Command } from 'nest-commander'; +import { + convertViewFilterOperandToCoreOperand, + isDefined, +} from 'twenty-shared/utils'; +import { In, Raw, Repository } from 'typeorm'; + +import { + ActiveOrSuspendedWorkspacesMigrationCommandRunner, + type 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'; +import { + WorkflowRunState, + WorkflowRunWorkspaceEntity, +} from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity'; +import { WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; +import { isWorkflowFilterAction } from 'src/modules/workflow/workflow-executor/workflow-actions/filter/guards/is-workflow-filter-action.guard'; +import { isWorkflowFindRecordsAction } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/guards/is-workflow-find-records-action.guard'; +import { type WorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type'; +@Command({ + name: 'upgrade:1-10:migrate-workflow-step-filter-operand-value', + description: + 'Migrate workflowVersion.steps[].settings.input.stepFilters[].operand to use new operand enum', +}) +export class MigrateWorkflowStepFilterOperandValueCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { + constructor( + @InjectRepository(Workspace) + protected readonly workspaceRepository: Repository, + protected readonly twentyORMGlobalManager: TwentyORMGlobalManager, + ) { + super(workspaceRepository, twentyORMGlobalManager); + } + + override async runOnWorkspace({ + workspaceId, + index, + total, + options, + }: RunOnWorkspaceArgs): Promise { + this.logger.log( + `[${index + 1}/${total}] Migrating workflow step filter operand values for workspace ${workspaceId}`, + ); + + // workflowVersions + const workflowVersionRepository = + await this.twentyORMGlobalManager.getRepositoryForWorkspace( + workspaceId, + 'workflowVersion', + { shouldBypassPermissionChecks: true }, + ); + + const workflowVersionsToMigrate = await workflowVersionRepository.find({ + where: [ + { + steps: Raw( + (_alias) => `"workflowVersion"."steps"::text LIKE :search`, + { + search: '%operand%', + }, + ), + }, + ], + }); + + this.logger.log( + `Found ${workflowVersionsToMigrate.length} workflowVersions to migrate`, + ); + + for (const workflowVersion of workflowVersionsToMigrate) { + let steps: WorkflowAction[] | null | undefined; + + steps = workflowVersion.steps; + + let hasChanged = false; + + for (const step of steps ?? []) { + if (isWorkflowFilterAction(step)) { + for (const filter of step.settings.input.stepFilters ?? []) { + if (isDefined(filter.operand) && isString(filter.operand)) { + const newOperand = convertViewFilterOperandToCoreOperand( + filter.operand, + ); + + if (newOperand && newOperand !== filter.operand) { + filter.operand = newOperand; + hasChanged = true; + } + } + } + } + if (isWorkflowFindRecordsAction(step)) { + for (const filter of step.settings.input.filter?.recordFilters ?? + []) { + if (isString(filter.operand)) { + const newOperand = convertViewFilterOperandToCoreOperand( + filter.operand, + ); + + if (newOperand && newOperand !== filter.operand) { + filter.operand = newOperand; + hasChanged = true; + } + } + } + } + } + + if (hasChanged) { + this.logger.log( + `${options.dryRun ? 'DRY RUN - Would be' : ''}Updating workflowVersion ${workflowVersion.id} in workspace ${workspaceId}`, + ); + + if (!options.dryRun) { + await workflowVersionRepository.update( + { id: workflowVersion.id }, + { steps }, + ); + } + + this.logger.log( + `${options.dryRun ? 'DRY RUN - Would have' : ''} Updated workflowVersion ${workflowVersion.id} in workspace ${workspaceId}`, + ); + } + } + + //workflowRuns + const workflowRunRepository = + await this.twentyORMGlobalManager.getRepositoryForWorkspace( + workspaceId, + 'workflowRun', + { shouldBypassPermissionChecks: true }, + ); + + const workflowRunsToMigrate = await workflowRunRepository.find({ + where: { + workflowVersionId: In( + workflowVersionsToMigrate.map( + (workflowVersion) => workflowVersion.id, + ), + ), + }, + }); + + this.logger.log( + `Found ${workflowRunsToMigrate.length} workflowRuns to migrate`, + ); + + for (const workflowRun of workflowRunsToMigrate) { + let state: WorkflowRunState | null | undefined = workflowRun.state; + + if (!isDefined(state)) { + continue; + } + + let hasChanged = false; + + for (const step of state.flow.steps) { + if (isWorkflowFindRecordsAction(step)) { + const filter = step.settings.input.filter; + + for (const recordFilter of filter?.recordFilters ?? []) { + if (isString(recordFilter.operand)) { + const newOperand = convertViewFilterOperandToCoreOperand( + recordFilter.operand, + ); + + if (newOperand && newOperand !== recordFilter.operand) { + recordFilter.operand = newOperand; + hasChanged = true; + } + } + } + } + if (isWorkflowFilterAction(step)) { + for (const filter of step.settings.input.stepFilters ?? []) { + if (isString(filter.operand)) { + const newOperand = convertViewFilterOperandToCoreOperand( + filter.operand, + ); + + if (newOperand && newOperand !== filter.operand) { + filter.operand = newOperand; + hasChanged = true; + } + } + } + } + } + + if (hasChanged) { + this.logger.log( + `${options.dryRun ? 'DRY RUN - Would be' : ''}Updating workflowRun ${workflowRun.id} in workspace ${workspaceId}`, + ); + + if (!options.dryRun) { + await workflowRunRepository.update({ id: workflowRun.id }, { state }); + } + + this.logger.log( + `${options.dryRun ? 'DRY RUN - Would have' : ''}Updated workflowRun ${workflowRun.id} in workspace ${workspaceId}`, + ); + } + } + } +} 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 new file mode 100644 index 0000000000..7b1f525163 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-upgrade-version-command.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { MigrateWorkflowStepFilterOperandValueCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-workflow-step-filter-operand-value'; +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; +import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; + +@Module({ + imports: [TypeOrmModule.forFeature([Workspace]), WorkspaceDataSourceModule], + providers: [MigrateWorkflowStepFilterOperandValueCommand], + exports: [MigrateWorkflowStepFilterOperandValueCommand], +}) +export class V1_10_UpgradeVersionCommandModule {} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade-version-command.module.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade-version-command.module.ts index 4ab8f43180..47445b7df3 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade-version-command.module.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade-version-command.module.ts @@ -4,6 +4,7 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { V0_54_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/0-54/0-54-upgrade-version-command.module'; import { V0_55_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/0-55/0-55-upgrade-version-command.module'; import { V1_1_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-1/1-1-upgrade-version-command.module'; +import { V1_10_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-10/1-10-upgrade-version-command.module'; import { V1_2_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-2/1-2-upgrade-version-command.module'; import { V1_3_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-3/1-3-upgrade-version-command.module'; import { V1_5_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-5/1-5-upgrade-version-command.module'; @@ -24,6 +25,7 @@ import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/worksp V1_5_UpgradeVersionCommandModule, V1_6_UpgradeVersionCommandModule, V1_7_UpgradeVersionCommandModule, + V1_10_UpgradeVersionCommandModule, WorkspaceSyncMetadataModule, ], providers: [UpgradeCommand], 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 3d13e1ac61..9d952e0524 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 { AddEnqueuedStatusToWorkflowRunCommand } from 'src/database/commands/upg import { FixSchemaArrayTypeCommand } from 'src/database/commands/upgrade-version-command/1-1/1-1-fix-schema-array-type.command'; 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 { MigrateWorkflowStepFilterOperandValueCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-workflow-step-filter-operand-value'; import { AddEnqueuedStatusToWorkflowRunV2Command } from 'src/database/commands/upgrade-version-command/1-2/1-2-add-enqueued-status-to-workflow-run-v2.command'; import { AddNextStepIdsToWorkflowVersionTriggers } from 'src/database/commands/upgrade-version-command/1-2/1-2-add-next-step-ids-to-workflow-version-triggers.command'; import { RemoveWorkflowRunsWithoutState } from 'src/database/commands/upgrade-version-command/1-2/1-2-remove-workflow-runs-without-state.command'; @@ -83,6 +84,9 @@ export class UpgradeCommand extends UpgradeCommandRunner { // 1.7 Commands protected readonly backfillWorkflowManualTriggerAvailabilityCommand: BackfillWorkflowManualTriggerAvailabilityCommand, + + // 1.10 Commands + protected readonly migrateWorkflowStepFilterOperandValueCommand: MigrateWorkflowStepFilterOperandValueCommand, ) { super( workspaceRepository, @@ -176,6 +180,11 @@ export class UpgradeCommand extends UpgradeCommandRunner { afterSyncMetadata: [], }; + const commands_1100: VersionCommands = { + beforeSyncMetadata: [this.migrateWorkflowStepFilterOperandValueCommand], + afterSyncMetadata: [], + }; + this.allCommands = { '0.53.0': commands_053, '0.54.0': commands_054, @@ -189,6 +198,7 @@ export class UpgradeCommand extends UpgradeCommandRunner { '1.5.0': commands_150, '1.6.0': commands_160, '1.7.0': commands_170, + '1.10.0': commands_1100, }; } diff --git a/packages/twenty-shared/src/types/ViewFilterOperandDeprecated.ts b/packages/twenty-shared/src/types/ViewFilterOperandDeprecated.ts index 813f41acac..dea35cfa8f 100644 --- a/packages/twenty-shared/src/types/ViewFilterOperandDeprecated.ts +++ b/packages/twenty-shared/src/types/ViewFilterOperandDeprecated.ts @@ -14,5 +14,5 @@ export enum ViewFilterOperandDeprecated { IsInPast = 'isInPast', IsInFuture = 'isInFuture', IsToday = 'isToday', - VectorSearch = 'vectorSearch', + VectorSearch = 'search', }