diff --git a/packages/twenty-server/src/workspace/workspace-query-builder/factories/__tests__/record-position-query.factory.spec.ts b/packages/twenty-server/src/workspace/workspace-query-builder/factories/__tests__/record-position-query.factory.spec.ts index 0cb99dadc..c8484f24f 100644 --- a/packages/twenty-server/src/workspace/workspace-query-builder/factories/__tests__/record-position-query.factory.spec.ts +++ b/packages/twenty-server/src/workspace/workspace-query-builder/factories/__tests__/record-position-query.factory.spec.ts @@ -16,35 +16,73 @@ describe('RecordPositionQueryFactory', () => { }); describe('create', () => { - it('should return a string with the position when positionValue is first', async () => { - const positionValue = 'first'; + describe('createForGet', () => { + it('should return a string with the position when positionValue is first', async () => { + const positionValue = 'first'; - const result = await factory.create( - RecordPositionQueryType.GET, - positionValue, - objectMetadataItem, - dataSourceSchema, - ); + const result = await factory.create( + RecordPositionQueryType.GET, + positionValue, + objectMetadataItem, + dataSourceSchema, + ); - expect(result).toEqual( - `SELECT position FROM workspace_test."company" + expect(result).toEqual( + `SELECT position FROM workspace_test."company" WHERE "position" IS NOT NULL ORDER BY "position" ASC LIMIT 1`, - ); + ); + }); + + it('should return a string with the position when positionValue is last', async () => { + const positionValue = 'last'; + + const result = await factory.create( + RecordPositionQueryType.GET, + positionValue, + objectMetadataItem, + dataSourceSchema, + ); + + expect(result).toEqual( + `SELECT position FROM workspace_test."company" + WHERE "position" IS NOT NULL ORDER BY "position" DESC LIMIT 1`, + ); + }); }); - it('should return a string with the position when positionValue is last', async () => { - const positionValue = 'last'; + it('should return a string with the position when positionValue is a number', async () => { + const positionValue = 1; + + try { + await factory.create( + RecordPositionQueryType.GET, + positionValue, + objectMetadataItem, + dataSourceSchema, + ); + } catch (error) { + expect(error.message).toEqual( + 'RecordPositionQueryType.GET requires positionValue to be a number', + ); + } + }); + }); + + describe('createForUpdate', () => { + it('should return a string when RecordPositionQueryType is UPDATE', async () => { + const positionValue = 1; const result = await factory.create( - RecordPositionQueryType.GET, + RecordPositionQueryType.UPDATE, positionValue, objectMetadataItem, dataSourceSchema, ); expect(result).toEqual( - `SELECT position FROM workspace_test."company" - WHERE "position" IS NOT NULL ORDER BY "position" DESC LIMIT 1`, + `UPDATE workspace_test."company" + SET "position" = $1 + WHERE "id" = $2`, ); }); }); diff --git a/packages/twenty-server/src/workspace/workspace-query-builder/factories/record-position-query.factory.ts b/packages/twenty-server/src/workspace/workspace-query-builder/factories/record-position-query.factory.ts index 40df6ab2c..a9201d426 100644 --- a/packages/twenty-server/src/workspace/workspace-query-builder/factories/record-position-query.factory.ts +++ b/packages/twenty-server/src/workspace/workspace-query-builder/factories/record-position-query.factory.ts @@ -12,7 +12,6 @@ export class RecordPositionQueryFactory { positionValue: 'first' | 'last' | number, objectMetadata: { isCustom: boolean; nameSingular: string }, dataSourceSchema: string, - recordId?: string, ): Promise { const name = (objectMetadata.isCustom ? '_' : '') + objectMetadata.nameSingular; @@ -27,24 +26,7 @@ export class RecordPositionQueryFactory { return this.createForGet(positionValue, name, dataSourceSchema); case RecordPositionQueryType.UPDATE: - if (typeof positionValue !== 'number') { - throw new Error( - 'RecordPositionQueryType.UPDATE requires positionValue to be a number', - ); - } - - if (!recordId) { - throw new Error( - 'RecordPositionQueryType.UPDATE requires recordId to be defined', - ); - } - - return this.createForUpdate( - positionValue, - name, - dataSourceSchema, - recordId, - ); + return this.createForUpdate(name, dataSourceSchema); default: throw new Error('Invalid RecordPositionQueryType'); } @@ -62,13 +44,11 @@ export class RecordPositionQueryFactory { } private async createForUpdate( - positionValue: number, name: string, dataSourceSchema: string, - recordId: string, ): Promise { return `UPDATE ${dataSourceSchema}."${name}" - SET "position" = ${positionValue} - WHERE "id" = '${recordId}'`; + SET "position" = $1 + WHERE "id" = $2`; } } diff --git a/packages/twenty-server/src/workspace/workspace-query-runner/factories/__tests__/record-position.factory.spec.ts b/packages/twenty-server/src/workspace/workspace-query-runner/factories/__tests__/record-position.factory.spec.ts new file mode 100644 index 000000000..4966fe7d1 --- /dev/null +++ b/packages/twenty-server/src/workspace/workspace-query-runner/factories/__tests__/record-position.factory.spec.ts @@ -0,0 +1,64 @@ +import { TestingModule, Test } from '@nestjs/testing'; + +import { WorkspaceDataSourceService } from 'src/workspace/workspace-datasource/workspace-datasource.service'; +import { RecordPositionQueryFactory } from 'src/workspace/workspace-query-builder/factories/record-position-query.factory'; +import { RecordPositionFactory } from 'src/workspace/workspace-query-runner/factories/record-position.factory'; + +describe('RecordPositionFactory', () => { + const recordPositionQueryFactory = { + create: jest.fn().mockResolvedValue('query'), + }; + + const workspaceDataSourceService = { + getSchemaName: jest.fn().mockReturnValue('schemaName'), + executeRawQuery: jest.fn().mockResolvedValue([{ position: 1 }]), + }; + + let factory: RecordPositionFactory; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + RecordPositionFactory, + { + provide: RecordPositionQueryFactory, + useValue: recordPositionQueryFactory, + }, + { + provide: WorkspaceDataSourceService, + useValue: workspaceDataSourceService, + }, + ], + }).compile(); + + factory = module.get(RecordPositionFactory); + }); + + it('should be defined', () => { + expect(factory).toBeDefined(); + }); + + describe('create', () => { + const objectMetadata = { isCustom: false, nameSingular: 'company' }; + const workspaceId = 'workspaceId'; + + it('should return the value when value is a number', async () => { + const value = 1; + const result = await factory.create(value, objectMetadata, workspaceId); + + expect(result).toEqual(value); + }); + it('should return the existing position / 2 when value is first', async () => { + const value = 'first'; + const result = await factory.create(value, objectMetadata, workspaceId); + + expect(result).toEqual(0.5); + }); + it('should return the existing position + 1 when value is last', async () => { + const value = 'last'; + const result = await factory.create(value, objectMetadata, workspaceId); + + expect(result).toEqual(2); + }); + }); +}); diff --git a/packages/twenty-server/src/workspace/workspace-query-runner/services/record-position-backfill-service.ts b/packages/twenty-server/src/workspace/workspace-query-runner/services/record-position-backfill-service.ts index b511c93e3..762ed1254 100644 --- a/packages/twenty-server/src/workspace/workspace-query-runner/services/record-position-backfill-service.ts +++ b/packages/twenty-server/src/workspace/workspace-query-runner/services/record-position-backfill-service.ts @@ -36,12 +36,11 @@ export class RecordPositionBackfillService { position, objectMetadata as ObjectMetadataInterface, dataSourceSchema, - recordId, ); this.workspaceDataSourceService.executeRawQuery( query, - [], + [position, recordId], workspaceId, undefined, );