From 35df56e7d897e6c944c65f463e3f12b5cdfbfc5a Mon Sep 17 00:00:00 2001 From: Guillim Date: Thu, 21 Aug 2025 16:43:14 +0200 Subject: [PATCH] morph fix for release 1.4 (#14029) DataLoader Specific update du to Morph relations that have many rows Fixes https://github.com/twentyhq/twenty/issues/14018 --- .../engine/dataloaders/dataloader.service.ts | 4 ++- ...er-morph-relation-duplicate-fields.util.ts | 8 ++--- .../field-metadata-relation.service.ts | 35 ++++++++++++++++++- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/packages/twenty-server/src/engine/dataloaders/dataloader.service.ts b/packages/twenty-server/src/engine/dataloaders/dataloader.service.ts index b806b430cb..71972dfc28 100644 --- a/packages/twenty-server/src/engine/dataloaders/dataloader.service.ts +++ b/packages/twenty-server/src/engine/dataloaders/dataloader.service.ts @@ -250,7 +250,9 @@ export class DataloaderService { }); }); - return filterMorphRelationDuplicateFieldsDTO(fields); + return filterMorphRelationDuplicateFieldsDTO( + fields, + ); }); return fieldMetadataCollection; diff --git a/packages/twenty-server/src/engine/dataloaders/utils/filter-morph-relation-duplicate-fields.util.ts b/packages/twenty-server/src/engine/dataloaders/utils/filter-morph-relation-duplicate-fields.util.ts index c5b5d491df..e300ac6296 100644 --- a/packages/twenty-server/src/engine/dataloaders/utils/filter-morph-relation-duplicate-fields.util.ts +++ b/packages/twenty-server/src/engine/dataloaders/utils/filter-morph-relation-duplicate-fields.util.ts @@ -1,7 +1,7 @@ -import { type FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto'; - -export const filterMorphRelationDuplicateFieldsDTO = ( - fields: FieldMetadataDTO[], +export const filterMorphRelationDuplicateFieldsDTO = < + T extends { name: string; id: string }, +>( + fields: T[], ) => { return fields.filter((currentField) => { return !fields.some( diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/services/field-metadata-relation.service.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/services/field-metadata-relation.service.ts index 41a61fed35..1dedcc3a2c 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/services/field-metadata-relation.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/services/field-metadata-relation.service.ts @@ -10,6 +10,7 @@ import { v4 } from 'uuid'; import { type FieldMetadataSettings } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface'; import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface'; +import { filterMorphRelationDuplicateFieldsDTO } from 'src/engine/dataloaders/utils/filter-morph-relation-duplicate-fields.util'; import { type CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input'; import { type UpdateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input'; import { type FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; @@ -18,6 +19,7 @@ import { FieldMetadataExceptionCode, } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception'; import { computeRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-relation-field-join-column-name.util'; +import { isFieldMetadataTypeMorphRelation } from 'src/engine/metadata-modules/field-metadata/utils/is-field-metadata-type-morph-relation.util'; import { prepareCustomFieldMetadataForCreation } from 'src/engine/metadata-modules/field-metadata/utils/prepare-field-metadata-for-creation.util'; import { validateRelationCreationPayloadOrThrow } from 'src/engine/metadata-modules/field-metadata/utils/validate-relation-creation-payload-or-throw.util'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; @@ -272,6 +274,37 @@ export class FieldMetadataRelationService { ); } + // Morph relation specific: + // to keep the fieldMetadata API simple + // we decided to override the targetFieldMetadata with the existing one + // in case the relation target is a morph relation + const isRelationTargetMorphRelation = + isFieldMetadataTypeMorphRelation(targetFieldMetadata); + + const targetObjectMetadataFields = Object.values( + targetObjectMetadata.fieldsById, + ); + + const targetObjectMetadataWithoutDuplicates = + filterMorphRelationDuplicateFieldsDTO( + targetObjectMetadataFields, + ); + const targetFieldMetadataSelected = + targetObjectMetadataWithoutDuplicates.find( + (fieldMetadata) => fieldMetadata.name === targetFieldMetadata.name, + ); + + if (!isDefined(targetFieldMetadataSelected)) { + throw new FieldMetadataException( + `Target field metadata not found for field metadata ${id}`, + FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED, + ); + } + + const targetFieldMetadataOverride = isRelationTargetMorphRelation + ? targetFieldMetadataSelected + : targetFieldMetadata; + return { sourceObjectMetadata: getObjectMetadataFromObjectMetadataItemWithFieldMaps( @@ -282,7 +315,7 @@ export class FieldMetadataRelationService { getObjectMetadataFromObjectMetadataItemWithFieldMaps( targetObjectMetadata, ) as ObjectMetadataEntity, - targetFieldMetadata: targetFieldMetadata as FieldMetadataEntity, + targetFieldMetadata: targetFieldMetadataOverride as FieldMetadataEntity, }; }); }