diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/convert-record-positions-to-integers.command.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/convert-record-positions-to-integers.command.ts new file mode 100644 index 000000000..0c5e0b9a5 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/convert-record-positions-to-integers.command.ts @@ -0,0 +1,128 @@ +import { Logger } from '@nestjs/common'; +import { InjectDataSource } from '@nestjs/typeorm'; + +import { Command, CommandRunner, Option } from 'nest-commander'; +import { DataSource } from 'typeorm'; + +import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; + +interface RunCommandOptions { + workspaceId?: string; +} + +@Command({ + name: 'workspace:convert-record-positions-to-integers', + description: 'Convert record positions to integers', +}) +export class ConvertRecordPositionsToIntegers extends CommandRunner { + private readonly logger = new Logger(ConvertRecordPositionsToIntegers.name); + + constructor( + @InjectDataSource('metadata') + private readonly metadataDataSource: DataSource, + private readonly workspaceDataSourceService: WorkspaceDataSourceService, + ) { + super(); + } + + async run(_passedParam: string[], options: RunCommandOptions): Promise { + const queryRunner = this.metadataDataSource.createQueryRunner(); + const workspaceId = options.workspaceId; + + if (!workspaceId || typeof workspaceId !== 'string') { + this.logger.error('Workspace id is required'); + + return; + } + + const customObjectMetadataCollection = await this.metadataDataSource + .getRepository(ObjectMetadataEntity) + .findBy({ + workspaceId, + isCustom: true, + }); + + const customObjectTableNames = customObjectMetadataCollection.map( + (metadata) => metadata.nameSingular, + ); + + await queryRunner.connect(); + await queryRunner.startTransaction(); + + const transactionManager = queryRunner.manager; + + this.logger.log('Converting record positions to integers'); + + try { + await this.convertRecordPositionsToIntegers( + customObjectTableNames, + workspaceId, + transactionManager, + ); + + await queryRunner.commitTransaction(); + } catch (error) { + await queryRunner.rollbackTransaction(); + this.logger.error('Error converting record positions to integers', error); + } finally { + await queryRunner.release(); + this.logger.log('Record positions converted to integers'); + } + } + + private async convertRecordPositionsToIntegers( + customObjectTableNames: string[], + workspaceId: string, + transactionManager: any, + ): Promise { + const dataSourceSchema = + this.workspaceDataSourceService.getSchemaName(workspaceId); + + for (const tableName of ['company', 'person', 'opportunity']) { + await this.convertRecordPositionsToIntegersForTable( + tableName, + dataSourceSchema, + workspaceId, + transactionManager, + ); + } + + for (const tableName of customObjectTableNames) { + await this.convertRecordPositionsToIntegersForTable( + `_${tableName}`, + dataSourceSchema, + workspaceId, + transactionManager, + ); + } + } + + private async convertRecordPositionsToIntegersForTable( + tableName: string, + dataSourceSchema: string, + workspaceId: string, + transactionManager: any, + ): Promise { + await this.workspaceDataSourceService.executeRawQuery( + `UPDATE ${dataSourceSchema}.${tableName} SET position = subquery.position + FROM ( + SELECT id, ROW_NUMBER() OVER (ORDER BY position) as position + FROM ${dataSourceSchema}.${tableName} + ) as subquery + WHERE ${dataSourceSchema}.${tableName}.id = subquery.id`, + [], + workspaceId, + transactionManager, + ); + } + + @Option({ + flags: '-w, --workspace-id [workspace_id]', + description: 'workspace id', + required: true, + }) + parseWorkspaceId(value: string): string { + return value; + } +} diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/workspace-sync-metadata-commands.module.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/workspace-sync-metadata-commands.module.ts index c9fc90423..8e30f0c41 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/workspace-sync-metadata-commands.module.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/commands/workspace-sync-metadata-commands.module.ts @@ -5,6 +5,8 @@ import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/worksp import { WorkspaceHealthModule } from 'src/engine/workspace-manager/workspace-health/workspace-health.module'; import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module'; import { AddStandardIdCommand } from 'src/engine/workspace-manager/workspace-sync-metadata/commands/add-standard-id.command'; +import { ConvertRecordPositionsToIntegers } from 'src/engine/workspace-manager/workspace-sync-metadata/commands/convert-record-positions-to-integers.command'; +import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; import { SyncWorkspaceMetadataCommand } from './sync-workspace-metadata.command'; @@ -16,10 +18,12 @@ import { SyncWorkspaceLoggerService } from './services/sync-workspace-logger.ser WorkspaceHealthModule, WorkspaceModule, DataSourceModule, + WorkspaceDataSourceModule, ], providers: [ SyncWorkspaceMetadataCommand, AddStandardIdCommand, + ConvertRecordPositionsToIntegers, SyncWorkspaceLoggerService, ], })