Refactor delete objectMetadata action type and handler to be workspace agnostic (#17530)

# Introduction
Refactoring the delete and update field to use cached
flatEntitty.__universal.objectMetadataUniversalIdentifier to infer
related object
This commit is contained in:
Paul Rastoin
2026-01-29 12:19:19 +01:00
committed by GitHub
parent b15d092abd
commit 9b7bd1a6aa
7 changed files with 45 additions and 41 deletions
@@ -117,7 +117,6 @@ export class ApplicationResolver {
}
await this.workspaceMigrationRunnerService.run({
// @ts-expect-error ignoring until we implement a production ready validation schema for workspaceMigration
actions,
workspaceId,
});
@@ -21,7 +21,6 @@ describe('aggregateOrchestratorActionsReportDeprioritizeSearchVectorUpdateFieldA
type: 'update',
metadataName: 'fieldMetadata',
entityId: 'search-vector-field-1',
objectMetadataId: 'object-1',
updates: [
{
property: 'label',
@@ -34,7 +33,6 @@ describe('aggregateOrchestratorActionsReportDeprioritizeSearchVectorUpdateFieldA
type: 'update',
metadataName: 'fieldMetadata',
entityId: 'regular-field-1',
objectMetadataId: 'object-1',
updates: [
{
property: 'label',
@@ -47,7 +45,6 @@ describe('aggregateOrchestratorActionsReportDeprioritizeSearchVectorUpdateFieldA
type: 'update',
metadataName: 'fieldMetadata',
entityId: 'regular-field-2',
objectMetadataId: 'object-1',
updates: [
{
property: 'label',
@@ -12,12 +12,7 @@ export type CreateFieldAction = Omit<
};
export type UpdateFieldAction =
BaseUpdateWorkspaceMigrationAction<'fieldMetadata'> & {
objectMetadataId: string;
};
BaseUpdateWorkspaceMigrationAction<'fieldMetadata'>;
export type DeleteFieldAction =
BaseDeleteWorkspaceMigrationAction<'fieldMetadata'> & {
// Remove this
objectMetadataId: string;
};
BaseDeleteWorkspaceMigrationAction<'fieldMetadata'>;
@@ -2,7 +2,6 @@ import { Injectable } from '@nestjs/common';
import { ALL_METADATA_NAME } from 'twenty-shared/metadata';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { UpdateFieldAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/field/types/workspace-migration-field-action';
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';
@@ -73,7 +72,6 @@ export class WorkspaceMigrationFieldActionsBuilderService extends WorkspaceEntit
type: 'delete',
metadataName: 'fieldMetadata',
universalIdentifier: flatFieldMetadataToValidate.universalIdentifier,
objectMetadataId: flatFieldMetadataToValidate.objectMetadataId,
},
};
}
@@ -96,23 +94,12 @@ export class WorkspaceMigrationFieldActionsBuilderService extends WorkspaceEntit
};
}
const {
flatEntityId,
flatEntityUpdates,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
} = args;
const flatFieldMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityId: flatEntityId,
flatEntityMaps:
optimisticFlatEntityMapsAndRelatedFlatEntityMaps.flatFieldMetadataMaps,
});
const { flatEntityId, flatEntityUpdates } = args;
const updateFieldAction: UpdateFieldAction = {
type: 'update',
metadataName: 'fieldMetadata',
entityId: flatEntityId,
objectMetadataId: flatFieldMetadata.objectMetadataId,
updates: flatEntityUpdates,
};
@@ -1,12 +1,17 @@
import { Injectable } from '@nestjs/common';
import { isDefined } from 'twenty-shared/utils';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/interfaces/workspace-migration-runner-action-handler-service.interface';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
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 { WorkspaceSchemaManagerService } from 'src/engine/twenty-orm/workspace-schema-manager/workspace-schema-manager.service';
import { type DeleteFieldAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/field/types/workspace-migration-field-action';
import {
WorkspaceMigrationActionExecutionException,
WorkspaceMigrationActionExecutionExceptionCode,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/exceptions/workspace-migration-action-execution.exception';
import { type WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
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';
@@ -58,18 +63,28 @@ export class DeleteFieldActionHandlerService extends WorkspaceMigrationRunnerAct
allFlatEntityMaps: { flatObjectMetadataMaps, flatFieldMetadataMaps },
workspaceId,
} = context;
const { objectMetadataId, universalIdentifier } = action;
const flatObjectMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityMaps: flatObjectMetadataMaps,
flatEntityId: objectMetadataId,
});
const { universalIdentifier } = action;
const fieldMetadata = findFlatEntityByUniversalIdentifierOrThrow({
flatEntityMaps: flatFieldMetadataMaps,
universalIdentifier,
});
const objectMetadataUniversalIdentifier =
fieldMetadata.__universal?.objectMetadataUniversalIdentifier;
if (!isDefined(objectMetadataUniversalIdentifier)) {
throw new WorkspaceMigrationActionExecutionException({
message: `objectMetadataUniversalIdentifier is not defined for field metadata ${universalIdentifier}`,
code: WorkspaceMigrationActionExecutionExceptionCode.NOT_SUPPORTED,
});
}
const flatObjectMetadata = findFlatEntityByUniversalIdentifierOrThrow({
flatEntityMaps: flatObjectMetadataMaps,
universalIdentifier: objectMetadataUniversalIdentifier,
});
const { schemaName, tableName } = getWorkspaceSchemaContextForMigration({
workspaceId,
flatObjectMetadata,
@@ -12,6 +12,7 @@ import { getCompositeTypeOrThrow } from 'src/engine/metadata-modules/field-metad
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
import { FlatEntityPropertiesToCompare } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-to-compare.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';
@@ -89,11 +90,26 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
allFlatEntityMaps: { flatObjectMetadataMaps, flatFieldMetadataMaps },
workspaceId,
} = context;
const { objectMetadataId, entityId, updates } = action;
const { entityId, updates } = action;
const flatObjectMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityId: objectMetadataId,
const currentFlatFieldMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityId: entityId,
flatEntityMaps: flatFieldMetadataMaps,
});
const objectMetadataUniversalIdentifier =
currentFlatFieldMetadata.__universal?.objectMetadataUniversalIdentifier;
if (!isDefined(objectMetadataUniversalIdentifier)) {
throw new WorkspaceMigrationActionExecutionException({
message: `objectMetadataUniversalIdentifier is not defined for field metadata ${entityId}`,
code: WorkspaceMigrationActionExecutionExceptionCode.NOT_SUPPORTED,
});
}
const flatObjectMetadata = findFlatEntityByUniversalIdentifierOrThrow({
flatEntityMaps: flatObjectMetadataMaps,
universalIdentifier: objectMetadataUniversalIdentifier,
});
const { schemaName, tableName } = getWorkspaceSchemaContextForMigration({
@@ -101,11 +117,6 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
flatObjectMetadata,
});
const currentFlatFieldMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityId: entityId,
flatEntityMaps: flatFieldMetadataMaps,
});
let optimisticFlatFieldMetadata = structuredClone(currentFlatFieldMetadata);
const defaultValueUpdate = findFlatEntityPropertyUpdate({
@@ -17,7 +17,7 @@ exports[`Install application should fail when entity does not exist should fail
},
"workspaceSchema": {
"code": "ENTITY_NOT_FOUND",
"message": "Could not find flat entity in maps",
"message": "Could not find flat entity with universal identifier 20202020-6110-4547-9fd0-2525257a2c3f",
},
},
"exceptionEventId": Any<String>,