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);
};
```
This commit is contained in:
Paul Rastoin
2026-02-04 14:50:46 +01:00
committed by GitHub
parent b03e3772e6
commit 48c8fa6809
89 changed files with 813 additions and 800 deletions
+1 -1
View File
@@ -913,7 +913,7 @@ export class WorkspaceMigrationMyEntityActionsBuilderService extends WorkspaceEn
type: 'update',
metadataName: 'myEntity',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdates,
};
return {
@@ -1,10 +1,11 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type FlatEntityPropertiesToCompare } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-to-compare.type';
import { type FlatEntityPropertyUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-property-update.type';
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
export type FlatEntityPropertiesUpdates<
T extends AllMetadataName,
K extends FlatEntityPropertiesToCompare<T> = FlatEntityPropertiesToCompare<T>,
> = Array<FlatEntityPropertyUpdate<T, Extract<K, keyof MetadataFlatEntity<T>>>>;
export type MetadataFlatEntityComparableProperties<T extends AllMetadataName> =
Extract<FlatEntityPropertiesToCompare<T>, keyof MetadataFlatEntity<T>>;
export type FlatEntityUpdate<T extends AllMetadataName> = Partial<
Pick<MetadataFlatEntity<T>, MetadataFlatEntityComparableProperties<T>>
>;
@@ -1,13 +0,0 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type FlatEntityPropertiesToCompare } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-to-compare.type';
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
import { type PropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/types/property-update.type';
export type FlatEntityPropertyUpdate<
T extends AllMetadataName,
K extends FlatEntityPropertiesToCompare<T> = FlatEntityPropertiesToCompare<T>,
> = PropertyUpdate<
MetadataFlatEntity<T>,
Extract<K, keyof MetadataFlatEntity<T>>
>;
@@ -1,21 +1,13 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`compareTwoFlatEntity It should detect flat field metadata isActive diff from true to false 1`] = `
[
{
"from": true,
"property": "isActive",
"to": false,
},
]
{
"isActive": false,
}
`;
exports[`compareTwoFlatEntity It should detect flat field metadata isActive diff from true to false 2`] = `
[
{
"from": false,
"property": "isActive",
"to": true,
},
]
{
"isActive": true,
}
`;
@@ -73,7 +73,7 @@ describe('compareTwoFlatEntity', () => {
});
expect(result).toMatchSnapshot(
extractRecordIdsAndDatesAsExpectAny(result),
extractRecordIdsAndDatesAsExpectAny({ ...result }),
);
},
);
@@ -1,10 +1,10 @@
import diff from 'microdiff';
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type FromTo } from 'twenty-shared/types';
import { parseJson } from 'twenty-shared/utils';
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type FlatEntityPropertiesToCompare } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-to-compare.type';
import { type FlatEntityPropertiesUpdates } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { type FlatEntityUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
import { transformFlatEntityForComparison } from 'src/engine/metadata-modules/flat-entity/utils/transform-flat-entity-for-comparison.util';
@@ -23,7 +23,7 @@ export const compareTwoFlatEntity = <
}: FromTo<MetadataFlatEntity<T>, 'flatEntity'> & {
propertiesToCompare: readonly PToCompare[];
propertiesToStringify: readonly PJsonB[];
}): FlatEntityPropertiesUpdates<T> => {
}): FlatEntityUpdate<T> | undefined => {
const [transformedFromFlatEntity, transformedToFlatEntity] = [
fromFlatEntity,
toFlatEntity,
@@ -40,37 +40,39 @@ export const compareTwoFlatEntity = <
transformedToFlatEntity,
);
return flatEntityDifferences.flatMap<FlatEntityPropertiesUpdates<T>[number]>(
(difference) => {
switch (difference.type) {
case 'CHANGE': {
const { oldValue, path, value } = difference;
const property = path[0] as PToCompare;
const isJsonb = propertiesToStringify.includes(
property as unknown as PJsonB,
);
if (flatEntityDifferences.length === 0) {
return undefined;
}
if (isJsonb) {
return {
from: parseJson(oldValue),
to: parseJson(value),
property,
};
}
const initialAccumulator: FlatEntityUpdate<T> = {};
return flatEntityDifferences.reduce((accumulator, difference) => {
switch (difference.type) {
case 'CHANGE': {
const { path, value } = difference;
const property = path[0] as PToCompare;
const isJsonb = propertiesToStringify.includes(
property as unknown as PJsonB,
);
if (isJsonb) {
return {
from: oldValue,
to: value,
property,
...accumulator,
[property]: parseJson(value),
};
}
case 'CREATE':
case 'REMOVE':
default: {
// Should never occur, we should only provide null never undefined and so on
return [];
}
return {
...accumulator,
[property]: value,
};
}
},
);
case 'CREATE':
case 'REMOVE':
default: {
// Should never occur, we should only provide null never undefined and so on
return accumulator;
}
}
}, initialAccumulator);
};
@@ -5,7 +5,7 @@ import { isDefined } from 'class-validator';
import { FieldMetadataType } from 'twenty-shared/types';
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
import { FlatEntityPropertiesUpdates } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { FlatEntityUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { type FlatFieldMetadataTypeValidator } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-type-validator.type';
import { FlatFieldMetadataValidationError } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-validation-error.type';
import { validateEnumSelectFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-enum-flat-field-metadata.util';
@@ -18,7 +18,7 @@ const DEFAULT_NO_VALIDATION = (): FlatFieldMetadataValidationError[] => [];
export type GenericValidateFlatFieldMetadataTypeSpecificitiesArgs =
FlatEntityValidationArgs<'fieldMetadata'> & {
updates?: FlatEntityPropertiesUpdates<'fieldMetadata'>;
update?: FlatEntityUpdate<'fieldMetadata'>;
};
const rejectUserCreation = (
@@ -29,7 +29,7 @@ const rejectUserCreation = (
return (
args: GenericValidateFlatFieldMetadataTypeSpecificitiesArgs,
): FlatFieldMetadataValidationError[] => {
const isCreation = !isDefined(args.updates);
const isCreation = !isDefined(args.update);
const isCustomField = args.flatEntityToValidate.isCustom;
if (isCreation && isCustomField) {
@@ -11,7 +11,6 @@ import {
type FlatViewGroupsToDeleteUpdateAndCreate,
recomputeViewGroupsOnFlatFieldMetadataOptionsUpdate,
} from 'src/engine/metadata-modules/flat-field-metadata/utils/recompute-view-groups-on-flat-field-metadata-options-update.util';
import { type PropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/types/property-update.type';
type HandleEnumFlatFieldMetadataOptionsUpdateSideEffectsArgs = FromTo<
FlatFieldMetadata<EnumFieldMetadataType>,
@@ -49,20 +48,14 @@ export const handleEnumFlatFieldMetadataUpdateSideEffects = ({
JSON.stringify(fromFlatFieldMetadata.options) !==
JSON.stringify(toFlatFieldMetadata.options)
) {
const optionsPropertyUpdate: PropertyUpdate<
FlatFieldMetadata<EnumFieldMetadataType>,
'options'
> = {
from: fromFlatFieldMetadata.options,
property: 'options',
to: toFlatFieldMetadata.options,
};
const optionsPropertyUpdate =
toFlatFieldMetadata.options as FlatFieldMetadata<EnumFieldMetadataType>['options'];
const { flatViewFiltersToDelete, flatViewFiltersToUpdate } =
recomputeViewFiltersOnFlatFieldMetadataOptionsUpdate({
flatViewFilterMaps,
fromFlatFieldMetadata,
update: optionsPropertyUpdate,
toOptions: optionsPropertyUpdate,
});
sideEffectResult.flatViewFiltersToDelete.push(...flatViewFiltersToDelete);
@@ -76,7 +69,7 @@ export const handleEnumFlatFieldMetadataUpdateSideEffects = ({
flatViewMaps,
flatViewGroupMaps,
fromFlatFieldMetadata,
update: optionsPropertyUpdate,
toOptions: optionsPropertyUpdate,
});
sideEffectResult.flatViewGroupsToCreate.push(...flatViewGroupsToCreate);
@@ -11,11 +11,10 @@ import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metada
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { compareTwoFlatFieldMetadataEnumOptions } from 'src/engine/metadata-modules/flat-field-metadata/utils/compare-two-flat-field-metadata-enum-options.util';
import { type FlatViewFilter } from 'src/engine/metadata-modules/flat-view-filter/types/flat-view-filter.type';
import { type PropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/types/property-update.type';
type RecomputeViewFiltersOnFlatFieldMetadataOptionsUpdateArgs = {
fromFlatFieldMetadata: FlatFieldMetadata<EnumFieldMetadataType>;
update: PropertyUpdate<FlatFieldMetadata<EnumFieldMetadataType>, 'options'>;
toOptions: FlatFieldMetadata<EnumFieldMetadataType>['options'];
} & Pick<AllFlatEntityMaps, 'flatViewFilterMaps'>;
export type FlatViewFiltersToDeleteAndUpdate = {
@@ -25,7 +24,7 @@ export type FlatViewFiltersToDeleteAndUpdate = {
export const recomputeViewFiltersOnFlatFieldMetadataOptionsUpdate = ({
flatViewFilterMaps,
fromFlatFieldMetadata,
update,
toOptions,
}: RecomputeViewFiltersOnFlatFieldMetadataOptionsUpdateArgs): FlatViewFiltersToDeleteAndUpdate => {
const flatViewFiltersToCreateAndUpdate: FlatViewFiltersToDeleteAndUpdate = {
flatViewFiltersToDelete: [],
@@ -38,7 +37,7 @@ export const recomputeViewFiltersOnFlatFieldMetadataOptionsUpdate = ({
} = compareTwoFlatFieldMetadataEnumOptions({
compareLabel: false,
fromOptions: fromFlatFieldMetadata.options,
toOptions: update.to,
toOptions,
});
if (
@@ -13,11 +13,10 @@ import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-m
import { compareTwoFlatFieldMetadataEnumOptions } from 'src/engine/metadata-modules/flat-field-metadata/utils/compare-two-flat-field-metadata-enum-options.util';
import { type FlatViewGroup } from 'src/engine/metadata-modules/flat-view-group/types/flat-view-group.type';
import { reduceFlatViewGroupsByViewId } from 'src/engine/metadata-modules/flat-view-group/utils/reduce-flat-view-groups-by-view-id.util';
import { type PropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/types/property-update.type';
type RecomputeViewGroupsOnFlatFieldMetadataOptionsUpdateArgs = {
fromFlatFieldMetadata: FlatFieldMetadata<EnumFieldMetadataType>;
update: PropertyUpdate<FlatFieldMetadata<EnumFieldMetadataType>, 'options'>;
toOptions: FlatFieldMetadata<EnumFieldMetadataType>['options'];
} & Pick<AllFlatEntityMaps, 'flatViewMaps' | 'flatViewGroupMaps'>;
export type FlatViewGroupsToDeleteUpdateAndCreate = {
@@ -29,7 +28,7 @@ export const recomputeViewGroupsOnFlatFieldMetadataOptionsUpdate = ({
flatViewMaps,
flatViewGroupMaps,
fromFlatFieldMetadata,
update,
toOptions,
}: RecomputeViewGroupsOnFlatFieldMetadataOptionsUpdateArgs): FlatViewGroupsToDeleteUpdateAndCreate => {
const {
deleted: deletedFieldMetadataOptions,
@@ -38,7 +37,7 @@ export const recomputeViewGroupsOnFlatFieldMetadataOptionsUpdate = ({
} = compareTwoFlatFieldMetadataEnumOptions({
compareLabel: false,
fromOptions: fromFlatFieldMetadata.options,
toOptions: update.to,
toOptions,
});
const flatViewsAffected = findManyFlatEntityByIdInFlatEntityMapsOrThrow({
@@ -3,7 +3,7 @@ import { isDefined, isValidUuid } from 'twenty-shared/utils';
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
import { type MorphOrRelationFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/types/morph-or-relation-field-metadata-type.type';
import { type FlatEntityPropertiesUpdates } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { type FlatEntityUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
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';
@@ -12,14 +12,12 @@ import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/
import { validateJunctionTargetSettings } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-junction-target-settings.util';
import { validateMorphOrRelationFlatFieldJoinColumName } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-morph-or-relation-flat-field-join-column-name.util';
import { validateMorphOrRelationFlatFieldOnDelete } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-morph-or-relation-flat-field-on-delete.util';
import { type PropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/types/property-update.type';
import { findFlatEntityPropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/utils/find-flat-entity-property-update.util';
type ValidateMorphOrRelationFlatFieldMetadataUpdatesArgs = Omit<
FlatFieldMetadataTypeValidationArgs<MorphOrRelationFieldMetadataType>,
'updates'
> & {
updates: FlatEntityPropertiesUpdates<'fieldMetadata'>;
update: FlatEntityUpdate<'fieldMetadata'>;
};
export const validateMorphOrRelationFlatFieldMetadataUpdates = ({
@@ -28,28 +26,44 @@ export const validateMorphOrRelationFlatFieldMetadataUpdates = ({
flatFieldMetadataMaps,
flatObjectMetadataMaps,
},
updates,
update,
buildOptions,
}: ValidateMorphOrRelationFlatFieldMetadataUpdatesArgs): FlatFieldMetadataValidationError[] => {
const errors: FlatFieldMetadataValidationError[] = [];
const settingsUpdate = findFlatEntityPropertyUpdate({
flatEntityUpdates: updates,
property: 'settings',
}) as
| PropertyUpdate<
FlatFieldMetadata<MorphOrRelationFieldMetadataType>,
'settings'
>
| undefined;
const fromFlatFieldMetadata = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: flatFieldMetadataToValidate.id,
flatEntityMaps: flatFieldMetadataMaps,
});
const toSettings = settingsUpdate?.to;
const fromSettings = settingsUpdate?.from;
if (!isDefined(fromFlatFieldMetadata)) {
return [
{
code: FieldMetadataExceptionCode.FIELD_METADATA_NOT_FOUND,
message: 'Could not found updated field metadata',
userFriendlyMessage: msg`Could not found updated field metadata`,
},
];
}
if (!isMorphOrRelationFlatFieldMetadata(fromFlatFieldMetadata)) {
return [
{
code: FieldMetadataExceptionCode.FIELD_METADATA_NOT_FOUND,
message: 'Udpated field is not a morph relation or a relation',
userFriendlyMessage: msg`Udpated field is not a morph relation or a relation`,
},
];
}
const toSettings = update.settings as
| FlatFieldMetadata<MorphOrRelationFieldMetadataType>['settings']
| undefined;
const fromSettings = fromFlatFieldMetadata.settings;
const isJoinColumnNameUpdated =
isDefined(settingsUpdate) &&
isDefined(toSettings?.joinColumnName) &&
isDefined(fromSettings?.joinColumnName) &&
isDefined(fromSettings.joinColumnName) &&
toSettings.joinColumnName !== fromSettings.joinColumnName;
if (isJoinColumnNameUpdated) {
@@ -80,7 +94,7 @@ export const validateMorphOrRelationFlatFieldMetadata = ({
flatFieldMetadataMaps,
flatObjectMetadataMaps,
},
updates,
update,
remainingFlatEntityMapsToValidate,
buildOptions,
workspaceId,
@@ -192,7 +206,7 @@ export const validateMorphOrRelationFlatFieldMetadata = ({
}
// TODO prastoin refactor FlatFieldMetadataTypeValidator to implement two code flow: create and update https://github.com/twentyhq/core-team-issues/issues/2044
if (isDefined(updates)) {
if (isDefined(update)) {
errors.push(
...validateMorphOrRelationFlatFieldMetadataUpdates({
flatEntityToValidate: flatFieldMetadataToValidate,
@@ -202,7 +216,7 @@ export const validateMorphOrRelationFlatFieldMetadata = ({
},
remainingFlatEntityMapsToValidate,
workspaceId,
updates,
update,
buildOptions,
additionalCacheDataMaps,
}),
@@ -3,7 +3,7 @@ import { Injectable } from '@nestjs/common';
import { msg } from '@lingui/core/macro';
import { isDefined } from 'twenty-shared/utils';
import { FlatEntityPropertiesUpdates } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { FlatEntityUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import {
type FlatPageLayoutWidgetTypeValidatorForCreation,
type FlatPageLayoutWidgetTypeValidatorForUpdate,
@@ -24,7 +24,7 @@ import { FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace
export type GenericValidateFlatPageLayoutWidgetTypeSpecificitiesArgs =
FlatEntityValidationArgs<'pageLayoutWidget'> & {
updates?: FlatEntityPropertiesUpdates<'pageLayoutWidget'>;
update?: FlatEntityUpdate<'pageLayoutWidget'>;
};
export type ValidateFlatPageLayoutWidgetTypeSpecificitiesForCreationArgs =
@@ -32,7 +32,7 @@ export type ValidateFlatPageLayoutWidgetTypeSpecificitiesForCreationArgs =
export type ValidateFlatPageLayoutWidgetTypeSpecificitiesForUpdateArgs =
FlatEntityValidationArgs<'pageLayoutWidget'> & {
updates: FlatEntityPropertiesUpdates<'pageLayoutWidget'>;
update: FlatEntityUpdate<'pageLayoutWidget'>;
};
@Injectable()
@@ -1,5 +0,0 @@
import { type FromTo } from 'twenty-shared/types';
export type PropertyUpdate<T, P extends keyof T> = {
property: P;
} & FromTo<T[P]>;
@@ -1,4 +1,4 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect a created entity 1`] = `
{
@@ -152,13 +152,9 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect an upd
"byUniversalIdentifier": {
"universal-identifier-1": {
"id": "field-id-1",
"updates": [
{
"from": false,
"property": "isActive",
"to": true,
},
],
"update": {
"isActive": true,
},
},
},
},
@@ -281,13 +277,9 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect create
"byUniversalIdentifier": {
"universal-identifier-1": {
"id": "field-id-1",
"updates": [
{
"from": true,
"property": "isActive",
"to": false,
},
],
"update": {
"isActive": false,
},
},
},
},
@@ -21,37 +21,25 @@ describe('aggregateOrchestratorActionsReportDeprioritizeSearchVectorUpdateFieldA
type: 'update',
metadataName: 'fieldMetadata',
universalIdentifier: 'search-vector-field-1',
updates: [
{
property: 'label',
from: 'Search Vector',
to: 'Updated Search Vector',
},
],
update: {
label: 'Updated Search Vector',
},
} satisfies UniversalUpdateFieldAction,
{
type: 'update',
metadataName: 'fieldMetadata',
universalIdentifier: 'regular-field-1',
updates: [
{
property: 'label',
from: 'First Name',
to: 'Updated First Name',
},
],
update: {
label: 'Updated First Name',
},
} satisfies UniversalUpdateFieldAction,
{
type: 'update',
metadataName: 'fieldMetadata',
universalIdentifier: 'regular-field-2',
updates: [
{
property: 'label',
from: 'Last Name',
to: 'Updated Last Name',
},
],
update: {
label: 'Updated Last Name',
},
} satisfies UniversalUpdateFieldAction,
],
delete: [],
@@ -1,24 +0,0 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type FlatEntityPropertiesToCompare } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-to-compare.type';
import { type FlatEntityPropertiesUpdates } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { type FlatEntityPropertyUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-property-update.type';
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
import { isPropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/utils/is-property-update.util';
export const findFlatEntityPropertyUpdate = <
T extends AllMetadataName,
P extends Extract<
FlatEntityPropertiesToCompare<T>,
keyof MetadataFlatEntity<T>
>,
>({
property,
flatEntityUpdates,
}: {
flatEntityUpdates: FlatEntityPropertiesUpdates<T>;
property: P;
}) =>
flatEntityUpdates.find((update): update is FlatEntityPropertyUpdate<T, P> =>
isPropertyUpdate(update, property),
);
@@ -6,7 +6,7 @@ import { ALL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY } from 'src/engine/
import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant';
import { type FlatEntityPropertiesToCompare } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-to-compare.type';
import { type FlatEntityPropertiesToStringify } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-to-stringify.type';
import { type FlatEntityPropertiesUpdates } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { type FlatEntityUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { type MetadataFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity-maps.type';
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
import { compareTwoFlatEntity } from 'src/engine/metadata-modules/flat-entity/utils/compare-two-flat-entity.util';
@@ -21,7 +21,7 @@ export type DeletedCreatedUpdatedMatrix<T extends AllMetadataName> = {
byUniversalIdentifier: Record<
string,
{
updates: FlatEntityPropertiesUpdates<T>;
update: FlatEntityUpdate<T>;
// TMP remove when maps is universal based
id: string;
}
@@ -88,7 +88,7 @@ export const flatEntityDeletedCreatedUpdatedMatrixDispatcher = <
if (!isDefined(toFlatEntity)) {
continue;
}
const updates = compareTwoFlatEntity({
const update = compareTwoFlatEntity({
fromFlatEntity,
toFlatEntity,
propertiesToCompare: propertiesToCompare as unknown as Extract<
@@ -101,7 +101,7 @@ export const flatEntityDeletedCreatedUpdatedMatrixDispatcher = <
>[],
});
if (updates.length === 0) {
if (!isDefined(update)) {
continue;
}
@@ -109,7 +109,7 @@ export const flatEntityDeletedCreatedUpdatedMatrixDispatcher = <
fromFlatEntity.universalIdentifier
] = {
id: toFlatEntity.id,
updates,
update,
};
}
@@ -1,8 +0,0 @@
import { type PropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/types/property-update.type';
export const isPropertyUpdate = <T, P extends keyof T>(
update: PropertyUpdate<T, keyof T>,
property: P,
): update is PropertyUpdate<T, P> => {
return update.property === property;
};
@@ -82,13 +82,13 @@ export class WorkspaceMigrationAgentActionsBuilderService extends WorkspaceEntit
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updateAgentAction: FlatUpdateAgentAction = {
type: 'update',
metadataName: 'agent',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -99,13 +99,13 @@ export class WorkspaceMigrationCommandMenuItemActionsBuilderService extends Work
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updateCommandMenuItemAction: FlatUpdateCommandMenuItemAction = {
type: 'update',
metadataName: 'commandMenuItem',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -101,13 +101,13 @@ export class WorkspaceMigrationFieldActionsBuilderService extends WorkspaceEntit
};
}
const { universalIdentifier, flatEntityUpdates } = args;
const { universalIdentifier, flatEntityUpdate } = args;
const updateFieldAction: UniversalUpdateFieldAction = {
type: 'update',
metadataName: 'fieldMetadata',
universalIdentifier,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -99,13 +99,13 @@ export class WorkspaceMigrationFrontComponentActionsBuilderService extends Works
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updateFrontComponentAction: FlatUpdateFrontComponentAction = {
type: 'update',
metadataName: 'frontComponent',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -1,6 +1,7 @@
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { type BaseFlatCreateWorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/base-flat-create-workspace-migration-action.type';
import { type BaseFlatDeleteWorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/base-flat-delete-workspace-migration-action.type';
import { type BaseFlatUpdateWorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/base-flat-update-workspace-migration-action.type';
import { type BaseUniversalDeleteWorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/base-universal-delete-workspace-migration-action.type';
export type FlatCreateIndexAction =
@@ -12,9 +13,8 @@ export type UniversalDeleteIndexAction =
export type FlatDeleteIndexAction =
BaseFlatDeleteWorkspaceMigrationAction<'index'>;
export type FlatUpdateIndexAction = {
type: 'update';
metadataName: 'index';
entityId: string;
updatedFlatEntity: FlatIndexMetadata;
};
export type FlatUpdateIndexAction =
BaseFlatUpdateWorkspaceMigrationAction<'index'> & {
// TODO document
updatedFlatEntity: FlatIndexMetadata;
};
@@ -7,13 +7,13 @@ import { isDefined } from 'twenty-shared/utils';
import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant';
import { FlatEntityMapsExceptionCode } from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { deleteFlatEntityFromFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/utils/delete-flat-entity-from-flat-entity-maps-through-mutation-or-throw.util';
import { WorkspaceEntityMigrationBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/services/workspace-entity-migration-builder.service';
import { FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-update-validation-args.type';
import { FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-validation-args.type';
import { FlatEntityValidationReturnType } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-validation-result.type';
import { FlatIndexValidatorService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-index-metadata-validator.service';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class WorkspaceMigrationIndexActionsBuilderService extends WorkspaceEntityMigrationBuilderService<
@@ -78,7 +78,7 @@ export class WorkspaceMigrationIndexActionsBuilderService extends WorkspaceEntit
protected validateFlatEntityUpdate({
optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
flatEntityId,
flatEntityUpdates,
flatEntityUpdate,
buildOptions,
workspaceId,
additionalCacheDataMaps,
@@ -128,11 +128,9 @@ export class WorkspaceMigrationIndexActionsBuilderService extends WorkspaceEntit
};
}
const updatedFlatIndex = {
const updatedFlatIndex: FlatIndexMetadata = {
...flatEntity,
...fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates: flatEntityUpdates,
}),
...flatEntityUpdate,
};
const tempOptimisticFlatIndexMaps = structuredClone(
@@ -174,7 +172,10 @@ export class WorkspaceMigrationIndexActionsBuilderService extends WorkspaceEntit
type: 'update',
metadataName: 'index',
entityId: flatEntity.id,
// Note: Index update action ignores the native update field
// As under the hood it result as a drop and create
updatedFlatEntity: updatedFlatIndex,
update: {},
},
};
}
@@ -139,13 +139,13 @@ export class WorkspaceMigrationLogicFunctionActionsBuilderService extends Worksp
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updateLogicFunctionAction: FlatUpdateLogicFunctionAction = {
type: 'update',
metadataName: 'logicFunction',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -100,13 +100,13 @@ export class WorkspaceMigrationNavigationMenuItemActionsBuilderService extends W
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updateNavigationMenuItemAction: FlatUpdateNavigationMenuItemAction = {
type: 'update',
metadataName: 'navigationMenuItem',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -95,13 +95,13 @@ export class WorkspaceMigrationObjectActionsBuilderService extends WorkspaceEnti
};
}
const { universalIdentifier, flatEntityUpdates } = args;
const { universalIdentifier, flatEntityUpdate } = args;
const updateObjectAction: UniversalUpdateObjectAction = {
type: 'update',
metadataName: 'objectMetadata',
universalIdentifier,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -99,13 +99,13 @@ export class WorkspaceMigrationPageLayoutTabActionsBuilderService extends Worksp
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updatePageLayoutTabAction: FlatUpdatePageLayoutTabAction = {
type: 'update',
metadataName: 'pageLayoutTab',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -101,13 +101,13 @@ export class WorkspaceMigrationPageLayoutWidgetActionsBuilderService extends Wor
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updatePageLayoutWidgetAction: FlatUpdatePageLayoutWidgetAction = {
type: 'update',
metadataName: 'pageLayoutWidget',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -95,13 +95,13 @@ export class WorkspaceMigrationPageLayoutActionsBuilderService extends Workspace
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updatePageLayoutAction: FlatUpdatePageLayoutAction = {
type: 'update',
metadataName: 'pageLayout',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -91,13 +91,13 @@ export class WorkspaceMigrationRoleTargetActionsBuilderService extends Workspace
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updateRoleTargetAction: FlatUpdateRoleTargetAction = {
type: 'update',
metadataName: 'roleTarget',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -82,13 +82,13 @@ export class WorkspaceMigrationRoleActionsBuilderService extends WorkspaceEntity
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updateRoleAction: FlatUpdateRoleAction = {
type: 'update',
metadataName: 'role',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -109,13 +109,13 @@ export class WorkspaceMigrationRowLevelPermissionPredicateGroupActionsBuilderSer
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updateAction: FlatUpdateRowLevelPermissionPredicateGroupAction = {
type: 'update',
metadataName: 'rowLevelPermissionPredicateGroup',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -109,13 +109,13 @@ export class WorkspaceMigrationRowLevelPermissionPredicateActionsBuilderService
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updateAction: FlatUpdateRowLevelPermissionPredicateAction = {
type: 'update',
metadataName: 'rowLevelPermissionPredicate',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -82,13 +82,13 @@ export class WorkspaceMigrationSkillActionsBuilderService extends WorkspaceEntit
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updateSkillAction: FlatUpdateSkillAction = {
type: 'update',
metadataName: 'skill',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -89,13 +89,13 @@ export class WorkspaceMigrationViewFieldActionsBuilderService extends WorkspaceE
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updateViewFieldAction: FlatUpdateViewFieldAction = {
type: 'update',
metadataName: 'viewField',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -99,13 +99,13 @@ export class WorkspaceMigrationViewFilterGroupActionsBuilderService extends Work
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updateViewFilterGroupAction: FlatUpdateViewFilterGroupAction = {
type: 'update',
metadataName: 'viewFilterGroup',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -91,13 +91,13 @@ export class WorkspaceMigrationViewFilterActionsBuilderService extends Workspace
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updateViewFilterAction: FlatUpdateViewFilterAction = {
type: 'update',
metadataName: 'viewFilter',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -91,13 +91,13 @@ export class WorkspaceMigrationViewGroupActionsBuilderService extends WorkspaceE
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updateViewGroupAction: FlatUpdateViewGroupAction = {
type: 'update',
metadataName: 'viewGroup',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -82,13 +82,13 @@ export class WorkspaceMigrationViewActionsBuilderService extends WorkspaceEntity
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updateViewAction: FlatUpdateViewAction = {
type: 'update',
metadataName: 'view',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -91,13 +91,13 @@ export class WorkspaceMigrationWebhookActionsBuilderService extends WorkspaceEnt
};
}
const { flatEntityId, flatEntityUpdates } = args;
const { flatEntityId, flatEntityUpdate } = args;
const updateWebhookAction: FlatUpdateWebhookAction = {
type: 'update',
metadataName: 'webhook',
entityId: flatEntityId,
updates: flatEntityUpdates,
update: flatEntityUpdate,
};
return {
@@ -11,6 +11,7 @@ import {
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { MetadataFlatEntityAndRelatedFlatEntityMapsForValidation } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity-and-related-flat-entity-maps-for-validation.type';
import { MetadataFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity-maps.type';
import { MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
import { MetadataValidationRelatedFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-related-types.type';
import { addFlatEntityToFlatEntityAndRelatedEntityMapsThroughMutationOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-and-related-entity-maps-through-mutation-or-throw.util';
import { deleteFlatEntityFromFlatEntityAndRelatedEntityMapsThroughMutationOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/delete-flat-entity-from-flat-entity-and-related-entity-maps-through-mutation-or-throw.util';
@@ -29,7 +30,6 @@ import { FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace
import { FlatEntityValidationReturnType } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-validation-result.type';
import { SuccessfulFlatEntityValidateAndBuild } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/successful-flat-entity-validate-and-build.type';
import { type WorkspaceMigrationBuilderOptions } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/workspace-migration-builder-options.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
export type ValidateAndBuildArgs<T extends AllMetadataName> = {
buildOptions: WorkspaceMigrationBuilderOptions;
@@ -237,7 +237,7 @@ export abstract class WorkspaceEntityMigrationBuilderService<
}
const validationResult = await this.validateFlatEntityUpdate({
flatEntityUpdates: flatEntityToUpdate.updates,
flatEntityUpdate: flatEntityToUpdate.update,
flatEntityId: flatEntityToUpdate.id,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
workspaceId,
@@ -265,11 +265,9 @@ export abstract class WorkspaceEntityMigrationBuilderService<
);
}
const updatedFlatEntity = {
const updatedFlatEntity: MetadataFlatEntity<T> = {
...existingFlatEntity,
...fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates: flatEntityToUpdate.updates,
}),
...flatEntityToUpdate.update,
};
replaceFlatEntityInFlatEntityMapsThroughMutationOrThrow({
@@ -1,6 +1,6 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type FlatEntityPropertiesUpdates } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { type FlatEntityUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { type WORKSPACE_MIGRATION_ACTION_TYPE } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/constants/workspace-migration-action-type.constant';
export type BaseFlatUpdateWorkspaceMigrationAction<T extends AllMetadataName> =
@@ -8,5 +8,5 @@ export type BaseFlatUpdateWorkspaceMigrationAction<T extends AllMetadataName> =
type: typeof WORKSPACE_MIGRATION_ACTION_TYPE.update;
metadataName: T;
entityId: string;
updates: FlatEntityPropertiesUpdates<T>;
update: FlatEntityUpdate<T>;
};
@@ -1,6 +1,6 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type FlatEntityPropertiesUpdates } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { type FlatEntityUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { type WORKSPACE_MIGRATION_ACTION_TYPE } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/constants/workspace-migration-action-type.constant';
export type BaseUniversalUpdateWorkspaceMigrationAction<
@@ -9,5 +9,5 @@ export type BaseUniversalUpdateWorkspaceMigrationAction<
type: typeof WORKSPACE_MIGRATION_ACTION_TYPE.update;
metadataName: T;
universalIdentifier: string;
updates: FlatEntityPropertiesUpdates<T>;
update: FlatEntityUpdate<T>;
};
@@ -1,6 +1,6 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type FlatEntityPropertiesUpdates } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { type FlatEntityUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { type FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-validation-args.type';
export type FlatEntityUpdateValidationArgs<T extends AllMetadataName> = Omit<
@@ -8,6 +8,6 @@ export type FlatEntityUpdateValidationArgs<T extends AllMetadataName> = Omit<
'flatEntityToValidate' | 'remainingFlatEntityMapsToValidate'
> & {
flatEntityId: string;
flatEntityUpdates: FlatEntityPropertiesUpdates<T>;
flatEntityUpdate: FlatEntityUpdate<T>;
universalIdentifier: string;
};
@@ -15,7 +15,6 @@ import { type FlatEntityValidationArgs } from 'src/engine/workspace-manager/work
import { validateAgentNameUniqueness } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/utils/validate-agent-name-uniqueness.util';
import { validateAgentRequiredProperties } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/utils/validate-agent-required-properties.util';
import { validateAgentResponseFormat } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/utils/validate-agent-response-format.util';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class FlatAgentValidatorService {
@@ -121,7 +120,7 @@ export class FlatAgentValidatorService {
public validateFlatAgentUpdate({
flatEntityId,
flatEntityUpdates,
flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatAgentMaps: optimisticFlatAgentMaps,
},
@@ -170,14 +169,9 @@ export class FlatAgentValidatorService {
});
}
const partialFlatAgent: Partial<FlatAgent> =
fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates: flatEntityUpdates,
});
const optimisticFlatAgent: FlatAgent = {
...fromFlatAgent,
...partialFlatAgent,
...flatEntityUpdate,
};
const existingAgents = Object.values(
@@ -189,23 +183,23 @@ export class FlatAgentValidatorService {
validationResult.errors.push(
...validateAgentRequiredProperties({
flatAgent: optimisticFlatAgent,
updatedProperties: partialFlatAgent,
updatedProperties: flatEntityUpdate,
}),
);
if (isDefined(partialFlatAgent.name)) {
if (isDefined(flatEntityUpdate.name)) {
validationResult.errors.push(
...validateAgentNameUniqueness({
name: partialFlatAgent.name,
name: flatEntityUpdate.name,
existingFlatAgents: existingAgents,
}),
);
}
if (isDefined(partialFlatAgent.responseFormat)) {
if (isDefined(flatEntityUpdate.responseFormat)) {
validationResult.errors.push(
...validateAgentResponseFormat({
responseFormat: partialFlatAgent.responseFormat,
responseFormat: flatEntityUpdate.responseFormat,
}),
);
}
@@ -7,7 +7,6 @@ import { isDefined } from 'twenty-shared/utils';
import { CommandMenuItemExceptionCode } from 'src/engine/metadata-modules/command-menu-item/command-menu-item.exception';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { findFlatEntityPropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/utils/find-flat-entity-property-update.util';
import { type FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/types/failed-flat-entity-validation.type';
import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util';
import { type FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-update-validation-args.type';
@@ -88,7 +87,7 @@ export class FlatCommandMenuItemValidatorService {
public validateFlatCommandMenuItemUpdate({
flatEntityId,
flatEntityUpdates,
flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatCommandMenuItemMaps: optimisticFlatCommandMenuItemMaps,
},
@@ -119,12 +118,9 @@ export class FlatCommandMenuItemValidatorService {
return validationResult;
}
const labelUpdate = findFlatEntityPropertyUpdate({
flatEntityUpdates,
property: 'label',
});
const labelUpdate = flatEntityUpdate.label;
if (isDefined(labelUpdate) && !isNonEmptyString(labelUpdate.to)) {
if (isDefined(labelUpdate) && !isNonEmptyString(labelUpdate)) {
validationResult.errors.push({
code: CommandMenuItemExceptionCode.INVALID_COMMAND_MENU_ITEM_INPUT,
message: t`Label is required`,
@@ -15,12 +15,10 @@ import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/
import { validateFlatFieldMetadataNameAvailability } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-flat-field-metadata-name-availability.util';
import { validateFlatFieldMetadataName } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-flat-field-metadata-name.util';
import { belongsToTwentyStandardApp } from 'src/engine/metadata-modules/utils/belongs-to-twenty-standard-app.util';
import { findFlatEntityPropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/utils/find-flat-entity-property-update.util';
import { FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/types/failed-flat-entity-validation.type';
import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util';
import { FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-update-validation-args.type';
import { FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-validation-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class FlatFieldMetadataValidatorService {
@@ -30,7 +28,7 @@ export class FlatFieldMetadataValidatorService {
validateFlatFieldMetadataUpdate({
flatEntityId,
flatEntityUpdates: updates,
flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatFieldMetadataMaps: optimisticFlatFieldMetadataMaps,
flatObjectMetadataMaps,
@@ -69,7 +67,7 @@ export class FlatFieldMetadataValidatorService {
const flatFieldMetadataToValidate = {
...existingFlatFieldMetadataToUpdate,
...fromFlatEntityPropertiesUpdatesToPartialFlatEntity({ updates }),
...flatEntityUpdate,
};
validationResult.flatEntityMinimalInformation = {
@@ -103,12 +101,7 @@ export class FlatFieldMetadataValidatorService {
} else if (
flatObjectMetadata.labelIdentifierFieldMetadataId ===
flatFieldMetadataToValidate.id &&
isDefined(
findFlatEntityPropertyUpdate({
flatEntityUpdates: updates,
property: 'isActive',
}),
) &&
isDefined(flatEntityUpdate.isActive) &&
flatFieldMetadataToValidate.isActive === false
) {
validationResult.errors.push({
@@ -120,13 +113,12 @@ export class FlatFieldMetadataValidatorService {
// Should be moved in relation field validator
if (isMorphOrRelationFlatFieldMetadata(flatFieldMetadataToValidate)) {
const relationNonEditableUpdatedProperties = updates.flatMap(
({ property }) =>
const updatedProperties = Object.keys(flatEntityUpdate);
const relationNonEditableUpdatedProperties = updatedProperties.filter(
(property) =>
!FLAT_FIELD_METADATA_RELATION_PROPERTIES_TO_COMPARE.includes(
property as FlatFieldMetadataRelationPropertiesToCompare,
)
? property
: [],
),
);
if (relationNonEditableUpdatedProperties.length > 0) {
@@ -139,7 +131,7 @@ export class FlatFieldMetadataValidatorService {
}
///
if (updates.some((update) => update.property === 'name')) {
if (isDefined(flatEntityUpdate.name)) {
validationResult.errors.push(
...validateFlatFieldMetadataName({
name: flatFieldMetadataToValidate.name,
@@ -182,7 +174,7 @@ export class FlatFieldMetadataValidatorService {
const fieldMetadataTypeValidationErrors =
this.flatFieldMetadataTypeValidatorService.validateFlatFieldMetadataTypeSpecificities(
{
updates,
update: flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatFieldMetadataMaps: optimisticFlatFieldMetadataMaps,
flatObjectMetadataMaps,
@@ -7,7 +7,6 @@ import { isDefined } from 'twenty-shared/utils';
import { MetadataFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-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 { NavigationMenuItemExceptionCode } from 'src/engine/metadata-modules/navigation-menu-item/navigation-menu-item.exception';
import { findFlatEntityPropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/utils/find-flat-entity-property-update.util';
import { validateFlatEntityCircularDependency } from 'src/engine/workspace-manager/workspace-migration/utils/validate-flat-entity-circular-dependency.util';
import {
type FailedFlatEntityValidation,
@@ -16,7 +15,6 @@ import {
import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util';
import { type FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-update-validation-args.type';
import { type FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-validation-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
const NAVIGATION_MENU_ITEM_MAX_DEPTH = 2;
@@ -263,7 +261,7 @@ export class FlatNavigationMenuItemValidatorService {
public validateFlatNavigationMenuItemUpdate({
flatEntityId,
flatEntityUpdates,
flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatNavigationMenuItemMaps: optimisticFlatNavigationMenuItemMaps,
},
@@ -294,14 +292,11 @@ export class FlatNavigationMenuItemValidatorService {
return validationResult;
}
const positionUpdate = findFlatEntityPropertyUpdate({
flatEntityUpdates,
property: 'position',
});
const positionUpdate = flatEntityUpdate.position;
if (
isDefined(positionUpdate) &&
(!Number.isInteger(positionUpdate.to) || positionUpdate.to < 0)
(!Number.isInteger(positionUpdate) || positionUpdate < 0)
) {
validationResult.errors.push({
code: NavigationMenuItemExceptionCode.INVALID_NAVIGATION_MENU_ITEM_INPUT,
@@ -312,15 +307,10 @@ export class FlatNavigationMenuItemValidatorService {
const toFlatNavigationMenuItem = {
...fromFlatNavigationMenuItem,
...fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates: flatEntityUpdates,
}),
...flatEntityUpdate,
};
const nameUpdate = findFlatEntityPropertyUpdate({
flatEntityUpdates,
property: 'name',
});
const nameUpdate = flatEntityUpdate.name;
const typeValidationErrors = this.validateNavigationMenuItemType({
hasTargetRecordId: isDefined(toFlatNavigationMenuItem.targetRecordId),
@@ -328,28 +318,19 @@ export class FlatNavigationMenuItemValidatorService {
toFlatNavigationMenuItem.targetObjectMetadataId,
),
hasViewId: isDefined(toFlatNavigationMenuItem.viewId),
name: isDefined(nameUpdate)
? nameUpdate.to
: toFlatNavigationMenuItem.name,
name: isDefined(nameUpdate) ? nameUpdate : toFlatNavigationMenuItem.name,
isUpdate: true,
});
validationResult.errors.push(...typeValidationErrors);
const folderIdUpdate = findFlatEntityPropertyUpdate({
flatEntityUpdates,
property: 'folderId',
});
const folderIdUpdate = flatEntityUpdate.folderId;
if (!isDefined(folderIdUpdate)) {
return validationResult;
}
const newFolderId = folderIdUpdate.to;
if (!isDefined(newFolderId)) {
return validationResult;
}
const newFolderId = folderIdUpdate;
const circularDependencyErrors = this.getCircularDependencyValidationErrors(
{
@@ -13,13 +13,12 @@ import { FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspa
import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util';
import { FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-update-validation-args.type';
import { FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-validation-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class FlatObjectMetadataValidatorService {
public validateFlatObjectMetadataUpdate({
flatEntityId,
flatEntityUpdates,
flatEntityUpdate,
buildOptions,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatObjectMetadataMaps: optimisticFlatObjectMetadataMaps,
@@ -54,9 +53,7 @@ export class FlatObjectMetadataValidatorService {
const updatedFlatObjectMetadata = {
...existingFlatObjectMetadata,
...fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates: flatEntityUpdates,
}),
...flatEntityUpdate,
};
validationResult.flatEntityMinimalInformation = {
@@ -73,14 +70,9 @@ export class FlatObjectMetadataValidatorService {
buildOptions,
}),
);
const labelIdentifierFieldMetadataIdUpdate = flatEntityUpdates.find(
(update) => update.property === 'labelIdentifierFieldMetadataId',
);
// TODO remove this once we migrated labelIdentifierFieldMetadataId as non nullable
if (isDefined(labelIdentifierFieldMetadataIdUpdate)) {
if (!isDefined(labelIdentifierFieldMetadataIdUpdate.to)) {
if (flatEntityUpdate.labelIdentifierFieldMetadataId !== undefined) {
if (flatEntityUpdate.labelIdentifierFieldMetadataId === null) {
validationResult.errors.push({
code: ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT,
message: 'labelIdentifierFieldMetadataId cannot be null',
@@ -28,7 +28,6 @@ import {
import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util';
import { FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-update-validation-args.type';
import { FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-validation-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class FlatPageLayoutWidgetValidatorService {
@@ -38,7 +37,7 @@ export class FlatPageLayoutWidgetValidatorService {
public async validateFlatPageLayoutWidgetUpdate({
flatEntityId,
flatEntityUpdates,
flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
additionalCacheDataMaps: { featureFlagsMap },
workspaceId,
@@ -76,9 +75,7 @@ export class FlatPageLayoutWidgetValidatorService {
const updatedFlatPageLayoutWidget = {
...existingFlatPageLayoutWidget,
...fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates: flatEntityUpdates,
}),
...flatEntityUpdate,
};
validationResult.flatEntityMinimalInformation = {
@@ -122,7 +119,7 @@ export class FlatPageLayoutWidgetValidatorService {
{
flatEntityToValidate: updatedFlatPageLayoutWidget,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
updates: flatEntityUpdates,
update: flatEntityUpdate,
additionalCacheDataMaps: { featureFlagsMap },
workspaceId,
buildOptions,
@@ -12,7 +12,6 @@ import { FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/wor
import { FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-validation-args.type';
import { validateFlatRoleTargetAssignationAvailability } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/utils/validate-flat-role-target-assignation-availability.util';
import { validateFlatRoleTargetTargetsOnlyOneEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/utils/validate-flat-role-target-targets-only-one-entity.util';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class FlatRoleTargetValidatorService {
@@ -113,7 +112,7 @@ export class FlatRoleTargetValidatorService {
validateFlatRoleTargetUpdate({
flatEntityId,
flatEntityUpdates,
flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatRoleTargetMaps: optimisticFlatRoleTargetMaps,
flatRoleMaps,
@@ -147,9 +146,7 @@ export class FlatRoleTargetValidatorService {
const updatedFlatRoleTarget = {
...existingRoleTarget,
...fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates: flatEntityUpdates,
}),
...flatEntityUpdate,
};
validationResult.errors.push(
@@ -6,7 +6,6 @@ import { isDefined } from 'twenty-shared/utils';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { PermissionsExceptionCode } from 'src/engine/metadata-modules/permissions/permissions.exception';
import { findFlatEntityPropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/utils/find-flat-entity-property-update.util';
import { type FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/types/failed-flat-entity-validation.type';
import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util';
import { type FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-update-validation-args.type';
@@ -15,7 +14,6 @@ import { validateRoleIsEditable } from 'src/engine/workspace-manager/workspace-m
import { validateRoleLabelUniqueness } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/utils/validate-role-label-uniqueness.util';
import { validateRoleReadWritePermissionsConsistency } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/utils/validate-role-read-write-permissions-consistency.util';
import { validateRoleRequiredPropertiesAreDefined } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/utils/validate-role-required-properties-are-defined.util';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class FlatRoleValidatorService {
@@ -109,7 +107,7 @@ export class FlatRoleValidatorService {
public validateFlatRoleUpdate({
flatEntityId,
flatEntityUpdates,
flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatRoleMaps: optimisticFlatRoleMaps,
},
@@ -150,9 +148,7 @@ export class FlatRoleValidatorService {
const toFlatRole = {
...fromFlatRole,
...fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates: flatEntityUpdates,
}),
...flatEntityUpdate,
};
validationResult.errors.push(
@@ -161,10 +157,7 @@ export class FlatRoleValidatorService {
}),
);
const flatRoleLabelUpdate = findFlatEntityPropertyUpdate({
flatEntityUpdates,
property: 'label',
});
const flatRoleLabelUpdate = flatEntityUpdate.label;
if (isDefined(flatRoleLabelUpdate)) {
const existingRoles = Object.values(
@@ -173,7 +166,7 @@ export class FlatRoleValidatorService {
validationResult.errors.push(
...validateRoleLabelUniqueness({
label: flatRoleLabelUpdate.to,
label: flatRoleLabelUpdate,
existingFlatRoles: existingRoles,
}),
);
@@ -12,7 +12,6 @@ import { FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspa
import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util';
import { FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-update-validation-args.type';
import { FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-validation-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class FlatRowLevelPermissionPredicateGroupValidatorService {
@@ -141,7 +140,7 @@ export class FlatRowLevelPermissionPredicateGroupValidatorService {
validateFlatRowLevelPermissionPredicateGroupUpdate({
flatEntityId,
flatEntityUpdates,
flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
}: FlatEntityUpdateValidationArgs<
typeof ALL_METADATA_NAME.rowLevelPermissionPredicateGroup
@@ -179,9 +178,7 @@ export class FlatRowLevelPermissionPredicateGroupValidatorService {
const updatedPredicateGroup = {
...existingPredicateGroup,
...fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates: flatEntityUpdates,
}),
...flatEntityUpdate,
};
if (updatedPredicateGroup.roleId !== existingPredicateGroup.roleId) {
@@ -12,7 +12,6 @@ import { FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspa
import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util';
import { FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-update-validation-args.type';
import { FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-validation-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class FlatRowLevelPermissionPredicateValidatorService {
@@ -154,7 +153,7 @@ export class FlatRowLevelPermissionPredicateValidatorService {
validateFlatRowLevelPermissionPredicateUpdate({
flatEntityId,
flatEntityUpdates,
flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
}: FlatEntityUpdateValidationArgs<
typeof ALL_METADATA_NAME.rowLevelPermissionPredicate
@@ -193,9 +192,7 @@ export class FlatRowLevelPermissionPredicateValidatorService {
const updatedPredicate = {
...existingPredicate,
...fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates: flatEntityUpdates,
}),
...flatEntityUpdate,
};
if (updatedPredicate.roleId !== existingPredicate.roleId) {
@@ -8,7 +8,6 @@ import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/
import { type FlatSkill } from 'src/engine/metadata-modules/flat-skill/types/flat-skill.type';
import { SkillExceptionCode } from 'src/engine/metadata-modules/skill/skill.exception';
import { belongsToTwentyStandardApp } from 'src/engine/metadata-modules/utils/belongs-to-twenty-standard-app.util';
import { findFlatEntityPropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/utils/find-flat-entity-property-update.util';
import { type FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/types/failed-flat-entity-validation.type';
import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util';
import { type FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-update-validation-args.type';
@@ -19,7 +18,6 @@ import {
validateSkillLabelIsDefined,
validateSkillRequiredProperties,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/utils/validate-skill-required-properties.util';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class FlatSkillValidatorService {
@@ -115,7 +113,7 @@ export class FlatSkillValidatorService {
public validateFlatSkillUpdate({
flatEntityId,
flatEntityUpdates,
flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatSkillMaps: optimisticFlatSkillMaps,
},
@@ -147,14 +145,10 @@ export class FlatSkillValidatorService {
return validationResult;
}
// Standard skills can only have isActive toggled, not other properties
const isActiveUpdate = findFlatEntityPropertyUpdate({
flatEntityUpdates,
property: 'isActive',
});
const isActiveUpdate = flatEntityUpdate.isActive;
const hasNonIsActiveUpdates = flatEntityUpdates.some(
(update) => update.property !== 'isActive',
const hasNonIsActiveUpdates = Object.keys(flatEntityUpdate).some(
(key) => key !== 'isActive',
);
// TODO refactor once skill has been migrated to universal pattern
@@ -189,15 +183,10 @@ export class FlatSkillValidatorService {
const optimisticFlatSkill: FlatSkill = {
...fromFlatSkill,
...fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates: flatEntityUpdates,
}),
...flatEntityUpdate,
};
const labelUpdate = findFlatEntityPropertyUpdate({
flatEntityUpdates,
property: 'label',
});
const labelUpdate = flatEntityUpdate.label;
if (isDefined(labelUpdate)) {
validationResult.errors.push(
@@ -205,10 +194,7 @@ export class FlatSkillValidatorService {
);
}
const contentUpdate = findFlatEntityPropertyUpdate({
flatEntityUpdates,
property: 'content',
});
const contentUpdate = flatEntityUpdate.content;
if (isDefined(contentUpdate)) {
validationResult.errors.push(
@@ -216,10 +202,7 @@ export class FlatSkillValidatorService {
);
}
const nameUpdate = findFlatEntityPropertyUpdate({
flatEntityUpdates,
property: 'name',
});
const nameUpdate = flatEntityUpdate.name;
if (isDefined(nameUpdate)) {
const existingSkills = Object.values(
@@ -230,7 +213,7 @@ export class FlatSkillValidatorService {
validationResult.errors.push(
...validateSkillNameUniqueness({
name: nameUpdate.to,
name: nameUpdate,
existingFlatSkills: existingSkills,
}),
);
@@ -13,7 +13,6 @@ import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/
import { FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-update-validation-args.type';
import { FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-validation-args.type';
import { validateLabelIdentifierFieldMetadataIdFlatViewField } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/utils/validate-label-identifier-field-metadata-id-flat-view-field.util';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class FlatViewFieldValidatorService {
@@ -21,7 +20,7 @@ export class FlatViewFieldValidatorService {
public validateFlatViewFieldUpdate({
flatEntityId,
flatEntityUpdates,
flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatViewFieldMaps: optimisticFlatViewFieldMaps,
flatViewMaps,
@@ -56,9 +55,7 @@ export class FlatViewFieldValidatorService {
const updatedFlatViewField = {
...existingFlatViewField,
...fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates: flatEntityUpdates,
}),
...flatEntityUpdate,
};
validationResult.flatEntityMinimalInformation = {
@@ -7,7 +7,6 @@ import { isDefined } from 'twenty-shared/utils';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { type FlatViewFilterGroupMaps } from 'src/engine/metadata-modules/flat-view-filter-group/types/flat-view-filter-group-maps.type';
import { ViewFilterGroupExceptionCode } from 'src/engine/metadata-modules/view-filter-group/exceptions/view-filter-group.exception';
import { findFlatEntityPropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/utils/find-flat-entity-property-update.util';
import { validateFlatEntityCircularDependency } from 'src/engine/workspace-manager/workspace-migration/utils/validate-flat-entity-circular-dependency.util';
import {
type FailedFlatEntityValidation,
@@ -191,7 +190,7 @@ export class FlatViewFilterGroupValidatorService {
validateFlatViewFilterGroupUpdate({
flatEntityId,
flatEntityUpdates,
flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatViewFilterGroupMaps: optimisticFlatViewFilterGroupMaps,
},
@@ -220,20 +219,14 @@ export class FlatViewFilterGroupValidatorService {
});
}
const parentViewFilterGroupIdUpdate = findFlatEntityPropertyUpdate({
property: 'parentViewFilterGroupId',
flatEntityUpdates,
});
const parentViewFilterGroupIdUpdate =
flatEntityUpdate.parentViewFilterGroupId;
if (!isDefined(parentViewFilterGroupIdUpdate)) {
return validationResult;
}
const newParentViewFilterGroupId = parentViewFilterGroupIdUpdate.to;
if (!isDefined(newParentViewFilterGroupId)) {
return validationResult;
}
const newParentViewFilterGroupId = parentViewFilterGroupIdUpdate;
const circularDependencyErrors = this.getCircularDependencyValidationErrors(
{
@@ -10,7 +10,6 @@ import { type FailedFlatEntityValidation } from 'src/engine/workspace-manager/wo
import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util';
import { type FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-update-validation-args.type';
import { type FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-validation-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class FlatViewFilterValidatorService {
@@ -130,7 +129,7 @@ export class FlatViewFilterValidatorService {
validateFlatViewFilterUpdate({
flatEntityId,
flatEntityUpdates,
flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatViewFilterMaps: optimisticFlatViewFilterMaps,
flatFieldMetadataMaps,
@@ -165,9 +164,7 @@ export class FlatViewFilterValidatorService {
const updatedFlatViewFilter = {
...existingViewFilter,
...fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates: flatEntityUpdates,
}),
...flatEntityUpdate,
};
const referencedFieldMetadata = findFlatEntityByIdInFlatEntityMaps({
@@ -10,13 +10,12 @@ import { FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspa
import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util';
import { FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-update-validation-args.type';
import { FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-validation-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class FlatViewGroupValidatorService {
public validateFlatViewGroupUpdate({
flatEntityId,
flatEntityUpdates,
flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatViewGroupMaps: optimisticFlatViewGroupMaps,
flatViewMaps,
@@ -50,9 +49,7 @@ export class FlatViewGroupValidatorService {
const updatedFlatViewGroup = {
...existingFlatViewGroup,
...fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates: flatEntityUpdates,
}),
...flatEntityUpdate,
};
if (!isDefined(updatedFlatViewGroup.fieldValue)) {
@@ -7,19 +7,17 @@ import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
import { ViewType } from 'src/engine/metadata-modules/view/enums/view-type.enum';
import { ViewExceptionCode } from 'src/engine/metadata-modules/view/exceptions/view.exception';
import { findFlatEntityPropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/utils/find-flat-entity-property-update.util';
import { type FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/types/failed-flat-entity-validation.type';
import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util';
import { type FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-update-validation-args.type';
import { type FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-validation-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
export class FlatViewValidatorService {
constructor() {}
public validateFlatViewUpdate({
flatEntityId,
flatEntityUpdates,
flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatViewMaps: optimisticFlatViewMaps,
flatFieldMetadataMaps,
@@ -51,27 +49,20 @@ export class FlatViewValidatorService {
return validationResult;
}
const partialUpdates = fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates: flatEntityUpdates,
});
const updatedFlatView: FlatView = {
...existingFlatView,
...partialUpdates,
...flatEntityUpdate,
};
const kanbanAggregateOperationFieldMetadataIdUpdate =
findFlatEntityPropertyUpdate({
property: 'kanbanAggregateOperationFieldMetadataId',
flatEntityUpdates,
});
flatEntityUpdate.kanbanAggregateOperationFieldMetadataId;
if (
isDefined(kanbanAggregateOperationFieldMetadataIdUpdate) &&
kanbanAggregateOperationFieldMetadataIdUpdate.to !== null &&
kanbanAggregateOperationFieldMetadataIdUpdate !== null &&
!isDefined(
findFlatEntityByIdInFlatEntityMaps({
flatEntityId: kanbanAggregateOperationFieldMetadataIdUpdate.to,
flatEntityId: kanbanAggregateOperationFieldMetadataIdUpdate,
flatEntityMaps: flatFieldMetadataMaps,
}),
)
@@ -7,7 +7,6 @@ import { isDefined } from 'twenty-shared/utils';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { WebhookExceptionCode } from 'src/engine/metadata-modules/webhook/webhook.exception';
import { findFlatEntityPropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/utils/find-flat-entity-property-update.util';
import { type FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/types/failed-flat-entity-validation.type';
import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util';
import { type FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-update-validation-args.type';
@@ -95,7 +94,7 @@ export class FlatWebhookValidatorService {
public validateFlatWebhookUpdate({
flatEntityId,
flatEntityUpdates,
flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatWebhookMaps: optimisticFlatWebhookMaps,
},
@@ -126,14 +125,11 @@ export class FlatWebhookValidatorService {
return validationResult;
}
const targetUrlUpdate = findFlatEntityPropertyUpdate({
flatEntityUpdates,
property: 'targetUrl',
});
const targetUrlUpdate = flatEntityUpdate.targetUrl;
if (
isDefined(targetUrlUpdate) &&
!this.validateTargetUrl(targetUrlUpdate.to)
!this.validateTargetUrl(targetUrlUpdate)
) {
validationResult.errors.push({
code: WebhookExceptionCode.INVALID_TARGET_URL,
@@ -1,5 +1,7 @@
import { Injectable } from '@nestjs/common';
import { type QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/interfaces/workspace-migration-runner-action-handler-service.interface';
import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity';
@@ -8,7 +10,6 @@ import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class UpdateAgentActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -25,16 +26,16 @@ export class UpdateAgentActionHandlerService extends WorkspaceMigrationRunnerAct
context: WorkspaceMigrationActionRunnerContext<FlatUpdateAgentAction>,
): Promise<void> {
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, updates } = flatAction;
const { entityId, update } = flatAction;
const agentRepository =
queryRunner.manager.getRepository<AgentEntity>(AgentEntity);
// Cast needed because TypeORM's QueryDeepPartialEntity doesn't handle
// JsonbProperty branded types with nested Record<string, unknown> well
await agentRepository.update(
{ id: entityId, workspaceId },
fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates,
}),
update as QueryDeepPartialEntity<AgentEntity>,
);
}
@@ -8,7 +8,6 @@ import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class UpdateCommandMenuItemActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -25,7 +24,7 @@ export class UpdateCommandMenuItemActionHandlerService extends WorkspaceMigratio
context: WorkspaceMigrationActionRunnerContext<FlatUpdateCommandMenuItemAction>,
): Promise<void> {
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, updates } = flatAction;
const { entityId, update } = flatAction;
const commandMenuItemRepository =
queryRunner.manager.getRepository<CommandMenuItemEntity>(
@@ -34,9 +33,7 @@ export class UpdateCommandMenuItemActionHandlerService extends WorkspaceMigratio
await commandMenuItemRepository.update(
{ id: entityId, workspaceId },
fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates,
}),
update,
);
}
@@ -1,6 +1,9 @@
import { Injectable } from '@nestjs/common';
import { FieldMetadataType } from 'twenty-shared/types';
import {
FieldMetadataSettingsMapping,
FieldMetadataType,
} from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { ColumnType, type QueryRunner } from 'typeorm';
@@ -9,21 +12,19 @@ import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-mana
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { computeCompositeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
import { getCompositeTypeOrThrow } from 'src/engine/metadata-modules/field-metadata/utils/get-composite-type-or-throw.util';
import { FlatEntityPropertiesToCompare } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-to-compare.type';
import { FlatEntityUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { findFlatEntityByUniversalIdentifierOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier-or-throw.util';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { isCompositeFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-composite-flat-field-metadata.util';
import { isEnumFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-enum-flat-field-metadata.util';
import { isFlatFieldMetadataOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { WorkspaceSchemaManagerService } from 'src/engine/twenty-orm/workspace-schema-manager/workspace-schema-manager.service';
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
import { isMorphOrRelationFieldMetadataType } from 'src/engine/utils/is-morph-or-relation-field-metadata-type.util';
import { PropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/types/property-update.type';
import { convertOnDeleteActionToOnDelete } from 'src/engine/workspace-manager/workspace-migration/utils/convert-on-delete-action-to-on-delete.util';
import { findFlatEntityPropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/utils/find-flat-entity-property-update.util';
import { isPropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/utils/is-property-update.util';
import {
FlatUpdateFieldAction,
UniversalUpdateFieldAction,
@@ -38,7 +39,6 @@ import {
type WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fieldMetadataTypeToColumnType } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/field-metadata-type-to-column-type.util';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
import { generateColumnDefinitions } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/generate-column-definitions.util';
import { getWorkspaceSchemaContextForMigration } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/get-workspace-schema-context-for-migration.util';
import {
@@ -47,17 +47,34 @@ import {
executeBatchEnumOperations,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/workspace-schema-enum-operations.util';
type UpdateFieldPropertyUpdateHandlerArgs<
P extends FlatEntityPropertiesToCompare<'fieldMetadata'>,
type UpdateFieldPropertyHandlerArgs<
T extends FieldMetadataType = FieldMetadataType,
> = {
queryRunner: QueryRunner;
schemaName: string;
tableName: string;
flatFieldMetadata: FlatFieldMetadata<T>;
update: PropertyUpdate<FlatFieldMetadata, P>;
update: FlatEntityUpdate<'fieldMetadata'>;
};
type NameUpdateHandlerArgs<T extends FieldMetadataType = FieldMetadataType> =
UpdateFieldPropertyHandlerArgs<T> & {
toName: string;
};
type DefaultValueUpdateHandlerArgs<
T extends FieldMetadataType = FieldMetadataType,
> = UpdateFieldPropertyHandlerArgs<T> & {
toDefaultValue: FlatFieldMetadata['defaultValue'];
};
type OptionsUpdateHandlerArgs<T extends FieldMetadataType = FieldMetadataType> =
UpdateFieldPropertyHandlerArgs<T> & {
toOptions: FlatFieldMetadata['options'];
flatObjectMetadata: FlatObjectMetadata;
workspaceId: string;
};
@Injectable()
export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
'update',
@@ -86,25 +103,22 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
type: 'update',
metadataName: 'fieldMetadata',
entityId: flatFieldMetadata.id,
updates: action.updates,
update: action.update,
};
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerContext<FlatUpdateFieldAction>,
): Promise<void> {
const { flatAction, queryRunner } = context;
const { flatAction, queryRunner, workspaceId } = context;
const fieldMetadataRepository =
queryRunner.manager.getRepository<FieldMetadataEntity>(
FieldMetadataEntity,
);
const { entityId } = flatAction;
const { entityId, update } = flatAction;
await fieldMetadataRepository.update(
entityId,
fromFlatEntityPropertiesUpdatesToPartialFlatEntity(flatAction),
);
await fieldMetadataRepository.update({ id: entityId, workspaceId }, update);
}
async executeForWorkspaceSchema(
@@ -116,7 +130,7 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
allFlatEntityMaps: { flatObjectMetadataMaps, flatFieldMetadataMaps },
workspaceId,
} = context;
const { entityId, updates } = flatAction;
const { entityId, update } = flatAction;
const currentFlatFieldMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityId: entityId,
@@ -135,183 +149,201 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
let optimisticFlatFieldMetadata = structuredClone(currentFlatFieldMetadata);
const defaultValueUpdate = findFlatEntityPropertyUpdate({
flatEntityUpdates: updates,
property: 'defaultValue',
});
const hasDefaultValueUpdate = isDefined(defaultValueUpdate);
let wasDefaultValueHandledByEnumUpdate = false;
const sortedUpdatesWithDefaultValuesUpdateLast = hasDefaultValueUpdate
? [
...updates.filter((update) => update.property !== 'defaultValue'),
defaultValueUpdate,
]
: updates;
if (isDefined(update.name)) {
await this.handleFieldNameUpdate({
queryRunner,
schemaName,
tableName,
flatFieldMetadata: optimisticFlatFieldMetadata,
update,
toName: update.name,
});
optimisticFlatFieldMetadata.name = update.name;
}
for (const update of sortedUpdatesWithDefaultValuesUpdateLast) {
if (isPropertyUpdate(update, 'name')) {
await this.handleFieldNameUpdate({
if (
update.options !== undefined &&
isEnumFlatFieldMetadata(optimisticFlatFieldMetadata)
) {
if (update.defaultValue !== undefined) {
optimisticFlatFieldMetadata = {
...optimisticFlatFieldMetadata,
defaultValue: update.defaultValue,
};
wasDefaultValueHandledByEnumUpdate = true;
}
await this.handleFieldOptionsUpdate({
queryRunner,
schemaName,
tableName,
flatFieldMetadata: optimisticFlatFieldMetadata,
flatObjectMetadata,
toOptions: update.options,
workspaceId,
update,
});
optimisticFlatFieldMetadata.options = update.options ?? [];
}
if (update.defaultValue !== undefined) {
if (wasDefaultValueHandledByEnumUpdate) {
optimisticFlatFieldMetadata.defaultValue = update.defaultValue;
} else {
await this.handleFieldDefaultValueUpdate({
queryRunner,
schemaName,
tableName,
flatFieldMetadata: optimisticFlatFieldMetadata,
toDefaultValue: update.defaultValue,
update,
});
optimisticFlatFieldMetadata.name = update.to;
optimisticFlatFieldMetadata.defaultValue = update.defaultValue;
}
if (isPropertyUpdate(update, 'defaultValue')) {
if (wasDefaultValueHandledByEnumUpdate) {
optimisticFlatFieldMetadata.defaultValue = update.to;
} else {
await this.handleFieldDefaultValueUpdate({
}
if (isDefined(update.settings)) {
// Handle joinColumnName rename
if (isMorphOrRelationFlatFieldMetadata(optimisticFlatFieldMetadata)) {
const fromSettings = optimisticFlatFieldMetadata.settings;
const toSettings = update.settings as
| FieldMetadataSettingsMapping['MORPH_RELATION']
| FieldMetadataSettingsMapping['RELATION'];
if (
isDefined(fromSettings?.joinColumnName) &&
isDefined(toSettings?.joinColumnName) &&
fromSettings.joinColumnName !== toSettings.joinColumnName
) {
await this.workspaceSchemaManagerService.columnManager.renameColumn({
queryRunner,
schemaName,
tableName,
flatFieldMetadata: optimisticFlatFieldMetadata,
update,
oldColumnName: fromSettings.joinColumnName,
newColumnName: toSettings.joinColumnName,
});
optimisticFlatFieldMetadata.defaultValue = update.to;
}
}
if (
isPropertyUpdate(update, 'options') &&
isEnumFlatFieldMetadata(optimisticFlatFieldMetadata)
) {
if (hasDefaultValueUpdate) {
optimisticFlatFieldMetadata = {
...optimisticFlatFieldMetadata,
defaultValue: defaultValueUpdate.to,
};
wasDefaultValueHandledByEnumUpdate = true;
}
await this.handleFieldOptionsUpdate({
queryRunner,
schemaName,
tableName,
flatFieldMetadata: optimisticFlatFieldMetadata,
flatObjectMetadata,
update,
workspaceId,
});
optimisticFlatFieldMetadata.options = update.to ?? [];
}
if (
isPropertyUpdate(update, 'settings') &&
isDefined(update.from?.joinColumnName) &&
isDefined(update.to?.joinColumnName) &&
update.from.joinColumnName !== update.to.joinColumnName &&
isMorphOrRelationFlatFieldMetadata(optimisticFlatFieldMetadata)
) {
await this.workspaceSchemaManagerService.columnManager.renameColumn({
queryRunner,
schemaName,
tableName,
oldColumnName: update.from.joinColumnName,
newColumnName: update.to.joinColumnName,
});
optimisticFlatFieldMetadata = {
...optimisticFlatFieldMetadata,
settings: {
...optimisticFlatFieldMetadata.settings,
joinColumnName: update.to.joinColumnName,
},
};
}
if (
isPropertyUpdate(update, 'settings') &&
isDefined(update.to?.asExpression) &&
isDefined(update.from?.asExpression) &&
(update.to.asExpression !== update.from.asExpression ||
update.to.generatedType !== update.from.generatedType)
) {
await this.workspaceSchemaManagerService.columnManager.dropColumns({
queryRunner,
schemaName,
tableName,
columnNames: [optimisticFlatFieldMetadata.name],
});
await this.workspaceSchemaManagerService.columnManager.addColumns({
queryRunner,
schemaName,
tableName,
columnDefinitions: [
{
name: optimisticFlatFieldMetadata.name,
type: 'tsvector',
...update.to,
settings: {
...optimisticFlatFieldMetadata.settings,
joinColumnName: toSettings.joinColumnName,
},
],
});
optimisticFlatFieldMetadata = {
...optimisticFlatFieldMetadata,
settings: update.to,
};
};
}
}
// Handle asExpression/generatedType change (for TS_VECTOR fields)
if (
isMorphOrRelationFlatFieldMetadata(optimisticFlatFieldMetadata) &&
isDefined(optimisticFlatFieldMetadata.settings.joinColumnName) &&
isPropertyUpdate(update, 'settings') &&
isDefined(update.from?.onDelete) &&
isDefined(update.to?.onDelete) &&
update.to.onDelete !== update.from.onDelete
isFlatFieldMetadataOfType(
optimisticFlatFieldMetadata,
FieldMetadataType.TS_VECTOR,
)
) {
const foreignKeyName =
await this.workspaceSchemaManagerService.foreignKeyManager.getForeignKeyName(
const fromSettings =
optimisticFlatFieldMetadata.settings as FieldMetadataSettingsMapping['TS_VECTOR'];
const toSettings =
update.settings as FieldMetadataSettingsMapping['TS_VECTOR'];
if (
isDefined(toSettings?.asExpression) &&
isDefined(fromSettings?.asExpression) &&
(toSettings.asExpression !== fromSettings.asExpression ||
toSettings.generatedType !== fromSettings.generatedType)
) {
await this.workspaceSchemaManagerService.columnManager.dropColumns({
queryRunner,
schemaName,
tableName,
columnNames: [optimisticFlatFieldMetadata.name],
});
await this.workspaceSchemaManagerService.columnManager.addColumns({
queryRunner,
schemaName,
tableName,
columnDefinitions: [
{
name: optimisticFlatFieldMetadata.name,
type: 'tsvector',
...toSettings,
},
],
});
optimisticFlatFieldMetadata = {
...optimisticFlatFieldMetadata,
settings: toSettings,
};
}
}
// Handle onDelete change (for morph/relation fields) order matters
if (isMorphOrRelationFlatFieldMetadata(optimisticFlatFieldMetadata)) {
const fromSettings = optimisticFlatFieldMetadata.settings;
const toSettings = update.settings as
| FieldMetadataSettingsMapping['MORPH_RELATION']
| FieldMetadataSettingsMapping['RELATION'];
if (
isDefined(optimisticFlatFieldMetadata.settings.joinColumnName) &&
isDefined(fromSettings?.onDelete) &&
isDefined(toSettings?.onDelete) &&
toSettings.onDelete !== fromSettings.onDelete
) {
const foreignKeyName =
await this.workspaceSchemaManagerService.foreignKeyManager.getForeignKeyName(
{
queryRunner,
schemaName,
tableName,
columnName: optimisticFlatFieldMetadata.settings.joinColumnName,
},
);
if (!isDefined(foreignKeyName)) {
throw new WorkspaceMigrationActionExecutionException({
message: 'Foreign key not found',
code: WorkspaceMigrationActionExecutionExceptionCode.NOT_SUPPORTED,
});
}
await this.workspaceSchemaManagerService.foreignKeyManager.dropForeignKey(
{
queryRunner,
schemaName,
tableName,
columnName: optimisticFlatFieldMetadata.settings.joinColumnName,
foreignKeyName,
},
);
if (!isDefined(foreignKeyName)) {
throw new WorkspaceMigrationActionExecutionException({
message: 'Foreign key not found',
code: WorkspaceMigrationActionExecutionExceptionCode.NOT_SUPPORTED,
});
}
const targetFlatObjectMetadata =
findFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityId:
optimisticFlatFieldMetadata.relationTargetObjectMetadataId,
flatEntityMaps: flatObjectMetadataMaps,
});
await this.workspaceSchemaManagerService.foreignKeyManager.dropForeignKey(
{
queryRunner,
schemaName,
tableName,
foreignKeyName,
},
);
const referencedTableName = computeObjectTargetTable(
targetFlatObjectMetadata,
);
const targetFlatObjectMetadata =
findFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityId:
optimisticFlatFieldMetadata.relationTargetObjectMetadataId,
flatEntityMaps: flatObjectMetadataMaps,
});
const referencedTableName = computeObjectTargetTable(
targetFlatObjectMetadata,
);
await this.workspaceSchemaManagerService.foreignKeyManager.createForeignKey(
{
queryRunner,
schemaName,
foreignKey: {
tableName,
columnName: update.to.joinColumnName,
referencedTableName,
referencedColumnName: 'id',
onDelete:
convertOnDeleteActionToOnDelete(update.to.onDelete) ??
'CASCADE',
await this.workspaceSchemaManagerService.foreignKeyManager.createForeignKey(
{
queryRunner,
schemaName,
foreignKey: {
tableName,
columnName: optimisticFlatFieldMetadata.settings.joinColumnName,
referencedTableName,
referencedColumnName: 'id',
onDelete:
convertOnDeleteActionToOnDelete(toSettings.onDelete) ??
'CASCADE',
},
},
},
);
);
}
}
}
}
@@ -321,8 +353,10 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
queryRunner,
schemaName,
tableName,
update,
}: UpdateFieldPropertyUpdateHandlerArgs<'name'>) {
toName,
}: NameUpdateHandlerArgs) {
const fromName = flatFieldMetadata.name;
if (isCompositeFlatFieldMetadata(flatFieldMetadata)) {
const compositeType = getCompositeTypeOrThrow(flatFieldMetadata.type);
@@ -336,11 +370,11 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
}
const fromCompositeColumnName = computeCompositeColumnName(
update.from,
fromName,
property,
);
const toCompositeColumnName = computeCompositeColumnName(
update.to,
toName,
property,
);
@@ -357,8 +391,8 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
queryRunner,
schemaName,
tableName,
oldColumnName: update.from,
newColumnName: update.to,
oldColumnName: fromName,
newColumnName: toName,
});
}
@@ -367,7 +401,7 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
tableName,
operation: EnumOperation.RENAME,
options: {
newFieldName: update.to,
newFieldName: toName,
},
});
@@ -384,8 +418,8 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
queryRunner,
schemaName,
tableName,
update,
}: UpdateFieldPropertyUpdateHandlerArgs<'defaultValue'>) {
toDefaultValue,
}: DefaultValueUpdateHandlerArgs) {
if (isCompositeFlatFieldMetadata(flatFieldMetadata)) {
const compositeType = getCompositeTypeOrThrow(flatFieldMetadata.type);
@@ -407,7 +441,7 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
property,
);
// @ts-expect-error - TODO: fix this
let compositeDefaultValue = update.to?.[property.name]; // not valid should be serialized
const compositeDefaultValue = toDefaultValue?.[property.name];
const serializedNewDefaultValue = serializeDefaultValue({
columnName: compositeColumnName,
@@ -440,7 +474,7 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
schemaName,
tableName,
columnType,
defaultValue: update.to,
defaultValue: toDefaultValue,
});
return await this.workspaceSchemaManagerService.columnManager.alterColumnDefault(
@@ -459,21 +493,19 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
queryRunner,
schemaName,
tableName,
update,
toOptions,
flatObjectMetadata,
workspaceId,
}: UpdateFieldPropertyUpdateHandlerArgs<'options'> & {
flatObjectMetadata: FlatObjectMetadata;
workspaceId: string;
}) {
}: OptionsUpdateHandlerArgs) {
const fromOptions = flatFieldMetadata.options;
const fromOptionsById = new Map(
(update.from ?? [])
(fromOptions ?? [])
.filter((opt) => isDefined(opt.id))
.map((opt) => [opt.id, opt]),
);
const toOptionsById = new Map(
(update.to ?? [])
(toOptions ?? [])
.filter((opt) => isDefined(opt.id))
.map((opt) => [opt.id, opt]),
);
@@ -500,7 +532,7 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
schemaName,
tableName,
columnDefinition: enumColumnDefinition,
enumValues: update.to?.map((opt) => opt.value) ?? [],
enumValues: toOptions?.map((opt) => opt.value) ?? [],
oldToNewEnumOptionMap: valueMapping,
});
}
@@ -8,7 +8,6 @@ import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class UpdateFrontComponentActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -25,7 +24,7 @@ export class UpdateFrontComponentActionHandlerService extends WorkspaceMigration
context: WorkspaceMigrationActionRunnerContext<FlatUpdateFrontComponentAction>,
): Promise<void> {
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, updates } = flatAction;
const { entityId, update } = flatAction;
const frontComponentRepository =
queryRunner.manager.getRepository<FrontComponentEntity>(
@@ -34,9 +33,7 @@ export class UpdateFrontComponentActionHandlerService extends WorkspaceMigration
await frontComponentRepository.update(
{ id: entityId, workspaceId },
fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates,
}),
update,
);
}
@@ -4,32 +4,31 @@ import { InjectRepository } from '@nestjs/typeorm';
import { promises as fs } from 'fs';
import { dirname, join } from 'path';
import { isObject } from '@sniptt/guards';
import { FileFolder, Sources } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { Repository } from 'typeorm';
import { FileFolder, Sources } from 'twenty-shared/types';
import { isObject } from '@sniptt/guards';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/interfaces/workspace-migration-runner-action-handler-service.interface';
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
import { LogicFunctionBuildService } from 'src/engine/core-modules/logic-function/logic-function-build/services/logic-function-build.service';
import { getLogicFunctionBaseFolderPath } from 'src/engine/core-modules/logic-function/logic-function-build/utils/get-logic-function-base-folder-path.util';
import { LambdaBuildDirectoryManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/lambda-build-directory-manager';
import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { FlatUpdateLogicFunctionAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/logic-function/types/workspace-migration-logic-function-action.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
import { LogicFunctionBuildService } from 'src/engine/core-modules/logic-function/logic-function-build/services/logic-function-build.service';
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
import { getLogicFunctionBaseFolderPath } from 'src/engine/core-modules/logic-function/logic-function-build/utils/get-logic-function-base-folder-path.util';
import { LambdaBuildDirectoryManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/lambda-build-directory-manager';
import {
LogicFunctionException,
LogicFunctionExceptionCode,
} from 'src/engine/metadata-modules/logic-function/logic-function.exception';
import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
import { FlatUpdateLogicFunctionAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/logic-function/types/workspace-migration-logic-function-action.type';
import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
@Injectable()
export class UpdateLogicFunctionActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -55,36 +54,31 @@ export class UpdateLogicFunctionActionHandlerService extends WorkspaceMigrationR
async executeForMetadata(
context: WorkspaceMigrationActionRunnerContext<FlatUpdateLogicFunctionAction>,
): Promise<void> {
const { flatAction, queryRunner } = context;
const { entityId, code } = flatAction;
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, code, update } = flatAction;
const logicFunctionRepository =
queryRunner.manager.getRepository<LogicFunctionEntity>(
LogicFunctionEntity,
);
await logicFunctionRepository.update(
entityId,
fromFlatEntityPropertiesUpdatesToPartialFlatEntity(flatAction),
);
await logicFunctionRepository.update({ id: entityId, workspaceId }, update);
const flatLogicFunction = findFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityId: entityId,
flatEntityMaps: context.allFlatEntityMaps.flatLogicFunctionMaps,
});
for (const update of flatAction.updates) {
if (update.property === 'checksum' && isDefined(code)) {
await this.handleChecksumUpdate({
flatLogicFunction,
code,
});
}
if (update.property === 'deletedAt' && isDefined(update.to)) {
await this.handleDeletedAtUpdate({
flatLogicFunction,
});
}
if (isDefined(update.checksum) && isDefined(code)) {
await this.handleChecksumUpdate({
flatLogicFunction,
code,
});
}
if (update.deletedAt !== undefined) {
await this.handleDeletedAtUpdate({
flatLogicFunction,
});
}
}
@@ -8,7 +8,6 @@ import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class UpdateNavigationMenuItemActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -25,7 +24,7 @@ export class UpdateNavigationMenuItemActionHandlerService extends WorkspaceMigra
context: WorkspaceMigrationActionRunnerContext<FlatUpdateNavigationMenuItemAction>,
): Promise<void> {
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, updates } = flatAction;
const { entityId, update } = flatAction;
const navigationMenuItemRepository =
queryRunner.manager.getRepository<NavigationMenuItemEntity>(
@@ -34,9 +33,7 @@ export class UpdateNavigationMenuItemActionHandlerService extends WorkspaceMigra
await navigationMenuItemRepository.update(
{ id: entityId, workspaceId },
fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates,
}),
update,
);
}
@@ -13,7 +13,6 @@ import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-meta
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { WorkspaceSchemaManagerService } from 'src/engine/twenty-orm/workspace-schema-manager/workspace-schema-manager.service';
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
import { findFlatEntityPropertyUpdate } from 'src/engine/workspace-manager/workspace-migration/utils/find-flat-entity-property-update.util';
import {
type FlatUpdateObjectAction,
type UniversalUpdateObjectAction,
@@ -22,7 +21,6 @@ import {
type WorkspaceMigrationActionRunnerArgs,
type WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
import { getWorkspaceSchemaContextForMigration } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/get-workspace-schema-context-for-migration.util';
import {
collectEnumOperationsForObject,
@@ -58,7 +56,7 @@ export class UpdateObjectActionHandlerService extends WorkspaceMigrationRunnerAc
type: 'update',
metadataName: 'objectMetadata',
entityId: flatObjectMetadata.id,
updates: action.updates,
update: action.update,
};
}
@@ -74,7 +72,7 @@ export class UpdateObjectActionHandlerService extends WorkspaceMigrationRunnerAc
await objectMetadataRepository.update(
flatAction.entityId,
fromFlatEntityPropertiesUpdatesToPartialFlatEntity(flatAction),
flatAction.update,
);
}
@@ -87,7 +85,7 @@ export class UpdateObjectActionHandlerService extends WorkspaceMigrationRunnerAc
allFlatEntityMaps: { flatObjectMetadataMaps, flatFieldMetadataMaps },
workspaceId,
} = context;
const { entityId, updates } = flatAction;
const { entityId, update } = flatAction;
const flatObjectMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityMaps: flatObjectMetadataMaps,
@@ -100,15 +98,10 @@ export class UpdateObjectActionHandlerService extends WorkspaceMigrationRunnerAc
objectMetadata: flatObjectMetadata,
});
const nameSingularUpdate = findFlatEntityPropertyUpdate({
flatEntityUpdates: updates,
property: 'nameSingular',
});
if (isDefined(nameSingularUpdate)) {
if (isDefined(update.nameSingular)) {
const updatedFlatObjectMetadata: FlatObjectMetadata = {
...flatObjectMetadata,
nameSingular: nameSingularUpdate.to,
nameSingular: update.nameSingular,
};
const newTableName = computeObjectTargetTable(updatedFlatObjectMetadata);
@@ -8,7 +8,6 @@ import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class UpdatePageLayoutTabActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -25,19 +24,14 @@ export class UpdatePageLayoutTabActionHandlerService extends WorkspaceMigrationR
context: WorkspaceMigrationActionRunnerContext<FlatUpdatePageLayoutTabAction>,
): Promise<void> {
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, updates } = flatAction;
const { entityId, update } = flatAction;
const pageLayoutTabRepository =
queryRunner.manager.getRepository<PageLayoutTabEntity>(
PageLayoutTabEntity,
);
await pageLayoutTabRepository.update(
{ id: entityId, workspaceId },
fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates,
}),
);
await pageLayoutTabRepository.update({ id: entityId, workspaceId }, update);
}
async executeForWorkspaceSchema(
@@ -8,7 +8,6 @@ import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class UpdatePageLayoutWidgetActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -28,22 +27,17 @@ export class UpdatePageLayoutWidgetActionHandlerService extends WorkspaceMigrati
async executeForMetadata(
context: WorkspaceMigrationActionRunnerContext<FlatUpdatePageLayoutWidgetAction>,
): Promise<void> {
const { flatAction, queryRunner } = context;
const { entityId, updates } = flatAction;
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, update } = flatAction;
const pageLayoutWidgetRepository =
queryRunner.manager.getRepository<PageLayoutWidgetEntity>(
PageLayoutWidgetEntity,
);
const partialPageLayoutWidget =
fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates,
});
await pageLayoutWidgetRepository.update(
{ id: entityId },
partialPageLayoutWidget,
{ id: entityId, workspaceId },
update,
);
}
@@ -8,7 +8,6 @@ import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class UpdatePageLayoutActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -25,17 +24,12 @@ export class UpdatePageLayoutActionHandlerService extends WorkspaceMigrationRunn
context: WorkspaceMigrationActionRunnerContext<FlatUpdatePageLayoutAction>,
): Promise<void> {
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, updates } = flatAction;
const { entityId, update } = flatAction;
const pageLayoutRepository =
queryRunner.manager.getRepository<PageLayoutEntity>(PageLayoutEntity);
await pageLayoutRepository.update(
{ id: entityId, workspaceId },
fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates,
}),
);
await pageLayoutRepository.update({ id: entityId, workspaceId }, update);
}
async executeForWorkspaceSchema(
@@ -8,7 +8,6 @@ import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class UpdateRoleTargetActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -28,16 +27,13 @@ export class UpdateRoleTargetActionHandlerService extends WorkspaceMigrationRunn
async executeForMetadata(
context: WorkspaceMigrationActionRunnerContext<FlatUpdateRoleTargetAction>,
): Promise<void> {
const { flatAction, queryRunner } = context;
const { entityId } = flatAction;
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, update } = flatAction;
const roleTargetRepository =
queryRunner.manager.getRepository<RoleTargetEntity>(RoleTargetEntity);
const update =
fromFlatEntityPropertiesUpdatesToPartialFlatEntity(flatAction);
await roleTargetRepository.update(entityId, update);
await roleTargetRepository.update({ id: entityId, workspaceId }, update);
}
async executeForWorkspaceSchema(
@@ -8,7 +8,6 @@ import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class UpdateRoleActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -25,15 +24,12 @@ export class UpdateRoleActionHandlerService extends WorkspaceMigrationRunnerActi
context: WorkspaceMigrationActionRunnerContext<FlatUpdateRoleAction>,
): Promise<void> {
const { flatAction, queryRunner, workspaceId } = context;
const { entityId } = flatAction;
const { entityId, update } = flatAction;
const roleRepository =
queryRunner.manager.getRepository<RoleEntity>(RoleEntity);
await roleRepository.update(
{ id: entityId, workspaceId },
fromFlatEntityPropertiesUpdatesToPartialFlatEntity(flatAction),
);
await roleRepository.update({ id: entityId, workspaceId }, update);
}
async executeForWorkspaceSchema(
@@ -10,7 +10,6 @@ import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class UpdateRowLevelPermissionPredicateGroupActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -26,18 +25,15 @@ export class UpdateRowLevelPermissionPredicateGroupActionHandlerService extends
async executeForMetadata(
context: WorkspaceMigrationActionRunnerContext<FlatUpdateRowLevelPermissionPredicateGroupAction>,
): Promise<void> {
const { flatAction, queryRunner } = context;
const { entityId } = flatAction;
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, update } = flatAction;
const repository =
queryRunner.manager.getRepository<RowLevelPermissionPredicateGroupEntity>(
RowLevelPermissionPredicateGroupEntity,
);
const update =
fromFlatEntityPropertiesUpdatesToPartialFlatEntity(flatAction);
await repository.update(entityId, update);
await repository.update({ id: entityId, workspaceId }, update);
}
async executeForWorkspaceSchema(
@@ -10,7 +10,6 @@ import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class UpdateRowLevelPermissionPredicateActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -26,18 +25,15 @@ export class UpdateRowLevelPermissionPredicateActionHandlerService extends Works
async executeForMetadata(
context: WorkspaceMigrationActionRunnerContext<FlatUpdateRowLevelPermissionPredicateAction>,
): Promise<void> {
const { flatAction, queryRunner } = context;
const { entityId } = flatAction;
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, update } = flatAction;
const repository =
queryRunner.manager.getRepository<RowLevelPermissionPredicateEntity>(
RowLevelPermissionPredicateEntity,
);
const update =
fromFlatEntityPropertiesUpdatesToPartialFlatEntity(flatAction);
await repository.update(entityId, update);
await repository.update({ id: entityId, workspaceId }, update);
}
async executeForWorkspaceSchema(
@@ -8,7 +8,6 @@ import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class UpdateSkillActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -25,17 +24,12 @@ export class UpdateSkillActionHandlerService extends WorkspaceMigrationRunnerAct
context: WorkspaceMigrationActionRunnerContext<FlatUpdateSkillAction>,
): Promise<void> {
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, updates } = flatAction;
const { entityId, update } = flatAction;
const skillRepository =
queryRunner.manager.getRepository<SkillEntity>(SkillEntity);
await skillRepository.update(
{ id: entityId, workspaceId },
fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates,
}),
);
await skillRepository.update({ id: entityId, workspaceId }, update);
}
async executeForWorkspaceSchema(
@@ -8,7 +8,6 @@ import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class UpdateViewFieldActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -28,16 +27,13 @@ export class UpdateViewFieldActionHandlerService extends WorkspaceMigrationRunne
async executeForMetadata(
context: WorkspaceMigrationActionRunnerContext<FlatUpdateViewFieldAction>,
): Promise<void> {
const { flatAction, queryRunner } = context;
const { entityId } = flatAction;
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, update } = flatAction;
const viewFieldRepository =
queryRunner.manager.getRepository<ViewFieldEntity>(ViewFieldEntity);
const update =
fromFlatEntityPropertiesUpdatesToPartialFlatEntity(flatAction);
await viewFieldRepository.update(entityId, update);
await viewFieldRepository.update({ id: entityId, workspaceId }, update);
}
async executeForWorkspaceSchema(
@@ -8,7 +8,6 @@ import {
type WorkspaceMigrationActionRunnerArgs,
type WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class UpdateViewFilterGroupActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -28,18 +27,18 @@ export class UpdateViewFilterGroupActionHandlerService extends WorkspaceMigratio
async executeForMetadata(
context: WorkspaceMigrationActionRunnerContext<FlatUpdateViewFilterGroupAction>,
): Promise<void> {
const { flatAction, queryRunner } = context;
const { entityId } = flatAction;
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, update } = flatAction;
const viewFilterGroupRepository =
queryRunner.manager.getRepository<ViewFilterGroupEntity>(
ViewFilterGroupEntity,
);
const update =
fromFlatEntityPropertiesUpdatesToPartialFlatEntity(flatAction);
await viewFilterGroupRepository.update(entityId, update);
await viewFilterGroupRepository.update(
{ id: entityId, workspaceId },
update,
);
}
async executeForWorkspaceSchema(
@@ -8,7 +8,6 @@ import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class UpdateViewFilterActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -28,16 +27,13 @@ export class UpdateViewFilterActionHandlerService extends WorkspaceMigrationRunn
async executeForMetadata(
context: WorkspaceMigrationActionRunnerContext<FlatUpdateViewFilterAction>,
): Promise<void> {
const { flatAction, queryRunner } = context;
const { entityId } = flatAction;
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, update } = flatAction;
const viewFilterRepository =
queryRunner.manager.getRepository<ViewFilterEntity>(ViewFilterEntity);
const update =
fromFlatEntityPropertiesUpdatesToPartialFlatEntity(flatAction);
await viewFilterRepository.update(entityId, update);
await viewFilterRepository.update({ id: entityId, workspaceId }, update);
}
async executeForWorkspaceSchema(
@@ -8,7 +8,6 @@ import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class UpdateViewGroupActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -24,16 +23,13 @@ export class UpdateViewGroupActionHandlerService extends WorkspaceMigrationRunne
async executeForMetadata(
context: WorkspaceMigrationActionRunnerContext<FlatUpdateViewGroupAction>,
): Promise<void> {
const { flatAction, queryRunner } = context;
const { entityId } = flatAction;
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, update } = flatAction;
const viewGroupRepository =
queryRunner.manager.getRepository<ViewGroupEntity>(ViewGroupEntity);
const update =
fromFlatEntityPropertiesUpdatesToPartialFlatEntity(flatAction);
await viewGroupRepository.update(entityId, update);
await viewGroupRepository.update({ id: entityId, workspaceId }, update);
}
async executeForWorkspaceSchema(
@@ -8,7 +8,6 @@ import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class UpdateViewActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -28,16 +27,13 @@ export class UpdateViewActionHandlerService extends WorkspaceMigrationRunnerActi
async executeForMetadata(
context: WorkspaceMigrationActionRunnerContext<FlatUpdateViewAction>,
): Promise<void> {
const { flatAction, queryRunner } = context;
const { entityId } = flatAction;
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, update } = flatAction;
const viewRepository =
queryRunner.manager.getRepository<ViewEntity>(ViewEntity);
await viewRepository.update(
entityId,
fromFlatEntityPropertiesUpdatesToPartialFlatEntity(flatAction),
);
await viewRepository.update({ id: entityId, workspaceId }, update);
}
async executeForWorkspaceSchema(
@@ -8,7 +8,6 @@ import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
@Injectable()
export class UpdateWebhookActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -25,17 +24,12 @@ export class UpdateWebhookActionHandlerService extends WorkspaceMigrationRunnerA
context: WorkspaceMigrationActionRunnerContext<FlatUpdateWebhookAction>,
): Promise<void> {
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, updates } = flatAction;
const { entityId, update } = flatAction;
const webhookRepository =
queryRunner.manager.getRepository<WebhookEntity>(WebhookEntity);
await webhookRepository.update(
{ id: entityId, workspaceId },
fromFlatEntityPropertiesUpdatesToPartialFlatEntity({
updates,
}),
);
await webhookRepository.update({ id: entityId, workspaceId }, update);
}
async executeForWorkspaceSchema(
@@ -6,6 +6,7 @@ import { LoggerService } from 'src/engine/core-modules/logger/logger.service';
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { AllFlatEntityTypesByMetadataName } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-types-by-metadata-name';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatEntityUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
import { MetadataRelatedFlatEntityMapsKeys } from 'src/engine/metadata-modules/flat-entity/types/metadata-related-flat-entity-maps-keys.type';
import { MetadataToFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/types/metadata-to-flat-entity-maps-key';
@@ -30,6 +31,7 @@ import {
import { optimisticallyApplyCreateActionOnAllFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/optimistically-apply-create-action-on-all-flat-entity-maps.util';
import { optimisticallyApplyDeleteActionOnAllFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/optimistically-apply-delete-action-on-all-flat-entity-maps.util';
import { optimisticallyApplyUpdateActionOnAllFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/optimistically-apply-update-action-on-all-flat-entity-maps.util';
import { sanitizeFlatEntityUpdate } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/sanitize-flat-entity-update.util';
type OptimisticallyApplyActionOnAllFlatEntityMapsArgs<
TFlatAction extends AllFlatWorkspaceMigrationAction,
@@ -131,11 +133,38 @@ export abstract class BaseWorkspaceMigrationRunnerActionHandlerService<
return Promise.resolve();
}
private sanitizeUniversalAction(
universalAction: TUniversalAction,
): TUniversalAction {
if (universalAction.type === 'update') {
const sanitizedFlatEntityUpdate = sanitizeFlatEntityUpdate({
metadataName: universalAction.metadataName,
flatEntityUpdate: universalAction.update as FlatEntityUpdate<
typeof universalAction.metadataName
>,
});
return {
...universalAction,
update: sanitizedFlatEntityUpdate,
};
}
return universalAction;
}
private async transpileUniversalActionToFlatActionOrThrow(
context: WorkspaceMigrationActionRunnerArgs<TUniversalAction>,
): Promise<TFlatAction> {
try {
return await this.transpileUniversalActionToFlatAction(context);
const sanitizedUniversalAction = this.sanitizeUniversalAction(
context.action,
);
return await this.transpileUniversalActionToFlatAction({
...context,
action: sanitizedUniversalAction,
});
} catch (error) {
throw new WorkspaceMigrationRunnerException({
action: context.action,
@@ -0,0 +1,64 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`sanitizeFlatEntityUpdate should handle agent metadata updates 1`] = `
{
"description": "Agent description",
"name": "My Agent",
}
`;
exports[`sanitizeFlatEntityUpdate should handle role metadata updates 1`] = `
{
"description": "Administrator role",
"label": "Admin Role",
}
`;
exports[`sanitizeFlatEntityUpdate should handle viewField metadata updates 1`] = `
{
"isVisible": true,
"position": 1,
"size": 100,
}
`;
exports[`sanitizeFlatEntityUpdate should handle webhook metadata updates 1`] = `
{
"description": "My webhook",
"targetUrl": "https://example.com/webhook",
}
`;
exports[`sanitizeFlatEntityUpdate should preserve null values as they are valid updates for fieldMetadata 1`] = `
{
"description": "Updated description",
"isActive": false,
"label": null,
}
`;
exports[`sanitizeFlatEntityUpdate should return empty object when all properties are undefined for fieldMetadata 1`] = `{}`;
exports[`sanitizeFlatEntityUpdate should return empty object when update is empty for fieldMetadata 1`] = `{}`;
exports[`sanitizeFlatEntityUpdate should return only valid properties for fieldMetadata when update contains valid and invalid properties 1`] = `
{
"isActive": true,
"label": "New Label",
}
`;
exports[`sanitizeFlatEntityUpdate should return only valid properties for objectMetadata 1`] = `
{
"isActive": true,
"labelPlural": "People",
"labelSingular": "Person",
}
`;
exports[`sanitizeFlatEntityUpdate should return only valid properties for view metadata 1`] = `
{
"icon": "IconUser",
"name": "My View",
}
`;
@@ -0,0 +1,132 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { sanitizeFlatEntityUpdate } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/sanitize-flat-entity-update.util';
describe('sanitizeFlatEntityUpdate', () => {
it('should return only valid properties for fieldMetadata when update contains valid and invalid properties', () => {
const result = sanitizeFlatEntityUpdate({
flatEntityUpdate: {
isActive: true,
label: 'New Label',
invalidProperty: 'should be removed',
} as any,
metadataName: 'fieldMetadata' as AllMetadataName,
});
expect(result).toMatchSnapshot();
});
it('should return empty object when all properties are undefined for fieldMetadata', () => {
const result = sanitizeFlatEntityUpdate({
flatEntityUpdate: {
isActive: undefined,
label: undefined,
} as any,
metadataName: 'fieldMetadata' as AllMetadataName,
});
expect(result).toMatchSnapshot();
});
it('should return empty object when update is empty for fieldMetadata', () => {
const result = sanitizeFlatEntityUpdate({
flatEntityUpdate: {} as any,
metadataName: 'fieldMetadata' as AllMetadataName,
});
expect(result).toMatchSnapshot();
});
it('should preserve null values as they are valid updates for fieldMetadata', () => {
const result = sanitizeFlatEntityUpdate({
flatEntityUpdate: {
isActive: false,
label: null,
description: 'Updated description',
} as any,
metadataName: 'fieldMetadata' as AllMetadataName,
});
expect(result).toMatchSnapshot();
});
it('should return only valid properties for view metadata', () => {
const result = sanitizeFlatEntityUpdate({
flatEntityUpdate: {
name: 'My View',
icon: 'IconUser',
invalidProperty: 'should be removed',
} as any,
metadataName: 'view' as AllMetadataName,
});
expect(result).toMatchSnapshot();
});
it('should return only valid properties for objectMetadata', () => {
const result = sanitizeFlatEntityUpdate({
flatEntityUpdate: {
isActive: true,
labelSingular: 'Person',
labelPlural: 'People',
invalidProperty: 'should be removed',
} as any,
metadataName: 'objectMetadata' as AllMetadataName,
});
expect(result).toMatchSnapshot();
});
it('should handle viewField metadata updates', () => {
const result = sanitizeFlatEntityUpdate({
flatEntityUpdate: {
position: 1,
size: 100,
isVisible: true,
invalidProperty: 'should be removed',
} as any,
metadataName: 'viewField' as AllMetadataName,
});
expect(result).toMatchSnapshot();
});
it('should handle role metadata updates', () => {
const result = sanitizeFlatEntityUpdate({
flatEntityUpdate: {
label: 'Admin Role',
description: 'Administrator role',
invalidProperty: 'should be removed',
} as any,
metadataName: 'role' as AllMetadataName,
});
expect(result).toMatchSnapshot();
});
it('should handle agent metadata updates', () => {
const result = sanitizeFlatEntityUpdate({
flatEntityUpdate: {
name: 'My Agent',
description: 'Agent description',
invalidProperty: 'should be removed',
} as any,
metadataName: 'agent' as AllMetadataName,
});
expect(result).toMatchSnapshot();
});
it('should handle webhook metadata updates', () => {
const result = sanitizeFlatEntityUpdate({
flatEntityUpdate: {
targetUrl: 'https://example.com/webhook',
description: 'My webhook',
invalidProperty: 'should be removed',
} as any,
metadataName: 'webhook' as AllMetadataName,
});
expect(result).toMatchSnapshot();
});
});
@@ -1,12 +0,0 @@
export const fromFlatEntityPropertiesUpdatesToPartialFlatEntity = <
T extends { updates: Array<{ property: string; to: unknown }> },
>(
action: T,
) => {
return action.updates.reduce((acc, { to, property }) => {
return {
...acc,
[property]: to,
};
}, {});
};
@@ -9,7 +9,6 @@ import { deleteFlatEntityFromFlatEntityAndRelatedEntityMapsThroughMutationOrThro
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util';
import { replaceFlatEntityInFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/utils/replace-flat-entity-in-flat-entity-maps-through-mutation-or-throw.util';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
type FlatUpdateAction<TMetadataName extends AllMetadataName> =
AllFlatEntityTypesByMetadataName[TMetadataName]['flatActions']['update'];
@@ -81,7 +80,7 @@ export const optimisticallyApplyUpdateActionOnAllFlatEntityMaps = <
const toFlatEntity = {
...fromFlatEntity,
...fromFlatEntityPropertiesUpdatesToPartialFlatEntity(flatAction),
...flatAction.update,
};
replaceFlatEntityInFlatEntityMapsThroughMutationOrThrow({
@@ -0,0 +1,34 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { ALL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY } from 'src/engine/metadata-modules/flat-entity/constant/all-flat-entity-properties-to-compare-and-stringify.constant';
import {
type FlatEntityUpdate,
type MetadataFlatEntityComparableProperties,
} from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
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);
};