Update object handle morph join col rename (#14153)

# Introduction
When udpating a flat object metadata name we need to search for RELATION
field that has a MORPH RELATION target flat field metadata with
MANY_TO_ONE relationType as its settings are binded to the updated flat
object metadata name

In the best of the world we would remove this complexity to be computed
at runtime only and deprecate implemented logic here

close https://github.com/twentyhq/core-team-issues/issues/1412
This commit is contained in:
Paul Rastoin
2025-08-29 16:46:15 +02:00
committed by GitHub
parent 28f1481d15
commit 6397a4d906
10 changed files with 201 additions and 35 deletions
@@ -4,11 +4,13 @@ import {
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties,
} from 'twenty-shared/utils';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
import { findFlatObjectMetadataInFlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-object-metadata-in-flat-object-metadata-maps.util';
import { FLAT_OBJECT_METADATA_PROPERTIES_TO_COMPARE } from 'src/engine/metadata-modules/flat-object-metadata/constants/flat-object-metadata-properties-to-compare.constant';
import { type FlatObjectMetadataPropertiesToCompare } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata-properties-to-compare.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { renameFlatObjectMetadataManyToOneMorphRelationTargetFlatFieldMetadatasSettingsJoinColumnName } from 'src/engine/metadata-modules/flat-object-metadata/utils/rename-flat-object-metadata-morph-relation-flat-field-metadatas-settings-join-column-name.util';
import { OBJECT_METADATA_STANDARD_OVERRIDES_PROPERTIES } from 'src/engine/metadata-modules/object-metadata/constants/object-metadata-standard-overrides-properties.constant';
import { type UpdateOneObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/update-object.input';
import {
@@ -33,10 +35,15 @@ const objectMetadataEditableProperties =
> => property !== 'standardOverrides',
);
type UpdatedFlatObjectAndOtherObjectFieldMetadatas = {
flatObjectMetadata: FlatObjectMetadata;
otherObjectFlatFieldMetadatas: FlatFieldMetadata[];
};
export const fromUpdateObjectInputToFlatObjectMetadata = ({
existingFlatObjectMetadataMaps,
updateObjectInput: rawUpdateObjectInput,
}: FromUpdateObjectInputToFlatObjectMetadataArgs): FlatObjectMetadata => {
}: FromUpdateObjectInputToFlatObjectMetadataArgs): UpdatedFlatObjectAndOtherObjectFieldMetadatas => {
const { id: objectMetadataIdToUpdate } =
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
rawUpdateObjectInput,
@@ -93,23 +100,54 @@ export const fromUpdateObjectInputToFlatObjectMetadata = ({
};
}, flatObjectMetadataToUpdate);
return updatedStandardFlatObjectdMetadata;
return {
flatObjectMetadata: updatedStandardFlatObjectdMetadata,
otherObjectFlatFieldMetadatas: [],
};
}
const updatedFlatObjectMetadata = objectMetadataEditableProperties.reduce(
(acc, property) => {
const initialAccumulator: UpdatedFlatObjectAndOtherObjectFieldMetadatas = {
flatObjectMetadata: flatObjectMetadataToUpdate,
otherObjectFlatFieldMetadatas: [],
};
return objectMetadataEditableProperties.reduce<UpdatedFlatObjectAndOtherObjectFieldMetadatas>(
({ flatObjectMetadata, otherObjectFlatFieldMetadatas }, property) => {
const updatedPropertyValue = updatedEditableObjectProperties[property];
const isPropertyUpdated =
updatedEditableObjectProperties[property] !== undefined;
updatedPropertyValue !== undefined &&
flatObjectMetadata[property] !== updatedPropertyValue;
if (!isPropertyUpdated) {
return {
flatObjectMetadata,
otherObjectFlatFieldMetadatas,
};
}
const updatedFlatObjectMetadata = {
...flatObjectMetadata,
[property]: updatedPropertyValue,
};
const newUpdatedOtherObjectFlatFieldMetadatas =
property === 'nameSingular'
? renameFlatObjectMetadataManyToOneMorphRelationTargetFlatFieldMetadatasSettingsJoinColumnName(
{
existingFlatObjectMetadataMaps,
fromFlatObjectMetadata: updatedFlatObjectMetadata,
toFlatObjectMetadata: updatedFlatObjectMetadata,
},
)
: [];
return {
...acc,
...(isPropertyUpdated
? { [property]: updatedEditableObjectProperties[property] }
: {}),
flatObjectMetadata: updatedFlatObjectMetadata,
otherObjectFlatFieldMetadatas: [
...otherObjectFlatFieldMetadatas,
...newUpdatedOtherObjectFlatFieldMetadatas,
],
};
},
flatObjectMetadataToUpdate,
initialAccumulator,
);
return updatedFlatObjectMetadata;
};
@@ -0,0 +1,50 @@
import { FieldMetadataType } from 'twenty-shared/types';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
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';
import { findFlatFieldMetadataInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-field-metadata-in-flat-object-metadata-maps-or-throw.util';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
type GetFlatObjectMetadataMorphRelationFlatFieldMetadatasArgs = {
flatObjectMetadata: FlatObjectMetadata;
existingFlatObjectMetadataMaps: FlatObjectMetadataMaps;
};
export const getFlatObjectMetadataManyToOneTargetMorphRelationFlatFieldMetadatasOrThrow =
({
flatObjectMetadata,
existingFlatObjectMetadataMaps,
}: GetFlatObjectMetadataMorphRelationFlatFieldMetadatasArgs) => {
const manyToOneMorphRelationTargetFlatFieldMetadataIds =
flatObjectMetadata.flatFieldMetadatas
.filter(
(
flatFieldMetadata,
): flatFieldMetadata is FlatFieldMetadata<FieldMetadataType.RELATION> =>
isFlatFieldMetadataEntityOfType(
flatFieldMetadata,
FieldMetadataType.RELATION,
) &&
flatFieldMetadata.settings.relationType ===
RelationType.MANY_TO_ONE &&
isFlatFieldMetadataEntityOfType(
flatFieldMetadata.flatRelationTargetFieldMetadata,
FieldMetadataType.MORPH_RELATION,
),
)
.map(({ id: fieldMetadataId, objectMetadataId }) => ({
fieldMetadataId,
objectMetadataId,
}));
return manyToOneMorphRelationTargetFlatFieldMetadataIds.map(
({ fieldMetadataId, objectMetadataId }) =>
findFlatFieldMetadataInFlatObjectMetadataMapsOrThrow({
fieldMetadataId,
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
objectMetadataId,
}),
) as FlatFieldMetadata<FieldMetadataType.MORPH_RELATION>[];
};
@@ -0,0 +1,46 @@
import { type FieldMetadataType, type FromTo } from 'twenty-shared/types';
import { computeMorphRelationFieldJoinColumnName } from 'twenty-shared/utils';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { getFlatObjectMetadataManyToOneTargetMorphRelationFlatFieldMetadatasOrThrow } from 'src/engine/metadata-modules/flat-object-metadata/utils/get-flat-object-metadata-many-to-one-target-morph-relation-flat-field-metadatas-or-throw.util';
type RenameFlatObjectMetadataManyToOneMorphRelationTargetFlatFieldMetadatasSettingsJoinColumnNameArgs =
FromTo<FlatObjectMetadata, 'flatObjectMetadata'> & {
existingFlatObjectMetadataMaps: FlatObjectMetadataMaps;
};
export const renameFlatObjectMetadataManyToOneMorphRelationTargetFlatFieldMetadatasSettingsJoinColumnName =
({
fromFlatObjectMetadata,
toFlatObjectMetadata,
existingFlatObjectMetadataMaps,
}: RenameFlatObjectMetadataManyToOneMorphRelationTargetFlatFieldMetadatasSettingsJoinColumnNameArgs): FlatFieldMetadata<FieldMetadataType.MORPH_RELATION>[] => {
const manyToOneMorphRelationFlatFieldMetadatas =
getFlatObjectMetadataManyToOneTargetMorphRelationFlatFieldMetadatasOrThrow(
{
flatObjectMetadata: fromFlatObjectMetadata,
existingFlatObjectMetadataMaps,
},
);
const updatedFlatFieldMetadatas =
manyToOneMorphRelationFlatFieldMetadatas.map(
(morphRelationFlatFieldMetadata) => {
const newJoinColumnName = computeMorphRelationFieldJoinColumnName({
name: morphRelationFlatFieldMetadata.name,
targetObjectMetadataNameSingular: toFlatObjectMetadata.nameSingular,
});
return {
...morphRelationFlatFieldMetadata,
settings: {
...morphRelationFlatFieldMetadata.settings,
joinColumnName: newJoinColumnName,
},
};
},
);
return updatedFlatFieldMetadatas;
};