Skip to content

Commit

Permalink
Create convert record positions to integers command (twentyhq#5287)
Browse files Browse the repository at this point in the history
## Context
Positions are used within a view to display and sort the different
records of standard/custom object.
When we add a new record and want to put it before the existing first
record, we have to use float values to insert them in the DB and respect
the desired order. We are adding a new command that can be executed to
flatten those positions.

---------

Co-authored-by: bosiraphael <[email protected]>
  • Loading branch information
2 people authored and i-am-chitti committed May 4, 2024
1 parent 0b690a0 commit 71c73a5
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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<void> {
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<void> {
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<void> {
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -16,10 +18,12 @@ import { SyncWorkspaceLoggerService } from './services/sync-workspace-logger.ser
WorkspaceHealthModule,
WorkspaceModule,
DataSourceModule,
WorkspaceDataSourceModule,
],
providers: [
SyncWorkspaceMetadataCommand,
AddStandardIdCommand,
ConvertRecordPositionsToIntegers,
SyncWorkspaceLoggerService,
],
})
Expand Down

0 comments on commit 71c73a5

Please sign in to comment.