Files
twenty/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/handle-enum-flat-field-metadata-update-side-effects.util.ts
T
Paul Rastoin 48c8fa6809 Refactor workspace migration update action (#17701)
# Introduction
Removing:
- `from` property from actions definition, as it's a legitimate source
of truth. The stored comparison might have been compromised since action
generation. If from is needed it should be computed from the optimistic
cache at runner lvl
- Removed the `FlatEntityPropertyUpdates` Array complexity in favor of

From
```ts
export type PropertyUpdate<T, P extends keyof T> = {
  property: P;
} & FromTo<T[P]>;
```

To
```ts
export type FlatEntityUpdate<T extends AllMetadataName> = Partial<
  Pick<
    MetadataFlatEntity<T>,
    Extract<FlatEntityPropertiesToCompare<T>, keyof MetadataFlatEntity<T>>
  >
>;
```

## New interactions
From
```ts
    const positionUpdate = findFlatEntityPropertyUpdate({
      flatEntityUpdates,
      property: 'position',
    });

    if (
      isDefined(positionUpdate) &&
      (!Number.isInteger(positionUpdate.to) || positionUpdate.to < 0)
    ) {


   const toFlatNavigationMenuItem = {
      ...fromFlatNavigationMenuItem,
      ...fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
        updates: flatEntityUpdates,
      }),
    };
```

To
```ts
    const positionUpdate = flatEntityUpdate.position;
    if (
      isDefined(positionUpdate) &&
      (!Number.isInteger(positionUpdate) || positionUpdate < 0)
    ) {

    const toFlatNavigationMenuItem = {
      ...fromFlatNavigationMenuItem,
      ...flatEntityUpdate,
    };
```

## `SanitizeFlatEntityUpdate`
Enforcing the `flatEntityUpdate` to only contains comparable properties
per flat entity by striping out all unexpected keys
In the future we will also move the whole validation at runner lvl at
some point

```ts
export const sanitizeFlatEntityUpdate = <T extends AllMetadataName>({
  flatEntityUpdate,
  metadataName,
}: {
  flatEntityUpdate: FlatEntityUpdate<T>;
  metadataName: T;
}): FlatEntityUpdate<T> => {
  const { propertiesToCompare } =
    ALL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY[metadataName];

  const initialAccumulator: FlatEntityUpdate<T> = {};

  return propertiesToCompare.reduce((accumulator, property) => {
    const updatedValue =
      flatEntityUpdate[property as MetadataFlatEntityComparableProperties<T>];

    if (updatedValue === undefined) {
      return accumulator;
    }

    return {
      ...accumulator,
      [property]: updatedValue,
    };
  }, initialAccumulator);
};
```
2026-02-04 13:50:46 +00:00

95 lines
3.6 KiB
TypeScript

import { type EnumFieldMetadataType, type FromTo } from 'twenty-shared/types';
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import {
type FlatViewFiltersToDeleteAndUpdate,
recomputeViewFiltersOnFlatFieldMetadataOptionsUpdate,
} from 'src/engine/metadata-modules/flat-field-metadata/utils/recompute-view-filters-on-flat-field-metadata-options-update.util';
import { recomputeViewGroupsOnEnumFlatFieldMetadataIsNullableUpdate } from 'src/engine/metadata-modules/flat-field-metadata/utils/recompute-view-groups-on-enum-flat-field-metadata-is-nullable-update.util';
import {
type FlatViewGroupsToDeleteUpdateAndCreate,
recomputeViewGroupsOnFlatFieldMetadataOptionsUpdate,
} from 'src/engine/metadata-modules/flat-field-metadata/utils/recompute-view-groups-on-flat-field-metadata-options-update.util';
type HandleEnumFlatFieldMetadataOptionsUpdateSideEffectsArgs = FromTo<
FlatFieldMetadata<EnumFieldMetadataType>,
'flatFieldMetadata'
> &
Pick<
AllFlatEntityMaps,
'flatViewFilterMaps' | 'flatViewGroupMaps' | 'flatViewMaps'
>;
type EnumFieldMetadataSideEffectResult = FlatViewGroupsToDeleteUpdateAndCreate &
FlatViewFiltersToDeleteAndUpdate;
const EMPTY_ENUM_FIELD_METADATA_SIDE_EFFECT_RESULT: EnumFieldMetadataSideEffectResult =
{
flatViewFiltersToDelete: [],
flatViewFiltersToUpdate: [],
flatViewGroupsToCreate: [],
flatViewGroupsToDelete: [],
flatViewGroupsToUpdate: [],
};
export const handleEnumFlatFieldMetadataUpdateSideEffects = ({
fromFlatFieldMetadata,
toFlatFieldMetadata,
flatViewFilterMaps,
flatViewGroupMaps,
flatViewMaps,
}: HandleEnumFlatFieldMetadataOptionsUpdateSideEffectsArgs): EnumFieldMetadataSideEffectResult => {
const sideEffectResult = structuredClone(
EMPTY_ENUM_FIELD_METADATA_SIDE_EFFECT_RESULT,
);
if (
JSON.stringify(fromFlatFieldMetadata.options) !==
JSON.stringify(toFlatFieldMetadata.options)
) {
const optionsPropertyUpdate =
toFlatFieldMetadata.options as FlatFieldMetadata<EnumFieldMetadataType>['options'];
const { flatViewFiltersToDelete, flatViewFiltersToUpdate } =
recomputeViewFiltersOnFlatFieldMetadataOptionsUpdate({
flatViewFilterMaps,
fromFlatFieldMetadata,
toOptions: optionsPropertyUpdate,
});
sideEffectResult.flatViewFiltersToDelete.push(...flatViewFiltersToDelete);
sideEffectResult.flatViewFiltersToUpdate.push(...flatViewFiltersToUpdate);
const {
flatViewGroupsToCreate,
flatViewGroupsToDelete,
flatViewGroupsToUpdate,
} = recomputeViewGroupsOnFlatFieldMetadataOptionsUpdate({
flatViewMaps,
flatViewGroupMaps,
fromFlatFieldMetadata,
toOptions: optionsPropertyUpdate,
});
sideEffectResult.flatViewGroupsToCreate.push(...flatViewGroupsToCreate);
sideEffectResult.flatViewGroupsToDelete.push(...flatViewGroupsToDelete);
sideEffectResult.flatViewGroupsToUpdate.push(...flatViewGroupsToUpdate);
}
if (fromFlatFieldMetadata.isNullable !== toFlatFieldMetadata.isNullable) {
const { flatViewGroupsToCreate, flatViewGroupsToDelete } =
recomputeViewGroupsOnEnumFlatFieldMetadataIsNullableUpdate({
flatViewMaps,
flatViewGroupMaps,
fromFlatFieldMetadata,
toFlatFieldMetadata,
});
sideEffectResult.flatViewGroupsToCreate.push(...flatViewGroupsToCreate);
sideEffectResult.flatViewGroupsToDelete.push(...flatViewGroupsToDelete);
}
return sideEffectResult;
};