Fix orderBy, groupBy, and orderByForRecords on foreignKey (#15480)

For the variables orderBy (for findMany and groupBy), groupBy (for
groupBy) and orderByForRecords (for groupBy), we were wrongfully adding
the foreign key field (eg: pointOfContact) by its joinColumnName (eg:
pointOfContactId) as the variable key (eg. `orderBy: { pointOfContactId:
"AscNullsFirst" } }`. That broke because then this key is used to
identify the field in the parsers.

This went unnoticed because this order / group option is not very
interesting as it is limited to the id for now, but it s still better to
have it work than crash!

before (on findMany)
<img width="1841" height="674" alt="flawn_order_by_pocId"
src="https://github.com/user-attachments/assets/3ccd7604-041d-4b7e-8b6a-c1d268440a45"
/>

after (on findMany)
<img width="1182" height="805" alt="image"
src="https://github.com/user-attachments/assets/e9253683-bcbe-429e-bbef-e334c7cc76af"
/>
This commit is contained in:
Marie
2025-10-31 15:13:49 +01:00
committed by GitHub
parent 4224a46854
commit bcdc07273e
4 changed files with 55 additions and 14 deletions
@@ -29,10 +29,12 @@ import {
type AggregationField,
getAvailableAggregationsFromObjectFields,
} from 'src/engine/api/graphql/workspace-schema-builder/utils/get-available-aggregations-from-object-fields.util';
import { isFieldMetadataRelationOrMorphRelation } from 'src/engine/api/graphql/workspace-schema-builder/utils/is-field-metadata-relation-or-morph-relation.utils';
import { UserInputError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
import { type FieldMetadataEntity } 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 { type ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
import { formatColumnNameForRelationField } from 'src/engine/twenty-orm/utils/format-column-name-for-relation-field.util';
import { formatColumnNamesFromCompositeFieldAndSubfields } from 'src/engine/twenty-orm/utils/format-column-names-from-composite-field-and-subfield.util';
export type OrderByCondition = {
@@ -54,14 +56,16 @@ export class GraphqlQueryOrderFieldParser {
): Record<string, OrderByCondition> {
return orderBy.reduce(
(acc, item) => {
Object.entries(item).forEach(([key, value]) => {
const fieldMetadataId = this.objectMetadataMapItem.fieldIdByName[key];
Object.entries(item).forEach(([fieldName, orderByDirection]) => {
const fieldMetadataId =
this.objectMetadataMapItem.fieldIdByName[fieldName] ||
this.objectMetadataMapItem.fieldIdByJoinColumnName[fieldName];
const fieldMetadata =
this.objectMetadataMapItem.fieldsById[fieldMetadataId];
if (!fieldMetadata || value === undefined) {
if (!fieldMetadata || orderByDirection === undefined) {
throw new GraphqlQueryRunnerException(
`Field "${key}" does not exist or is not sortable`,
`Field "${fieldName}" does not exist or is not sortable`,
GraphqlQueryRunnerExceptionCode.FIELD_NOT_FOUND,
);
}
@@ -69,7 +73,7 @@ export class GraphqlQueryOrderFieldParser {
if (isCompositeFieldMetadataType(fieldMetadata.type)) {
const compositeOrder = parseCompositeFieldForOrder(
fieldMetadata,
value,
orderByDirection,
objectNameSingular,
isForwardPagination,
);
@@ -79,9 +83,18 @@ export class GraphqlQueryOrderFieldParser {
const orderByCasting =
this.getOptionalOrderByCasting(fieldMetadata);
acc[`"${objectNameSingular}"."${key}"${orderByCasting}`] =
const columnName = isFieldMetadataRelationOrMorphRelation(
fieldMetadata,
)
? formatColumnNameForRelationField(
fieldMetadata.name,
fieldMetadata.settings,
)
: fieldName;
acc[`"${objectNameSingular}"."${columnName}"${orderByCasting}`] =
convertOrderByToFindOptionsOrder(
value as OrderByDirection,
orderByDirection as OrderByDirection,
isForwardPagination,
);
}
@@ -60,7 +60,8 @@ export const parseGroupByArgs = (
}
for (const fieldName of Object.keys(fieldNames)) {
const fieldMetadataId =
objectMetadataItemWithFieldMaps.fieldIdByName[fieldName];
objectMetadataItemWithFieldMaps.fieldIdByName[fieldName] ||
objectMetadataItemWithFieldMaps.fieldIdByJoinColumnName[fieldName];
const fieldMetadata =
objectMetadataItemWithFieldMaps.fieldsById[fieldMetadataId];