Remove dead code to backfill record positions (#11439)
Fixes https://github.com/twentyhq/core-team-issues/issues/767
This commit is contained in:
@ -1,142 +0,0 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
|
||||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
|
||||||
|
|
||||||
import { FieldMetadataType } from 'twenty-shared/types';
|
|
||||||
|
|
||||||
import { RecordPositionBackfillService } from 'src/engine/api/graphql/workspace-query-runner/services/record-position-backfill-service';
|
|
||||||
import { RecordPositionService } from 'src/engine/core-modules/record-position/services/record-position.service';
|
|
||||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
|
||||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
|
||||||
|
|
||||||
describe('RecordPositionBackfillService', () => {
|
|
||||||
let recordPositionService;
|
|
||||||
let objectMetadataRepository;
|
|
||||||
let workspaceDataSourceService;
|
|
||||||
|
|
||||||
let service: RecordPositionBackfillService;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
recordPositionService = {
|
|
||||||
buildRecordPosition: jest.fn().mockResolvedValue([
|
|
||||||
{
|
|
||||||
position: 1,
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
};
|
|
||||||
|
|
||||||
objectMetadataRepository = {
|
|
||||||
find: jest.fn().mockReturnValue([]),
|
|
||||||
};
|
|
||||||
|
|
||||||
workspaceDataSourceService = {
|
|
||||||
getSchemaName: jest.fn().mockReturnValue('schemaName'),
|
|
||||||
executeRawQuery: jest.fn().mockResolvedValue([]),
|
|
||||||
};
|
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
|
||||||
providers: [
|
|
||||||
RecordPositionBackfillService,
|
|
||||||
{
|
|
||||||
provide: RecordPositionService,
|
|
||||||
useValue: recordPositionService,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: WorkspaceDataSourceService,
|
|
||||||
useValue: workspaceDataSourceService,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: getRepositoryToken(ObjectMetadataEntity, 'metadata'),
|
|
||||||
useValue: objectMetadataRepository,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}).compile();
|
|
||||||
|
|
||||||
service = module.get<RecordPositionBackfillService>(
|
|
||||||
RecordPositionBackfillService,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be defined', () => {
|
|
||||||
expect(service).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('when no object metadata found, should do nothing', async () => {
|
|
||||||
await service.backfill('workspaceId', false);
|
|
||||||
expect(workspaceDataSourceService.executeRawQuery).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('when objectMetadata without position, should do nothing', async () => {
|
|
||||||
objectMetadataRepository.find.mockReturnValue([]);
|
|
||||||
await service.backfill('workspaceId', false);
|
|
||||||
expect(workspaceDataSourceService.executeRawQuery).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('when objectMetadata but all record with position, should create and run query once', async () => {
|
|
||||||
objectMetadataRepository.find.mockReturnValue([
|
|
||||||
{
|
|
||||||
id: '1',
|
|
||||||
nameSingular: 'company',
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
type: FieldMetadataType.POSITION,
|
|
||||||
isCustom: true,
|
|
||||||
nameSingular: 'position',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
await service.backfill('workspaceId', false);
|
|
||||||
expect(workspaceDataSourceService.executeRawQuery).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('when record without position, should create and run query twice', async () => {
|
|
||||||
objectMetadataRepository.find.mockReturnValue([
|
|
||||||
{
|
|
||||||
id: '1',
|
|
||||||
nameSingular: 'company',
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
type: FieldMetadataType.POSITION,
|
|
||||||
isCustom: true,
|
|
||||||
nameSingular: 'position',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
workspaceDataSourceService.executeRawQuery.mockResolvedValueOnce([
|
|
||||||
{
|
|
||||||
id: '1',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
await service.backfill('workspaceId', false);
|
|
||||||
expect(workspaceDataSourceService.executeRawQuery).toHaveBeenCalledTimes(2);
|
|
||||||
expect(recordPositionService.buildRecordPosition).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('when dryRun is true, should not update position', async () => {
|
|
||||||
objectMetadataRepository.find.mockReturnValue([
|
|
||||||
{
|
|
||||||
id: '1',
|
|
||||||
nameSingular: 'company',
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
type: FieldMetadataType.POSITION,
|
|
||||||
isCustom: true,
|
|
||||||
nameSingular: 'position',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
workspaceDataSourceService.executeRawQuery.mockResolvedValueOnce([
|
|
||||||
{
|
|
||||||
id: '1',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
await service.backfill('workspaceId', true);
|
|
||||||
expect(workspaceDataSourceService.executeRawQuery).toHaveBeenCalledTimes(1);
|
|
||||||
expect(recordPositionService.buildRecordPosition).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
import { Module } from '@nestjs/common';
|
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
||||||
|
|
||||||
import { RecordPositionBackfillService } from 'src/engine/api/graphql/workspace-query-runner/services/record-position-backfill-service';
|
|
||||||
import { RecordPositionService } from 'src/engine/core-modules/record-position/services/record-position.service';
|
|
||||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
|
||||||
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
|
||||||
|
|
||||||
@Module({
|
|
||||||
imports: [
|
|
||||||
WorkspaceDataSourceModule,
|
|
||||||
TypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'),
|
|
||||||
],
|
|
||||||
providers: [RecordPositionService, RecordPositionBackfillService],
|
|
||||||
exports: [RecordPositionBackfillService],
|
|
||||||
})
|
|
||||||
export class RecordPositionBackfillModule {}
|
|
||||||
@ -1,124 +0,0 @@
|
|||||||
import { Injectable, Logger } from '@nestjs/common';
|
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
|
||||||
|
|
||||||
import { isDefined } from 'class-validator';
|
|
||||||
import { FieldMetadataType } from 'twenty-shared/types';
|
|
||||||
import { Repository } from 'typeorm';
|
|
||||||
|
|
||||||
import { RecordPositionService } from 'src/engine/core-modules/record-position/services/record-position.service';
|
|
||||||
import { RecordPositionQueryType } from 'src/engine/core-modules/record-position/types/record-position-query.type';
|
|
||||||
import { buildRecordPositionQuery } from 'src/engine/core-modules/record-position/utils/build-record-position-query.util';
|
|
||||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
|
||||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class RecordPositionBackfillService {
|
|
||||||
private readonly logger = new Logger(RecordPositionBackfillService.name);
|
|
||||||
constructor(
|
|
||||||
@InjectRepository(ObjectMetadataEntity, 'metadata')
|
|
||||||
private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
|
|
||||||
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
|
|
||||||
private readonly recordPositionService: RecordPositionService,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async backfill(workspaceId: string, dryRun: boolean) {
|
|
||||||
this.logger.log(
|
|
||||||
`Starting backfilling record positions for workspace ${workspaceId}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const dataSourceSchema =
|
|
||||||
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
|
||||||
|
|
||||||
const objectMetadataCollection = await this.objectMetadataRepository.find({
|
|
||||||
where: {
|
|
||||||
workspaceId,
|
|
||||||
fields: {
|
|
||||||
name: 'position',
|
|
||||||
type: FieldMetadataType.POSITION,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
relations: {
|
|
||||||
fields: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const objectMetadata of objectMetadataCollection) {
|
|
||||||
const [recordsWithoutPositionQuery, recordsWithoutPositionQueryParams] =
|
|
||||||
buildRecordPositionQuery(
|
|
||||||
{
|
|
||||||
recordPositionQueryType: RecordPositionQueryType.FIND_BY_POSITION,
|
|
||||||
positionValue: null,
|
|
||||||
},
|
|
||||||
objectMetadata,
|
|
||||||
dataSourceSchema,
|
|
||||||
);
|
|
||||||
|
|
||||||
const recordsWithoutPosition =
|
|
||||||
await this.workspaceDataSourceService.executeRawQuery(
|
|
||||||
recordsWithoutPositionQuery,
|
|
||||||
recordsWithoutPositionQueryParams,
|
|
||||||
workspaceId,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
|
||||||
!isDefined(recordsWithoutPosition) ||
|
|
||||||
recordsWithoutPosition?.length === 0
|
|
||||||
) {
|
|
||||||
this.logger.log(
|
|
||||||
`No records without position for ${objectMetadata.nameSingular}`,
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const position = await this.recordPositionService.buildRecordPosition({
|
|
||||||
objectMetadata: {
|
|
||||||
isCustom: objectMetadata.isCustom,
|
|
||||||
nameSingular: objectMetadata.nameSingular,
|
|
||||||
},
|
|
||||||
value: 'last',
|
|
||||||
workspaceId,
|
|
||||||
});
|
|
||||||
|
|
||||||
for (
|
|
||||||
let recordIndex = 0;
|
|
||||||
recordIndex < recordsWithoutPosition.length;
|
|
||||||
recordIndex++
|
|
||||||
) {
|
|
||||||
const recordId = recordsWithoutPosition[recordIndex].id;
|
|
||||||
|
|
||||||
if (!recordId) {
|
|
||||||
this.logger.log(
|
|
||||||
`Fetched record without id for ${objectMetadata.nameSingular}`,
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const backfilledPosition = position + recordIndex;
|
|
||||||
|
|
||||||
this.logger.log(
|
|
||||||
`Backfilling position ${backfilledPosition} for ${objectMetadata.nameSingular} ${recordId}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (dryRun) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const [query, params] = buildRecordPositionQuery(
|
|
||||||
{
|
|
||||||
recordPositionQueryType: RecordPositionQueryType.UPDATE_POSITION,
|
|
||||||
recordId: recordsWithoutPosition[recordIndex].id,
|
|
||||||
positionValue: position + recordIndex,
|
|
||||||
},
|
|
||||||
objectMetadata,
|
|
||||||
dataSourceSchema,
|
|
||||||
);
|
|
||||||
|
|
||||||
await this.workspaceDataSourceService.executeRawQuery(
|
|
||||||
query,
|
|
||||||
params,
|
|
||||||
workspaceId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user