Morph-add-new-object-destination (#16027)

Add new object target to an existing morph relation (backend only)

Fixes https://github.com/twentyhq/core-team-issues/issues/1898

---------

Co-authored-by: prastoin <paul@twenty.com>
This commit is contained in:
Guillim
2025-11-27 12:10:13 +01:00
committed by GitHub
parent 7001c91a7d
commit 1a45576990
36 changed files with 1208 additions and 337 deletions
@@ -10,7 +10,7 @@ import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/
import { validateMorphOrRelationFlatFieldJoinColumName } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-morph-or-relation-flat-field-join-column-name.util';
import { findFlatEntityPropertyUpdate } from 'src/engine/workspace-manager/workspace-migration-v2/utils/find-flat-entity-property-update.util';
export const validateMorphOrRelationFlatFieldMetadata = async ({
export const validateMorphOrRelationFlatFieldMetadata = ({
flatEntityToValidate: flatFieldMetadataToValidate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatFieldMetadataMaps,
@@ -18,9 +18,7 @@ export const validateMorphOrRelationFlatFieldMetadata = async ({
},
updates,
remainingFlatEntityMapsToValidate,
}: FlatFieldMetadataTypeValidationArgs<MorphOrRelationFieldMetadataType>): Promise<
FlatFieldMetadataValidationError[]
> => {
}: FlatFieldMetadataTypeValidationArgs<MorphOrRelationFieldMetadataType>): FlatFieldMetadataValidationError[] => {
const { relationTargetFieldMetadataId, relationTargetObjectMetadataId } =
flatFieldMetadataToValidate;
@@ -0,0 +1,60 @@
import { msg } from '@lingui/core/macro';
import { FieldMetadataType } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { type FlatFieldMetadataTypeValidationArgs } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-type-validator.type';
import { type FlatFieldMetadataValidationError } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-validation-error.type';
import { isFlatFieldMetadataOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
import { validateMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-morph-or-relation-flat-field-metadata.util';
export const validateMorphRelationFlatFieldMetadata = (
args: FlatFieldMetadataTypeValidationArgs<FieldMetadataType.MORPH_RELATION>,
): FlatFieldMetadataValidationError[] => {
const {
flatEntityToValidate: flatFieldMetadataToValidate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: { flatFieldMetadataMaps },
remainingFlatEntityMapsToValidate,
} = args;
const { relationTargetFieldMetadataId } = flatFieldMetadataToValidate;
const errors: FlatFieldMetadataValidationError[] = [];
errors.push(...validateMorphOrRelationFlatFieldMetadata(args));
const targetFlatFieldMetadata =
remainingFlatEntityMapsToValidate?.byId[relationTargetFieldMetadataId] ??
findFlatEntityByIdInFlatEntityMaps({
flatEntityId: relationTargetFieldMetadataId,
flatEntityMaps: flatFieldMetadataMaps,
});
if (
isDefined(targetFlatFieldMetadata) &&
!isFlatFieldMetadataOfType(
targetFlatFieldMetadata,
FieldMetadataType.RELATION,
)
) {
errors.push({
code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
message: 'A morph relation field can only target a RELATION field',
userFriendlyMessage: msg`Invalid relation field target`,
});
}
const sourceObjectMetadataId = flatFieldMetadataToValidate.objectMetadataId;
const targetObjectMetadataId =
flatFieldMetadataToValidate.relationTargetObjectMetadataId;
if (sourceObjectMetadataId === targetObjectMetadataId) {
errors.push({
code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
message: 'Source object cannot be the target object',
userFriendlyMessage: msg`Source object cannot be the target object`,
});
}
return errors;
};