diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-many-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-many-resolver.service.ts index 396b5ffdd..5caa30e4e 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-many-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-many-resolver.service.ts @@ -118,6 +118,7 @@ export class GraphqlQueryFindManyResolverService { const cursorArgFilter = computeCursorArgFilter( cursor, orderByWithIdCondition, + objectMetadata.fields, isForwardPagination, ); diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/utils/compute-cursor-arg-filter.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/utils/compute-cursor-arg-filter.ts index ed55af29e..c602aef7f 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/utils/compute-cursor-arg-filter.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/utils/compute-cursor-arg-filter.ts @@ -8,10 +8,15 @@ import { GraphqlQueryRunnerException, GraphqlQueryRunnerExceptionCode, } from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception'; +import { compositeTypeDefinitions } from 'src/engine/metadata-modules/field-metadata/composite-types'; +import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util'; +import { FieldMetadataMap } from 'src/engine/metadata-modules/utils/generate-object-metadata-map.util'; export const computeCursorArgFilter = ( cursor: Record, orderBy: RecordOrderBy, + fieldMetadataMap: FieldMetadataMap, isForwardPagination = true, ): RecordFilter[] => { const cursorKeys = Object.keys(cursor ?? {}); @@ -31,9 +36,12 @@ export const computeCursorArgFilter = ( ) { whereCondition = { ...whereCondition, - [cursorKeys[subConditionIndex]]: { - eq: cursorValues[subConditionIndex], - }, + ...buildWhereCondition( + cursorKeys[subConditionIndex], + cursorValues[subConditionIndex], + fieldMetadataMap, + 'eq', + ), }; } @@ -60,7 +68,66 @@ export const computeCursorArgFilter = ( return { ...whereCondition, - ...{ [key]: { [operator]: value } }, + ...buildWhereCondition(key, value, fieldMetadataMap, operator), } as RecordFilter; }); }; + +const buildWhereCondition = ( + key: string, + value: any, + fieldMetadataMap: FieldMetadataMap, + operator: string, +): Record => { + const fieldMetadata = fieldMetadataMap[key]; + + if (!fieldMetadata) { + throw new GraphqlQueryRunnerException( + `Field metadata not found for key: ${key}`, + GraphqlQueryRunnerExceptionCode.INVALID_CURSOR, + ); + } + + if (isCompositeFieldMetadataType(fieldMetadata.type)) { + return buildCompositeWhereCondition( + key, + value, + fieldMetadata.type, + operator, + ); + } + + return { [key]: { [operator]: value } }; +}; + +const buildCompositeWhereCondition = ( + key: string, + value: any, + fieldType: FieldMetadataType, + operator: string, +): Record => { + const compositeType = compositeTypeDefinitions.get(fieldType); + + if (!compositeType) { + throw new GraphqlQueryRunnerException( + `Composite type definition not found for type: ${fieldType}`, + GraphqlQueryRunnerExceptionCode.INVALID_CURSOR, + ); + } + + const result: Record = {}; + + compositeType.properties.forEach((property) => { + if ( + property.type !== FieldMetadataType.RAW_JSON && + value[property.name] !== undefined + ) { + result[key] = { + ...result[key], + [property.name]: { [operator]: value[property.name] }, + }; + } + }); + + return result; +};