Fix paginated order by with composite fields (#7187)
## Context
Cursor is modifying the where object but does not handle properly
composite fields. I'm introducing field metadata as a source of truth to
fix this issue.
RAW_JSON for example (as a sub-field type) should be ignored in a lt/gt,
probably other field types as well.
## Before
```typescript
[
{
emails: {
lt: {
primaryEmail: "brenda.brown@example.com",
additionalEmails: null,
},
},
},
{
emails: {
eq: {
primaryEmail: "brenda.brown@example.com",
additionalEmails: null,
},
},
position: {
gt: 877,
},
},
{
emails: {
eq: {
primaryEmail: "brenda.brown@example.com",
additionalEmails: null,
},
},
position: {
eq: 877,
},
id: {
gt: "fe43c45d-7560-4eb1-8fd3-c48fd0a4dcd4",
},
},
]
```
## After
```typescript
[
{
emails: {
primaryEmail: {
lt: "brenda.brown@example.com",
},
},
},
{
emails: {
primaryEmail: {
eq: "brenda.brown@example.com",
},
},
position: {
gt: 877,
},
},
{
emails: {
primaryEmail: {
eq: "brenda.brown@example.com",
},
},
position: {
eq: 877,
},
id: {
gt: "fe43c45d-7560-4eb1-8fd3-c48fd0a4dcd4",
},
},
]
```
This commit is contained in:
@ -118,6 +118,7 @@ export class GraphqlQueryFindManyResolverService {
|
||||
const cursorArgFilter = computeCursorArgFilter(
|
||||
cursor,
|
||||
orderByWithIdCondition,
|
||||
objectMetadata.fields,
|
||||
isForwardPagination,
|
||||
);
|
||||
|
||||
|
||||
@ -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<string, any>,
|
||||
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<string, any> => {
|
||||
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<string, any> => {
|
||||
const compositeType = compositeTypeDefinitions.get(fieldType);
|
||||
|
||||
if (!compositeType) {
|
||||
throw new GraphqlQueryRunnerException(
|
||||
`Composite type definition not found for type: ${fieldType}`,
|
||||
GraphqlQueryRunnerExceptionCode.INVALID_CURSOR,
|
||||
);
|
||||
}
|
||||
|
||||
const result: Record<string, any> = {};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user