diff --git a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect.ts b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect.ts index 6bea94d6f2b3..5e8a3abf05ea 100644 --- a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect.ts +++ b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect.ts @@ -1,6 +1,5 @@ import { ApolloCache, StoreObject } from '@apollo/client'; import { isNonEmptyString } from '@sniptt/guards'; -import { Buffer } from 'buffer'; import { triggerUpdateRelationsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerUpdateRelationsOptimisticEffect'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; @@ -11,6 +10,7 @@ import { RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode'; import { isRecordMatchingFilter } from '@/object-record/record-filter/utils/isRecordMatchingFilter'; import { CachedObjectRecordQueryVariables } from '@/apollo/types/CachedObjectRecordQueryVariables'; +import { encodeCursor } from '@/apollo/utils/encodeCursor'; import { isDefined } from '~/utils/isDefined'; import { parseApolloStoreFieldName } from '~/utils/parseApolloStoreFieldName'; @@ -128,13 +128,7 @@ export const triggerCreateRecordsOptimisticEffect = ({ ); if (recordToCreateReference && !recordAlreadyInCache) { - const cursor = Buffer.from( - JSON.stringify({ - position: recordToCreate.position, - id: recordToCreate.id, - }), - 'utf-8', - ).toString('base64'); + const cursor = encodeCursor(recordToCreate); const edge = { __typename: getEdgeTypename(objectMetadataItem.nameSingular), diff --git a/packages/twenty-front/src/modules/apollo/utils/__tests__/encodeCursor.test.ts b/packages/twenty-front/src/modules/apollo/utils/__tests__/encodeCursor.test.ts new file mode 100644 index 000000000000..09fddabb5826 --- /dev/null +++ b/packages/twenty-front/src/modules/apollo/utils/__tests__/encodeCursor.test.ts @@ -0,0 +1,55 @@ +import { encodeCursor } from '@/apollo/utils/encodeCursor'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; + +describe('encodeCursor', () => { + it('should create a cursor with id only', () => { + const record: ObjectRecord = { __typename: 'ObjectRecord', id: '123' }; + const cursor = encodeCursor(record); + const decoded = JSON.parse(Buffer.from(cursor, 'base64').toString('utf-8')); + + expect(decoded).toEqual({ id: '123' }); + }); + + it('should create a cursor with id and position', () => { + const record: ObjectRecord = { + __typename: 'ObjectRecord', + id: '123', + position: 1, + }; + const cursor = encodeCursor(record); + const decoded = JSON.parse(Buffer.from(cursor, 'base64').toString('utf-8')); + + expect(decoded).toEqual({ id: '123', position: 1 }); + }); + + it('should create a cursor with id and position as 0', () => { + const record: ObjectRecord = { + __typename: 'ObjectRecord', + id: '123', + position: 0, + }; + const cursor = encodeCursor(record); + const decoded = JSON.parse(Buffer.from(cursor, 'base64').toString('utf-8')); + + expect(decoded).toEqual({ id: '123', position: 0 }); + }); + + it('should create a cursor with id and ignore extra fields', () => { + const record: ObjectRecord = { + __typename: 'ObjectRecord', + id: '123', + position: 1, + extra: 'extra', + }; + const cursor = encodeCursor(record); + const decoded = JSON.parse(Buffer.from(cursor, 'base64').toString('utf-8')); + + expect(decoded).toEqual({ id: '123', position: 1 }); + }); + + it('should throw an error if record does not have an id', () => { + const record = { position: 1 } as any; + + expect(() => encodeCursor(record)).toThrow(); + }); +}); diff --git a/packages/twenty-front/src/modules/apollo/utils/encodeCursor.ts b/packages/twenty-front/src/modules/apollo/utils/encodeCursor.ts new file mode 100644 index 000000000000..60eaf60f632f --- /dev/null +++ b/packages/twenty-front/src/modules/apollo/utils/encodeCursor.ts @@ -0,0 +1,18 @@ +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { isDefined } from '~/utils/isDefined'; + +export const encodeCursor = (record: ObjectRecord) => { + if (!('id' in record) || !isDefined(record.id)) { + throw new Error('Record does not have an id'); + } + + const payload: { + id: string; + position?: number; + } = { + position: record.position, + id: record.id, + }; + + return Buffer.from(JSON.stringify(payload), 'utf-8').toString('base64'); +};