Morph relation field v2 fixes (#14216)

Fixes, depending on the contextual current operation in order to
retrieve relation target and all morph related fields to be delete:
- DELETE Field,
- DELETE Object, 
- UPDATE Field, that affects all others related fields
This commit is contained in:
Paul Rastoin
2025-09-02 14:17:20 +02:00
committed by GitHub
parent c4f56156d6
commit 6d6ee939cf
10 changed files with 649 additions and 102 deletions
@@ -0,0 +1,43 @@
import { FieldMetadataType } from 'twenty-shared/types';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { findFlatFieldMetadatasRelatedToMorphRelationOrThrow } from 'src/engine/metadata-modules/flat-field-metadata/utils/find-flat-field-metadatas-related-to-morph-relation-or-throw.util';
import { findRelationFlatFieldMetadataTargetFlatFieldMetadataOrThrow } from 'src/engine/metadata-modules/flat-field-metadata/utils/find-relation-flat-field-metadatas-target-flat-field-metadata-or-throw.util';
import { isFlatFieldMetadataEntityOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
export const computeFlatFieldMetadataRelatedFlatFieldMetadata = ({
flatFieldMetadata,
flatObjectMetadataMaps,
}: {
flatFieldMetadata: FlatFieldMetadata;
flatObjectMetadataMaps: FlatObjectMetadataMaps;
}): FlatFieldMetadata[] => {
if (
isFlatFieldMetadataEntityOfType(
flatFieldMetadata,
FieldMetadataType.RELATION,
)
) {
return [
findRelationFlatFieldMetadataTargetFlatFieldMetadataOrThrow({
flatFieldMetadata,
flatObjectMetadataMaps,
}),
];
}
if (
isFlatFieldMetadataEntityOfType(
flatFieldMetadata,
FieldMetadataType.MORPH_RELATION,
)
) {
return findFlatFieldMetadatasRelatedToMorphRelationOrThrow({
flatFieldMetadata,
flatObjectMetadataMaps,
});
}
return [];
};
@@ -62,6 +62,10 @@ export const findFlatFieldMetadatasRelatedToMorphRelationOrThrow = ({
flatObjectMetadataMaps,
});
if (flatFieldMetadata.id === morphRelationFlatFieldMetadata.id) {
return [relationTargetFlatFieldMetadata];
}
return [flatFieldMetadata, relationTargetFlatFieldMetadata];
},
);
@@ -1,4 +1,3 @@
import { FieldMetadataType } from 'twenty-shared/types';
import {
isDefined,
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties,
@@ -10,9 +9,7 @@ import {
FieldMetadataExceptionCode,
} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { findFlatFieldMetadatasRelatedToMorphRelationOrThrow } from 'src/engine/metadata-modules/flat-field-metadata/utils/find-flat-field-metadatas-related-to-morph-relation-or-throw.util';
import { findRelationFlatFieldMetadataTargetFlatFieldMetadataOrThrow } from 'src/engine/metadata-modules/flat-field-metadata/utils/find-relation-flat-field-metadatas-target-flat-field-metadata-or-throw.util';
import { isFlatFieldMetadataEntityOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
import { computeFlatFieldMetadataRelatedFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/compute-flat-field-metadata-related-flat-field-metadata.util';
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
import { findFlatFieldMetadataInFlatObjectMetadataMapsWithOnlyFieldId } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-field-metadata-in-flat-object-metadata-maps-with-field-id-only.util';
@@ -43,32 +40,11 @@ export const fromDeleteFieldInputToFlatFieldMetadatasToDelete = ({
);
}
if (
isFlatFieldMetadataEntityOfType(
flatFieldMetadataToDelete,
FieldMetadataType.MORPH_RELATION,
)
) {
return findFlatFieldMetadatasRelatedToMorphRelationOrThrow({
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
const relatedFlatFieldMetadataToDelete =
computeFlatFieldMetadataRelatedFlatFieldMetadata({
flatFieldMetadata: flatFieldMetadataToDelete,
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
});
}
if (
isFlatFieldMetadataEntityOfType(
flatFieldMetadataToDelete,
FieldMetadataType.RELATION,
)
) {
const relationTargetFlatFieldMetadata =
findRelationFlatFieldMetadataTargetFlatFieldMetadataOrThrow({
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
flatFieldMetadata: flatFieldMetadataToDelete,
});
return [flatFieldMetadataToDelete, relationTargetFlatFieldMetadata];
}
return [flatFieldMetadataToDelete];
return [flatFieldMetadataToDelete, ...relatedFlatFieldMetadataToDelete];
};
@@ -13,11 +13,36 @@ import { FLAT_FIELD_METADATA_PROPERTIES_TO_COMPARE } from 'src/engine/metadata-m
import { type FieldInputTranspilationResult } from 'src/engine/metadata-modules/flat-field-metadata/types/field-input-transpilation-result.type';
import { type FlatFieldMetadataPropertiesToCompare } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-properties-to-compare.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import {} from 'src/engine/metadata-modules/flat-field-metadata/utils/compare-two-flat-field-metadata.util';
import { computeFlatFieldMetadataRelatedFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/compute-flat-field-metadata-related-flat-field-metadata.util';
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
import { findFlatFieldMetadataInFlatObjectMetadataMapsWithOnlyFieldId } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-field-metadata-in-flat-object-metadata-maps-with-field-id-only.util';
import { fromFlatObjectMetadataWithFlatFieldMapsToFlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/utils/from-flat-object-metadata-with-flat-field-maps-to-flat-object-metadatas.util';
import { isStandardMetadata } from 'src/engine/metadata-modules/utils/is-standard-metadata.util';
const applyUpdatesToFlatFieldMetadata = ({
updatedEditableFieldProperties,
flatFieldMetadata,
}: {
updatedEditableFieldProperties: SanitizedUpdateFieldInput;
flatFieldMetadata: FlatFieldMetadata;
}) => {
return fieldMetadataEditableProperties.reduce((acc, property) => {
let newValue = updatedEditableFieldProperties[property];
if (property === 'options' && isDefined(newValue)) {
newValue = updatedEditableFieldProperties[property]?.map((option) => ({
id: v4(),
...option,
}));
}
return {
...acc,
...(newValue !== undefined ? { [property]: newValue } : {}),
};
}, flatFieldMetadata);
};
const fieldMetadataEditableProperties =
FLAT_FIELD_METADATA_PROPERTIES_TO_COMPARE.filter(
(
@@ -28,6 +53,13 @@ const fieldMetadataEditableProperties =
> => property !== 'standardOverrides',
);
type SanitizedUpdateFieldInput = ReturnType<
typeof extractAndSanitizeObjectStringFields<
UpdateFieldInput,
(typeof fieldMetadataEditableProperties)[number][]
>
>;
type FromUpdateFieldInputToFlatFieldMetadataArgs = {
existingFlatObjectMetadataMaps: FlatObjectMetadataMaps;
updateFieldInput: UpdateFieldInput;
@@ -35,7 +67,9 @@ type FromUpdateFieldInputToFlatFieldMetadataArgs = {
export const fromUpdateFieldInputToFlatFieldMetadata = ({
existingFlatObjectMetadataMaps,
updateFieldInput: rawUpdateFieldInput,
}: FromUpdateFieldInputToFlatFieldMetadataArgs): FieldInputTranspilationResult<FlatFieldMetadata> => {
}: FromUpdateFieldInputToFlatFieldMetadataArgs): FieldInputTranspilationResult<
FlatFieldMetadata[]
> => {
const updateFieldInputInformalProperties =
extractAndSanitizeObjectStringFields(rawUpdateFieldInput, [
'objectMetadataId',
@@ -46,13 +80,13 @@ export const fromUpdateFieldInputToFlatFieldMetadata = ({
fieldMetadataEditableProperties,
);
const relatedFlatFieldMetadata =
const existingFlatFieldMetadataToUpdate =
findFlatFieldMetadataInFlatObjectMetadataMapsWithOnlyFieldId({
fieldMetadataId: updateFieldInputInformalProperties.id,
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
});
if (!isDefined(relatedFlatFieldMetadata)) {
if (!isDefined(existingFlatFieldMetadataToUpdate)) {
return {
status: 'fail',
error: {
@@ -65,7 +99,7 @@ export const fromUpdateFieldInputToFlatFieldMetadata = ({
const flatObjectMetadataWithFlatFieldMaps =
existingFlatObjectMetadataMaps.byId[
relatedFlatFieldMetadata.objectMetadataId
existingFlatFieldMetadataToUpdate.objectMetadataId
];
if (!isDefined(flatObjectMetadataWithFlatFieldMaps)) {
@@ -79,7 +113,12 @@ export const fromUpdateFieldInputToFlatFieldMetadata = ({
};
}
if (flatObjectMetadataWithFlatFieldMaps.isRemote) {
const flatObjectMetadata =
fromFlatObjectMetadataWithFlatFieldMapsToFlatObjectMetadata(
flatObjectMetadataWithFlatFieldMaps,
);
if (flatObjectMetadata.isRemote) {
return {
status: 'fail',
error: {
@@ -89,7 +128,7 @@ export const fromUpdateFieldInputToFlatFieldMetadata = ({
};
}
if (isStandardMetadata(relatedFlatFieldMetadata)) {
if (isStandardMetadata(existingFlatFieldMetadataToUpdate)) {
const invalidUpdatedProperties = Object.keys(
updatedEditableFieldProperties,
).filter((property) =>
@@ -125,35 +164,35 @@ export const fromUpdateFieldInputToFlatFieldMetadata = ({
: {}),
},
};
}, relatedFlatFieldMetadata);
}, existingFlatFieldMetadataToUpdate);
return {
status: 'success',
result: updatedStandardFlatFieldMetadata,
result: [updatedStandardFlatFieldMetadata],
};
}
const updatedFlatFieldMetadata = fieldMetadataEditableProperties.reduce(
(acc, property) => {
let newValue = updatedEditableFieldProperties[property];
const relatedFlatFieldMetadatasToUpdate =
computeFlatFieldMetadataRelatedFlatFieldMetadata({
flatFieldMetadata: existingFlatFieldMetadataToUpdate,
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
});
if (property === 'options' && isDefined(newValue)) {
newValue = updatedEditableFieldProperties[property]?.map((option) => ({
id: v4(),
...option,
}));
}
const flatFieldMetadatasToUpdate = [
existingFlatFieldMetadataToUpdate,
...relatedFlatFieldMetadatasToUpdate,
];
return {
...acc,
...(newValue !== undefined ? { [property]: newValue } : {}),
};
},
relatedFlatFieldMetadata,
);
const optimisticiallyUpdatedFlatFieldMetadatas =
flatFieldMetadatasToUpdate.map((flatFieldMetadata) => {
return applyUpdatesToFlatFieldMetadata({
flatFieldMetadata,
updatedEditableFieldProperties,
});
});
return {
status: 'success',
result: updatedFlatFieldMetadata,
result: optimisticiallyUpdatedFlatFieldMetadatas,
};
};