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:
+14
-6
@@ -38,6 +38,7 @@ import { parseGroupByArgs } from 'src/engine/api/graphql/graphql-query-runner/gr
|
||||
import { removeQuotes } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/remove-quote.util';
|
||||
import { GroupByWithRecordsService } from 'src/engine/api/graphql/graphql-query-runner/group-by/services/group-by-with-records.service';
|
||||
import { ProcessAggregateHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-aggregate.helper';
|
||||
import { isFieldMetadataRelationOrMorphRelation } from 'src/engine/api/graphql/workspace-schema-builder/utils/is-field-metadata-relation-or-morph-relation.utils';
|
||||
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
|
||||
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
||||
import { ViewFilterGroupService } from 'src/engine/metadata-modules/view-filter-group/services/view-filter-group.service';
|
||||
@@ -45,6 +46,7 @@ import { ViewFilterService } from 'src/engine/metadata-modules/view-filter/servi
|
||||
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
import { ViewService } from 'src/engine/metadata-modules/view/services/view.service';
|
||||
import { WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder';
|
||||
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';
|
||||
|
||||
@Injectable()
|
||||
@@ -104,12 +106,18 @@ export class CommonGroupByQueryRunnerService extends CommonBaseQueryRunnerServic
|
||||
);
|
||||
|
||||
const groupByDefinitions = groupByFields.map((groupByField) => {
|
||||
const columnNameWithQuotes = `"${
|
||||
formatColumnNamesFromCompositeFieldAndSubfields(
|
||||
groupByField.fieldMetadata.name,
|
||||
groupByField.subFieldName ? [groupByField.subFieldName] : undefined,
|
||||
)[0]
|
||||
}"`;
|
||||
const columnName = isFieldMetadataRelationOrMorphRelation(
|
||||
groupByField.fieldMetadata,
|
||||
)
|
||||
? formatColumnNameForRelationField(
|
||||
groupByField.fieldMetadata.name,
|
||||
groupByField.fieldMetadata.settings,
|
||||
)
|
||||
: formatColumnNamesFromCompositeFieldAndSubfields(
|
||||
groupByField.fieldMetadata.name,
|
||||
groupByField.subFieldName ? [groupByField.subFieldName] : undefined,
|
||||
)[0];
|
||||
const columnNameWithQuotes = `"${columnName}"`;
|
||||
const alias =
|
||||
removeQuotes(columnNameWithQuotes) +
|
||||
(isGroupByDateField(groupByField)
|
||||
|
||||
+20
-7
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
+2
-1
@@ -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];
|
||||
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import { RelationType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type FieldMetadataRelationSettings } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
|
||||
|
||||
export const formatColumnNameForRelationField = (
|
||||
fieldName: string,
|
||||
fieldMetadataSettings: FieldMetadataRelationSettings,
|
||||
): string => {
|
||||
if (fieldMetadataSettings.relationType === RelationType.MANY_TO_ONE) {
|
||||
if (!isDefined(fieldMetadataSettings.joinColumnName)) {
|
||||
throw new Error(`Join column name is not defined for field ${fieldName}`);
|
||||
}
|
||||
|
||||
return fieldMetadataSettings.joinColumnName;
|
||||
}
|
||||
|
||||
return fieldName;
|
||||
};
|
||||
Reference in New Issue
Block a user