diff --git a/packages/twenty-server/src/database/commands/upgrade-version/0-40/0-40-add-context-to-actor-composite-type.ts b/packages/twenty-server/src/database/commands/upgrade-version/0-40/0-40-add-context-to-actor-composite-type.ts new file mode 100644 index 00000000000..e32df3978f0 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version/0-40/0-40-add-context-to-actor-composite-type.ts @@ -0,0 +1,157 @@ +import { InjectRepository } from '@nestjs/typeorm'; + +import chalk from 'chalk'; +import { Command } from 'nest-commander'; +import { FieldMetadataType } from 'twenty-shared'; +import { Repository, TableColumn } from 'typeorm'; + +import { + ActiveWorkspacesCommandOptions, + ActiveWorkspacesCommandRunner, +} from 'src/database/commands/active-workspaces.command'; +import { CommandLogger } from 'src/database/commands/logger'; +import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; +import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { WorkspaceMetadataVersionService } from 'src/engine/metadata-modules/workspace-metadata-version/services/workspace-metadata-version.service'; +import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; +import { computeTableName } from 'src/engine/utils/compute-table-name.util'; +import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; + +@Command({ + name: 'upgrade-0.40:add-context-to-actor-composite-type', + description: 'Add context to actor composite type.', +}) +export class AddContextToActorCompositeTypeCommand extends ActiveWorkspacesCommandRunner { + protected readonly logger; + + constructor( + @InjectRepository(Workspace, 'core') + protected readonly workspaceRepository: Repository, + private readonly twentyORMGlobalManager: TwentyORMGlobalManager, + @InjectRepository(FieldMetadataEntity, 'metadata') + private readonly fieldMetadataRepository: Repository, + private readonly workspaceDataSourceService: WorkspaceDataSourceService, + private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService, + ) { + super(workspaceRepository); + this.logger = new CommandLogger({ + constructorName: this.constructor.name, + verbose: false, + }); + this.logger.setVerbose(false); + } + + async executeActiveWorkspacesCommand( + _passedParam: string[], + options: ActiveWorkspacesCommandOptions, + workspaceIds: string[], + ): Promise { + this.logger.log(`Running add-context-to-actor-composite-type command`); + + if (options?.dryRun) { + this.logger.log(chalk.yellow('Dry run mode: No changes will be applied')); + } + + for (const workspaceId of workspaceIds) { + try { + await this.execute(workspaceId, options?.dryRun); + this.logger.verbose(`Added for workspace: ${workspaceId}`); + } catch (error) { + this.logger.error(`Error for workspace: ${workspaceId}`, error); + } + } + } + + private async execute(workspaceId: string, dryRun = false): Promise { + this.logger.verbose(`Adding for workspace: ${workspaceId}`); + const actorFields = await this.fieldMetadataRepository.find({ + where: { + type: FieldMetadataType.ACTOR, + workspaceId, + }, + relations: ['object'], + }); + + // Filter and update fields with EMAIL or CALENDAR source + for (const field of actorFields) { + if (!field || !field.object) { + this.logger.verbose( + 'field.objectMetadata is null', + workspaceId, + field.id, + ); + continue; + } + + await this.addContextColumn( + field, + `${field.name}Context`, + workspaceId, + dryRun, + ); + } + } + + private async addContextColumn( + field: FieldMetadataEntity, + newColumnName: string, + workspaceId: string, + dryRun = false, + ): Promise { + const workspaceDataSource = + await this.workspaceDataSourceService.connectToWorkspaceDataSource( + workspaceId, + ); + + if (!workspaceDataSource) { + this.logger.verbose('No workspace data source found'); + + return; + } + + const queryRunner = workspaceDataSource?.createQueryRunner(); + + await queryRunner.connect(); + await queryRunner.startTransaction(); + + const schemaName = + this.workspaceDataSourceService.getSchemaName(workspaceId); + + try { + const hasColumn = await queryRunner.hasColumn( + `${schemaName}.${computeTableName( + field.object.nameSingular, + field?.object?.isCustom, + )}`, + newColumnName, + ); + + if (hasColumn) { + return; + } + + if (!dryRun) { + await queryRunner.addColumn( + `${schemaName}.${computeTableName( + field.object.nameSingular, + field?.object?.isCustom, + )}`, + new TableColumn({ + name: newColumnName, + type: 'jsonb', + default: `'{}'::"jsonb"`, + isNullable: true, + }), + ); + + await queryRunner.commitTransaction(); + } + } catch (error) { + await queryRunner.rollbackTransaction(); + + throw error; + } finally { + await queryRunner.release(); + } + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version/0-40/0-40-upgrade-version.command.ts b/packages/twenty-server/src/database/commands/upgrade-version/0-40/0-40-upgrade-version.command.ts index 11f965a83db..7c86ba423c2 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version/0-40/0-40-upgrade-version.command.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version/0-40/0-40-upgrade-version.command.ts @@ -5,6 +5,7 @@ import { Repository } from 'typeorm'; import { ActiveWorkspacesCommandRunner } from 'src/database/commands/active-workspaces.command'; import { BaseCommandOptions } from 'src/database/commands/base.command'; +import { AddContextToActorCompositeTypeCommand } from 'src/database/commands/upgrade-version/0-40/0-40-add-context-to-actor-composite-type'; import { MigrateAggregateOperationOptionsCommand } from 'src/database/commands/upgrade-version/0-40/0-40-migrate-aggregate-operations-options.command'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; @@ -17,6 +18,7 @@ export class UpgradeTo0_40Command extends ActiveWorkspacesCommandRunner { @InjectRepository(Workspace, 'core') protected readonly workspaceRepository: Repository, private readonly migrateAggregateOperationOptionsCommand: MigrateAggregateOperationOptionsCommand, + private readonly addContextToActorCompositeTypeCommand: AddContextToActorCompositeTypeCommand, ) { super(workspaceRepository); } @@ -33,5 +35,11 @@ export class UpgradeTo0_40Command extends ActiveWorkspacesCommandRunner { options, workspaceIds, ); + + await this.addContextToActorCompositeTypeCommand.executeActiveWorkspacesCommand( + passedParam, + options, + workspaceIds, + ); } } diff --git a/packages/twenty-server/src/database/commands/upgrade-version/0-40/0-40-upgrade-version.module.ts b/packages/twenty-server/src/database/commands/upgrade-version/0-40/0-40-upgrade-version.module.ts index c1471e69b5e..8d969161189 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version/0-40/0-40-upgrade-version.module.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version/0-40/0-40-upgrade-version.module.ts @@ -1,5 +1,6 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { AddContextToActorCompositeTypeCommand } from 'src/database/commands/upgrade-version/0-40/0-40-add-context-to-actor-composite-type'; import { MigrateAggregateOperationOptionsCommand } from 'src/database/commands/upgrade-version/0-40/0-40-migrate-aggregate-operations-options.command'; import { UpdateInactiveWorkspaceStatusCommand } from 'src/database/commands/upgrade-version/0-40/0-40-update-inactive-workspace-status.command'; @@ -17,6 +18,7 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat import { WorkspaceMetadataVersionModule } from 'src/engine/metadata-modules/workspace-metadata-version/workspace-metadata-version.module'; import { WorkspaceMigrationEntity } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity'; import { WorkspaceMigrationModule } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.module'; +import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.module'; @Module({ @@ -44,12 +46,14 @@ import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/wor WorkspaceMigrationRunnerModule, WorkspaceMigrationModule, WorkspaceMetadataVersionModule, + WorkspaceDataSourceModule, TypeORMModule, ], providers: [ UpgradeTo0_40Command, MigrateAggregateOperationOptionsCommand, UpdateInactiveWorkspaceStatusCommand, + AddContextToActorCompositeTypeCommand, ], }) export class UpgradeTo0_40CommandModule {}