Update Name of relation fieldMetadata (#15749)

UpdateOne of a Relation that involves a CustomObject, because the
nameSingular needs to be updated in the fieldMetadata
- nameSingular and namePlural must be provided since they are necessary
for morph name computation
  - label sync should be false


Interesting files to look at:

-
packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-default-relation-flat-field-metadatas-for-custom-object.util.ts

- UPDATE =>
packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/utils/rename-related-morph-field-on-object-names-update.util.ts
( also update relation indexes ) needs v2 refactor to handle field
relation name update
- CREATE =>
packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-default-relation-flat-field-metadatas-for-custom-object.util.ts
( handle morph instead of previous classic relation )
- DELETE => DONE

Edit:
closes https://github.com/twentyhq/core-team-issues/issues/1897

---------

Co-authored-by: prastoin <paul@twenty.com>
This commit is contained in:
Guillim
2025-11-23 21:45:30 +01:00
committed by GitHub
parent 6203b7b3e6
commit 4848bc03f3
24 changed files with 1282 additions and 405 deletions
@@ -33,11 +33,14 @@ export const computeFlatFieldMetadataRelatedFlatFieldMetadata = ({
FieldMetadataType.MORPH_RELATION,
)
) {
return findFlatFieldMetadatasRelatedToMorphRelationOrThrow({
flatFieldMetadata,
flatFieldMetadataMaps,
flatObjectMetadata,
});
const { morphRelationFlatFieldMetadatas, relationFlatFieldMetadatas } =
findFlatFieldMetadatasRelatedToMorphRelationOrThrow({
flatFieldMetadata,
flatFieldMetadataMaps,
flatObjectMetadata,
});
return [...morphRelationFlatFieldMetadatas, ...relationFlatFieldMetadatas];
}
return [];
@@ -0,0 +1,159 @@
import { FieldMetadataType, type FromTo } from 'twenty-shared/types';
import { type UpdateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input';
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { FLAT_FIELD_METADATA_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-editable-properties.constant';
import { FLAT_FIELD_METADATA_MORPH_RELATION_EDITABLE_PROPERTIES_ON_SIBLING_MORPH_RELATION_UPDATE_CONSTANT } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-morph-relation-editable-properties-on-sibling-morph-relation-update.constant';
import { FLAT_FIELD_METADATA_RELATION_EDITABLE_PROPERTIES_ON_SIBLING_MORPH_OR_RELATION_UPDATE_CONSTANT } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-relation-editable-properties-on-sibling-morph-or-relation-update.constant';
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 { isFlatFieldMetadataOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
import { sanitizeRawUpdateFieldInput } from 'src/engine/metadata-modules/flat-field-metadata/utils/sanitize-raw-update-field-input';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { isStandardMetadata } from 'src/engine/metadata-modules/utils/is-standard-metadata.util';
import { mergeUpdateInExistingRecord } from 'src/utils/merge-update-in-existing-record.util';
type ComputeFlatFieldToUpdateAndRelatedFlatFieldToUpdateReturnType = {
flatFieldMetadataFromTo: FromTo<FlatFieldMetadata, 'flatFieldMetadata'>;
relatedFlatFieldMetadatasFromTo: FromTo<
FlatFieldMetadata,
'flatFieldMetadata'
>[];
};
type ComputeFlatFieldToUpdateAndRelatedFlatFieldToUpdateArgs = {
rawUpdateFieldInput: UpdateFieldInput;
fromFlatFieldMetadata: FlatFieldMetadata;
flatObjectMetadata: FlatObjectMetadata;
} & Pick<AllFlatEntityMaps, 'flatFieldMetadataMaps'>;
// Note: Standard override is way too complex we should land a smoother implemenentation once we standardize
// them across every flat entities
export const computeFlatFieldToUpdateAndRelatedFlatFieldToUpdate = ({
fromFlatFieldMetadata,
rawUpdateFieldInput,
flatFieldMetadataMaps,
flatObjectMetadata,
}: ComputeFlatFieldToUpdateAndRelatedFlatFieldToUpdateArgs): ComputeFlatFieldToUpdateAndRelatedFlatFieldToUpdateReturnType => {
const { standardOverrides, updatedEditableFieldProperties } =
sanitizeRawUpdateFieldInput({
existingFlatFieldMetadata: fromFlatFieldMetadata,
rawUpdateFieldInput,
});
const isStandardField = isStandardMetadata(fromFlatFieldMetadata);
const toFlatFieldMetadata = {
...mergeUpdateInExistingRecord({
existing: fromFlatFieldMetadata,
properties:
FLAT_FIELD_METADATA_EDITABLE_PROPERTIES[
isStandardField ? 'standard' : 'custom'
],
update: updatedEditableFieldProperties,
}),
standardOverrides,
};
if (
isFlatFieldMetadataOfType(fromFlatFieldMetadata, FieldMetadataType.RELATION)
) {
const relatedFlatFieldMetadataFrom =
findRelationFlatFieldMetadataTargetFlatFieldMetadataOrThrow({
flatFieldMetadata: fromFlatFieldMetadata,
flatFieldMetadataMaps,
});
const relatedFlatFieldMetadataTo = mergeUpdateInExistingRecord({
existing: relatedFlatFieldMetadataFrom as FlatFieldMetadata,
properties:
FLAT_FIELD_METADATA_RELATION_EDITABLE_PROPERTIES_ON_SIBLING_MORPH_OR_RELATION_UPDATE_CONSTANT,
update: updatedEditableFieldProperties,
});
return {
flatFieldMetadataFromTo: {
fromFlatFieldMetadata,
toFlatFieldMetadata,
},
relatedFlatFieldMetadatasFromTo: [
{
fromFlatFieldMetadata: relatedFlatFieldMetadataFrom,
toFlatFieldMetadata: relatedFlatFieldMetadataTo,
},
],
};
}
if (
isFlatFieldMetadataOfType(
fromFlatFieldMetadata,
FieldMetadataType.MORPH_RELATION,
)
) {
const { morphRelationFlatFieldMetadatas, relationFlatFieldMetadatas } =
findFlatFieldMetadatasRelatedToMorphRelationOrThrow({
flatFieldMetadata: fromFlatFieldMetadata,
flatFieldMetadataMaps,
flatObjectMetadata,
});
const relatedMorphRelationFlatFieldMetdataTo =
morphRelationFlatFieldMetadatas.map<
FromTo<FlatFieldMetadata, 'flatFieldMetadata'>
>((relatedFlatFieldMetadataFrom) => {
const relatedMorphPropertiesToUpdateTo =
FLAT_FIELD_METADATA_MORPH_RELATION_EDITABLE_PROPERTIES_ON_SIBLING_MORPH_RELATION_UPDATE_CONSTANT[
isStandardField ? 'standard' : 'custom'
];
const relatedFlatFieldMetadataTo = {
...mergeUpdateInExistingRecord({
existing: relatedFlatFieldMetadataFrom as FlatFieldMetadata,
properties: relatedMorphPropertiesToUpdateTo,
update: updatedEditableFieldProperties,
}),
standardOverrides,
};
return {
fromFlatFieldMetadata: relatedFlatFieldMetadataFrom,
toFlatFieldMetadata: relatedFlatFieldMetadataTo,
};
});
const relatedRelationFlatFieldMetadataTo = relationFlatFieldMetadatas.map<
FromTo<FlatFieldMetadata, 'flatFieldMetadata'>
>((relatedFlatFieldMetadataFrom) => {
const relatedFlatFieldMetadataTo = mergeUpdateInExistingRecord({
existing: relatedFlatFieldMetadataFrom as FlatFieldMetadata,
properties:
FLAT_FIELD_METADATA_RELATION_EDITABLE_PROPERTIES_ON_SIBLING_MORPH_OR_RELATION_UPDATE_CONSTANT,
update: updatedEditableFieldProperties,
});
return {
fromFlatFieldMetadata: relatedFlatFieldMetadataFrom,
toFlatFieldMetadata: relatedFlatFieldMetadataTo,
};
});
return {
flatFieldMetadataFromTo: {
fromFlatFieldMetadata,
toFlatFieldMetadata,
},
relatedFlatFieldMetadatasFromTo: [
...relatedMorphRelationFlatFieldMetdataTo,
...relatedRelationFlatFieldMetadataTo,
],
};
}
return {
flatFieldMetadataFromTo: {
fromFlatFieldMetadata,
toFlatFieldMetadata,
},
relatedFlatFieldMetadatasFromTo: [],
};
};
@@ -0,0 +1,26 @@
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
export const findFieldRelatedIndexes = ({
flatFieldMetadata,
flatObjectMetadata,
flatIndexMaps,
}: {
flatFieldMetadata: FlatFieldMetadata;
flatObjectMetadata: FlatObjectMetadata;
flatIndexMaps: FlatEntityMaps<FlatIndexMetadata>;
}): FlatIndexMetadata[] => {
const objectIndexes = findManyFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityMaps: flatIndexMaps,
flatEntityIds: flatObjectMetadata.indexMetadataIds,
});
return objectIndexes.filter((index) =>
index.flatIndexFieldMetadatas.some(
(indexField) => indexField.fieldMetadataId === flatFieldMetadata.id,
),
);
};
@@ -1,6 +1,5 @@
import { type FieldMetadataType } from 'twenty-shared/types';
import { type MorphOrRelationFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/types/morph-or-relation-field-metadata-type.type';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { findAllOthersMorphRelationFlatFieldMetadatasOrThrow } from 'src/engine/metadata-modules/flat-field-metadata/utils/find-all-others-morph-relation-flat-field-metadatas-or-throw.util';
@@ -12,32 +11,35 @@ export type FindFlatFieldMetadatasRelatedToMorphRelationOrThrowArgs = {
flatFieldMetadata: FlatFieldMetadata<FieldMetadataType.MORPH_RELATION>;
flatObjectMetadata: FlatObjectMetadata;
};
type FindFlatFieldMetadatasRelatedToMorphRelationOrThrowReturnType = {
morphRelationFlatFieldMetadatas: FlatFieldMetadata<FieldMetadataType.MORPH_RELATION>[];
relationFlatFieldMetadatas: FlatFieldMetadata<FieldMetadataType.RELATION>[];
};
export const findFlatFieldMetadatasRelatedToMorphRelationOrThrow = ({
flatFieldMetadataMaps,
flatFieldMetadata: morphRelationFlatFieldMetadata,
flatObjectMetadata,
}: FindFlatFieldMetadatasRelatedToMorphRelationOrThrowArgs): FlatFieldMetadata<MorphOrRelationFieldMetadataType>[] => {
const allMorphFlatFieldMetadatas =
}: FindFlatFieldMetadatasRelatedToMorphRelationOrThrowArgs): FindFlatFieldMetadatasRelatedToMorphRelationOrThrowReturnType => {
const morphRelationFlatFieldMetadatas =
findAllOthersMorphRelationFlatFieldMetadatasOrThrow({
flatFieldMetadata: morphRelationFlatFieldMetadata,
flatFieldMetadataMaps,
flatObjectMetadata,
});
return [
const relationFlatFieldMetadatas = [
morphRelationFlatFieldMetadata,
...allMorphFlatFieldMetadatas,
].flatMap((flatFieldMetadata) => {
const relationTargetFlatFieldMetadata =
findRelationFlatFieldMetadataTargetFlatFieldMetadataOrThrow({
flatFieldMetadata,
flatFieldMetadataMaps,
});
...morphRelationFlatFieldMetadatas,
].map((flatFieldMetadata) =>
findRelationFlatFieldMetadataTargetFlatFieldMetadataOrThrow({
flatFieldMetadata,
flatFieldMetadataMaps,
}),
) as FlatFieldMetadata<FieldMetadataType.RELATION>[];
if (flatFieldMetadata.id === morphRelationFlatFieldMetadata.id) {
return [relationTargetFlatFieldMetadata];
}
return [flatFieldMetadata, relationTargetFlatFieldMetadata];
});
return {
morphRelationFlatFieldMetadatas,
relationFlatFieldMetadatas,
};
};
@@ -3,7 +3,6 @@ import {
extractAndSanitizeObjectStringFields,
isDefined,
} from 'twenty-shared/utils';
import { v4 } from 'uuid';
import { type UpdateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input';
import {
@@ -12,18 +11,14 @@ import {
} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { FLAT_FIELD_METADATA_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-editable-properties.constant';
import { type FieldInputTranspilationResult } from 'src/engine/metadata-modules/flat-field-metadata/types/field-input-transpilation-result.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { computeFlatFieldMetadataRelatedFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/compute-flat-field-metadata-related-flat-field-metadata.util';
import { computeFlatFieldToUpdateAndRelatedFlatFieldToUpdate } from 'src/engine/metadata-modules/flat-field-metadata/utils/compute-flat-field-to-update-and-related-flat-field-to-update.util';
import {
FLAT_FIELD_METADATA_UPDATE_EMPTY_SIDE_EFFECTS,
type FlatFieldMetadataUpdateSideEffects,
handleFlatFieldMetadataUpdateSideEffect,
} from 'src/engine/metadata-modules/flat-field-metadata/utils/handle-flat-field-metadata-update-side-effect.util';
import { sanitizeRawUpdateFieldInput } from 'src/engine/metadata-modules/flat-field-metadata/utils/sanitize-raw-update-field-input';
import { isStandardMetadata } from 'src/engine/metadata-modules/utils/is-standard-metadata.util';
import { mergeUpdateInExistingRecord } from 'src/utils/merge-update-in-existing-record.util';
type FromUpdateFieldInputToFlatFieldMetadataArgs = {
updateFieldInput: UpdateFieldInput;
@@ -73,13 +68,6 @@ export const fromUpdateFieldInputToFlatFieldMetadata = ({
};
}
const isStandardField = isStandardMetadata(existingFlatFieldMetadataToUpdate);
const { standardOverrides, updatedEditableFieldProperties } =
sanitizeRawUpdateFieldInput({
existingFlatFieldMetadata: existingFlatFieldMetadataToUpdate,
rawUpdateFieldInput,
});
const flatObjectMetadata = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: existingFlatFieldMetadataToUpdate.objectMetadataId,
flatEntityMaps: existingFlatObjectMetadataMaps,
@@ -92,124 +80,100 @@ export const fromUpdateFieldInputToFlatFieldMetadata = ({
);
}
const relatedFlatFieldMetadatasToUpdate =
computeFlatFieldMetadataRelatedFlatFieldMetadata({
flatFieldMetadata: existingFlatFieldMetadataToUpdate,
const { flatFieldMetadataFromTo, relatedFlatFieldMetadatasFromTo } =
computeFlatFieldToUpdateAndRelatedFlatFieldToUpdate({
flatFieldMetadataMaps,
flatObjectMetadata,
fromFlatFieldMetadata: existingFlatFieldMetadataToUpdate,
rawUpdateFieldInput,
});
const flatFieldMetadatasToUpdate = [
existingFlatFieldMetadataToUpdate,
...relatedFlatFieldMetadatasToUpdate,
];
const initialAccumulator: FlatFieldMetadataAndIndexToUpdate = {
...structuredClone(FLAT_FIELD_METADATA_UPDATE_EMPTY_SIDE_EFFECTS),
flatFieldMetadatasToUpdate: [],
};
updatedEditableFieldProperties.options = !isDefined(
updatedEditableFieldProperties.options,
)
? updatedEditableFieldProperties.options
: updatedEditableFieldProperties.options.map((option) => ({
id: v4(),
...option,
}));
const optimisticiallyUpdatedFlatFieldMetadatas = [
flatFieldMetadataFromTo,
...relatedFlatFieldMetadatasFromTo,
].reduce<FlatFieldMetadataAndIndexToUpdate>(
(accumulator, { fromFlatFieldMetadata, toFlatFieldMetadata }) => {
const {
flatViewGroupsToCreate,
flatViewGroupsToDelete,
flatViewGroupsToUpdate,
flatIndexMetadatasToUpdate,
flatViewFiltersToDelete,
flatViewFiltersToUpdate,
flatIndexMetadatasToCreate,
flatIndexMetadatasToDelete,
flatViewsToDelete,
flatViewFieldsToDelete,
flatViewsToUpdate,
} = handleFlatFieldMetadataUpdateSideEffect({
flatViewFilterMaps,
flatViewGroupMaps,
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
fromFlatFieldMetadata,
flatFieldMetadataMaps,
flatIndexMaps,
toFlatFieldMetadata,
flatViewMaps,
flatViewFieldMaps,
});
const optimisticiallyUpdatedFlatFieldMetadatas =
flatFieldMetadatasToUpdate.reduce<FlatFieldMetadataAndIndexToUpdate>(
(accumulator, fromFlatFieldMetadata) => {
const toFlatFieldMetadata = {
...mergeUpdateInExistingRecord({
existing: fromFlatFieldMetadata,
properties:
FLAT_FIELD_METADATA_EDITABLE_PROPERTIES[
isStandardField ? 'standard' : 'custom'
],
update: updatedEditableFieldProperties,
}),
standardOverrides,
};
const {
flatViewGroupsToCreate,
flatViewGroupsToDelete,
flatViewGroupsToUpdate,
flatIndexMetadatasToUpdate,
flatViewFiltersToDelete,
flatViewFiltersToUpdate,
flatIndexMetadatasToCreate,
flatIndexMetadatasToDelete,
flatViewsToDelete,
flatViewFieldsToDelete,
flatViewsToUpdate,
} = handleFlatFieldMetadataUpdateSideEffect({
flatViewFilterMaps,
flatViewGroupMaps,
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
fromFlatFieldMetadata,
flatFieldMetadataMaps,
flatIndexMaps,
return {
flatFieldMetadatasToUpdate: [
...accumulator.flatFieldMetadatasToUpdate,
toFlatFieldMetadata,
flatViewMaps,
flatViewFieldMaps,
});
return {
flatFieldMetadatasToUpdate: [
...accumulator.flatFieldMetadatasToUpdate,
toFlatFieldMetadata,
],
flatIndexMetadatasToUpdate: [
...accumulator.flatIndexMetadatasToUpdate,
...flatIndexMetadatasToUpdate,
],
flatViewFiltersToDelete: [
...accumulator.flatViewFiltersToDelete,
...flatViewFiltersToDelete,
],
flatViewFiltersToUpdate: [
...accumulator.flatViewFiltersToUpdate,
...flatViewFiltersToUpdate,
],
flatViewGroupsToCreate: [
...accumulator.flatViewGroupsToCreate,
...flatViewGroupsToCreate,
],
flatViewGroupsToDelete: [
...accumulator.flatViewGroupsToDelete,
...flatViewGroupsToDelete,
],
flatViewGroupsToUpdate: [
...accumulator.flatViewGroupsToUpdate,
...flatViewGroupsToUpdate,
],
flatIndexMetadatasToDelete: [
...accumulator.flatIndexMetadatasToDelete,
...flatIndexMetadatasToDelete,
],
flatIndexMetadatasToCreate: [
...accumulator.flatIndexMetadatasToCreate,
...flatIndexMetadatasToCreate,
],
flatViewsToDelete: [
...accumulator.flatViewsToDelete,
...flatViewsToDelete,
],
flatViewFieldsToDelete: [
...accumulator.flatViewFieldsToDelete,
...flatViewFieldsToDelete,
],
flatViewsToUpdate: [
...accumulator.flatViewsToUpdate,
...flatViewsToUpdate,
],
};
},
initialAccumulator,
);
],
flatIndexMetadatasToUpdate: [
...accumulator.flatIndexMetadatasToUpdate,
...flatIndexMetadatasToUpdate,
],
flatViewFiltersToDelete: [
...accumulator.flatViewFiltersToDelete,
...flatViewFiltersToDelete,
],
flatViewFiltersToUpdate: [
...accumulator.flatViewFiltersToUpdate,
...flatViewFiltersToUpdate,
],
flatViewGroupsToCreate: [
...accumulator.flatViewGroupsToCreate,
...flatViewGroupsToCreate,
],
flatViewGroupsToDelete: [
...accumulator.flatViewGroupsToDelete,
...flatViewGroupsToDelete,
],
flatViewGroupsToUpdate: [
...accumulator.flatViewGroupsToUpdate,
...flatViewGroupsToUpdate,
],
flatIndexMetadatasToDelete: [
...accumulator.flatIndexMetadatasToDelete,
...flatIndexMetadatasToDelete,
],
flatIndexMetadatasToCreate: [
...accumulator.flatIndexMetadatasToCreate,
...flatIndexMetadatasToCreate,
],
flatViewsToDelete: [
...accumulator.flatViewsToDelete,
...flatViewsToDelete,
],
flatViewFieldsToDelete: [
...accumulator.flatViewFieldsToDelete,
...flatViewFieldsToDelete,
],
flatViewsToUpdate: [
...accumulator.flatViewsToUpdate,
...flatViewsToUpdate,
],
};
},
initialAccumulator,
);
return {
status: 'success',
@@ -1,11 +1,11 @@
import { type FromTo } from 'twenty-shared/types';
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { findFieldRelatedIndexes } from 'src/engine/metadata-modules/flat-field-metadata/utils/find-field-related-index.util';
import { generateIndexForFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/generate-index-for-flat-field-metadata.util';
import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
import { recomputeIndexOnFlatFieldMetadataNameUpdate } from 'src/engine/metadata-modules/flat-field-metadata/utils/recompute-index-on-flat-field-metadata-name-update.util';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
@@ -52,7 +52,7 @@ export const handleIndexChangesDuringFieldUpdate = ({
flatEntityId: fromFlatFieldMetadata.objectMetadataId,
});
const relatedIndexes = findRelatedIndexes({
const relatedIndexes = findFieldRelatedIndexes({
flatFieldMetadata: fromFlatFieldMetadata,
flatObjectMetadata,
flatIndexMaps,
@@ -81,27 +81,6 @@ const hasIndexRelevantChanges = ({
fromFlatFieldMetadata.name !== toFlatFieldMetadata.name ||
fromFlatFieldMetadata.isUnique !== toFlatFieldMetadata.isUnique;
const findRelatedIndexes = ({
flatFieldMetadata,
flatObjectMetadata,
flatIndexMaps,
}: {
flatFieldMetadata: FlatFieldMetadata;
flatObjectMetadata: FlatObjectMetadata;
flatIndexMaps: FlatEntityMaps<FlatIndexMetadata>;
}): FlatIndexMetadata[] => {
const objectIndexes = findManyFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityMaps: flatIndexMaps,
flatEntityIds: flatObjectMetadata.indexMetadataIds,
});
return objectIndexes.filter((index) =>
index.flatIndexFieldMetadatas.some(
(indexField) => indexField.fieldMetadataId === flatFieldMetadata.id,
),
);
};
const handleNoExistingIndexes = ({
toFlatFieldMetadata,
flatObjectMetadata,
@@ -139,7 +118,10 @@ const handleExistingIndexes = ({
FlatFieldMetadata,
'flatFieldMetadata'
>): FieldMetadataUpdateIndexSideEffect => {
if (toFlatFieldMetadata.isUnique === false) {
if (
toFlatFieldMetadata.isUnique === false &&
!isMorphOrRelationFlatFieldMetadata(fromFlatFieldMetadata)
) {
const expectedUniqueIndex = generateIndexForFlatFieldMetadata({
flatFieldMetadata: {
...fromFlatFieldMetadata,
@@ -160,7 +142,6 @@ const handleExistingIndexes = ({
: [],
};
}
const updatedIndexes = recomputeIndexOnFlatFieldMetadataNameUpdate({
flatFieldMetadataMaps,
flatObjectMetadata,
@@ -42,13 +42,11 @@ export const recomputeIndexOnFlatFieldMetadataNameUpdate = ({
},
);
return relatedFlatIndexMetadata.map<FlatIndexMetadata>((flatIndex) => {
const newIndex = generateFlatIndexMetadataWithNameOrThrow({
return relatedFlatIndexMetadata.map((flatIndex) =>
generateFlatIndexMetadataWithNameOrThrow({
flatIndex,
flatObjectMetadata,
objectFlatFieldMetadatas: optimisticObjectFlatFieldMetadatas,
});
return newIndex;
});
}),
);
};
@@ -2,6 +2,7 @@ import {
extractAndSanitizeObjectStringFields,
isDefined,
} from 'twenty-shared/utils';
import { v4 } from 'uuid';
import { FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES } from 'src/engine/metadata-modules/field-metadata/constants/field-metadata-standard-overrides-properties.constant';
import { type UpdateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input';
@@ -33,6 +34,15 @@ export const sanitizeRawUpdateFieldInput = ({
],
);
updatedEditableFieldProperties.options = !isDefined(
updatedEditableFieldProperties.options,
)
? updatedEditableFieldProperties.options
: updatedEditableFieldProperties.options.map((option) => ({
id: v4(),
...option,
}));
if (!isStandardField) {
return {
updatedEditableFieldProperties,