Files
twenty/packages/twenty-server/test/integration/graphql/utils/find-many-operation-factory.util.ts
Raphaël Bosi d4995ab54e Fix cursor-based pagination with lexicographic ordering for composite fields (#12467)
# Fix cursor-based pagination with lexicographic ordering for composite
fields

## Bug

The existing cursor-based pagination implementation had a bug when
handling composite fields.
When paginating through results sorted by composite fields (like
`fullName` with sub-properties `firstName` and`lastName`), the WHERE
conditions generated for cursor positioning were incorrect, leading to
records being skipped.

The previous implementation was generating wrong WHERE conditions:

For example, when paginating with a cursor like `{ firstName: 'John',
lastName: 'Doe' }`, it would generate:

```sql
WHERE firstName > 'John' AND lastName > 'Doe'
```

This is incorrect because it would miss records like `{ firstName:
'John', lastName: 'Smith' }` which should be included in forward
pagination.

## Fix

Create a new util to use proper lexicographic order when sorting a
composite field.

---------

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
2025-06-11 14:48:03 +00:00

57 lines
1.3 KiB
TypeScript

import gql from 'graphql-tag';
import { capitalize } from 'twenty-shared/utils';
type FindManyOperationFactoryParams = {
objectMetadataSingularName: string;
objectMetadataPluralName: string;
gqlFields: string;
filter?: object;
orderBy?: object;
limit?: number;
after?: string;
before?: string;
first?: number;
last?: number;
};
export const findManyOperationFactory = ({
objectMetadataSingularName,
objectMetadataPluralName,
gqlFields,
filter = {},
orderBy = {},
limit,
after,
before,
first,
last,
}: FindManyOperationFactoryParams) => ({
query: gql`
query ${capitalize(objectMetadataPluralName)}($filter: ${capitalize(objectMetadataSingularName)}FilterInput, $orderBy: [${capitalize(objectMetadataSingularName)}OrderByInput], $limit: Int, $after: String, $before: String, $first: Int, $last: Int) {
${objectMetadataPluralName}(filter: $filter, orderBy: $orderBy, limit: $limit, after: $after, before: $before, first: $first, last: $last) {
edges {
node {
${gqlFields}
}
cursor
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
`,
variables: {
filter,
orderBy,
limit,
after,
before,
first,
last,
},
});