Flat entity maps cache generic service + runner dynamically retrieving invalidating update cache + view service v2 refactor (#14508)

# Introduction
Migrate previous runner only iterating on `flatObjectMetadataMaps` to
`allFlatEntityMaps`.
Refactored the optimistic to be handled inside the actions handler

## Workspace flat map cache
Introducing a new service and registry, that will dynamically retrieve
and or recompute requested cache when called

## Runner refactor
Runner now dynamically invalidate updated cache at the end of the
transaction

close
https://github.com/orgs/twentyhq/projects/1/views/8?pane=issue&itemId=129136356&issue=twentyhq%7Ccore-team-issues%7C1492
close
https://github.com/orgs/twentyhq/projects/1/views/8?pane=issue&itemId=129136210&issue=twentyhq%7Ccore-team-issues%7C1494
This commit is contained in:
Paul Rastoin
2025-09-16 14:39:42 +02:00
committed by GitHub
parent 8f42c33bd4
commit 371c26bc9b
79 changed files with 1534 additions and 575 deletions
@@ -10,11 +10,10 @@ import { ObjectMetadataHealthService } from 'src/engine/workspace-manager/worksp
import { WorkspaceHealthService } from 'src/engine/workspace-manager/workspace-health/workspace-health.service';
import { WorkspaceMigrationBuilderModule } from 'src/engine/workspace-manager/workspace-migration-builder/workspace-migration-builder.module';
import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.module';
import { WorkspaceFixService } from 'src/engine/workspace-manager/workspace-health/services/workspace-fix.service';
import { workspaceFixers } from './fixer';
import { WorkspaceFixService } from './services/workspace-fix.service';
@Module({
imports: [
DataSourceModule,
@@ -4,11 +4,10 @@ import { WorkspaceMigrationModule } from 'src/engine/metadata-modules/workspace-
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
import { WorkspaceMigrationColumnService } from 'src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-column.service';
import { WorkspaceMigrationEnumService } from 'src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-enum.service';
import { WorkspaceMigrationTypeService } from 'src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-type.service';
import { WorkspaceMigrationRunnerService } from './workspace-migration-runner.service';
import { WorkspaceMigrationTypeService } from './services/workspace-migration-type.service';
@Module({
imports: [WorkspaceDataSourceModule, WorkspaceMigrationModule],
providers: [
@@ -1,4 +1,4 @@
import { type AllFlatEntitiesByMetadataEngineName } from 'src/engine/core-modules/common/types/all-flat-entities.type';
import { type AllFlatEntitiesByMetadataEngineName } from 'src/engine/core-modules/common/types/all-flat-entities-by-metadata-engine-name.type';
import { type FieldMetadataMinimalInformation } from 'src/engine/metadata-modules/flat-field-metadata/types/field-metadata-minimal-information.type';
import { type FlatFieldMetadataValidationError } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-validation-error.type';
import { type FlatObjectMetadataValidationError } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata-validation-error.type';
@@ -165,9 +165,14 @@ export class WorkspaceMigrationBuildOrchestratorService {
};
}
const relatedFlatEntityMapsKeys = Object.keys(
fromToAllFlatEntityMaps,
) as (keyof AllFlatEntityMaps)[];
return {
status: 'success',
workspaceMigration: {
relatedFlatEntityMapsKeys,
actions: allActions,
workspaceId,
},
@@ -1,6 +1,6 @@
import { type FromTo } from 'twenty-shared/types';
import { type AllFlatEntitiesByMetadataEngineName } from 'src/engine/core-modules/common/types/all-flat-entities.type';
import { type AllFlatEntitiesByMetadataEngineName } from 'src/engine/core-modules/common/types/all-flat-entities-by-metadata-engine-name.type';
import { type AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { type FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/types/failed-flat-entity-validation.type';
import { type WorkspaceMigrationV2BuilderOptions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-builder-v2.service';
@@ -0,0 +1,6 @@
import { type AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
export type ViewFieldRelatedFlatEntityMaps = Pick<
AllFlatEntityMaps,
'flatObjectMetadataMaps' | 'flatViewMaps'
>;
@@ -1,8 +1,8 @@
import { Injectable } from '@nestjs/common';
import { AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { FlatViewField } from 'src/engine/core-modules/view/flat-view/types/flat-view-field.type';
import { compareTwoFlatViewField } from 'src/engine/core-modules/view/flat-view/utils/compare-two-flat-view-field.util';
import { ViewFieldRelatedFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/types/view-field-related-flat-entity-maps.type';
import {
FlatEntityUpdateValidationArgs,
FlatEntityValidationArgs,
@@ -19,10 +19,6 @@ import {
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-view-field-action';
import { FlatViewFieldValidatorService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/validators/services/flat-view-field-validator.service';
export type ViewFieldRelatedFlatEntityMaps = Pick<
AllFlatEntityMaps,
'flatObjectMetadataMaps' | 'flatViewMaps'
>;
@Injectable()
export class WorkspaceMigrationV2ViewFieldActionsBuilderService extends WorkspaceEntityMigrationBuilderV2Service<
FlatViewField,
@@ -1,3 +1,4 @@
import { type AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { type WorkspaceMigrationActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-action-common-v2';
export type WorkspaceMigrationV2<
@@ -9,5 +10,5 @@ export type WorkspaceMigrationV2<
// description?: string;
actions: TActions[];
workspaceId: string;
// objectActions: TActions[] // could be cool ?
relatedFlatEntityMapsKeys?: (keyof AllFlatEntityMaps)[];
};
@@ -8,7 +8,7 @@ import { FlatViewFieldMaps } from 'src/engine/core-modules/view/flat-view/types/
import { FlatViewField } from 'src/engine/core-modules/view/flat-view/types/flat-view-field.type';
import { findFlatFieldMetadataInFlatObjectMetadataMapsWithOnlyFieldId } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-field-metadata-in-flat-object-metadata-maps-with-field-id-only.util';
import { FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/types/failed-flat-entity-validation.type';
import { ViewFieldRelatedFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view-field/workspace-migration-v2-view-field-actions-builder.service';
import { ViewFieldRelatedFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/types/view-field-related-flat-entity-maps.type';
type ViewFieldValidationArgs = {
flatViewFieldToValidate: FlatViewField;
@@ -1,8 +1,13 @@
import { Injectable } from '@nestjs/common';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import {
OptimisticallyApplyActionOnAllFlatEntityMapsArgs,
WorkspaceMigrationRunnerActionHandler,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import { AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { addFlatFieldMetadataInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/add-flat-field-metadata-in-flat-object-metadata-maps-or-throw.util';
import { findFlatObjectMetadataWithFlatFieldMapsInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-object-metadata-with-flat-field-maps-in-flat-object-metadata-maps-or-throw.util';
import { WorkspaceSchemaManagerService } from 'src/engine/twenty-orm/workspace-schema-manager/workspace-schema-manager.service';
import { type CreateFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2';
@@ -25,6 +30,22 @@ export class CreateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
super();
}
optimisticallyApplyActionOnAllFlatEntityMaps({
action,
allFlatEntityMaps,
}: OptimisticallyApplyActionOnAllFlatEntityMapsArgs<CreateFieldAction>): Partial<AllFlatEntityMaps> {
const { flatObjectMetadataMaps } = allFlatEntityMaps;
const updatedFlatObjectMetadataMaps =
addFlatFieldMetadataInFlatObjectMetadataMapsOrThrow({
flatFieldMetadata: action.flatFieldMetadata,
flatObjectMetadataMaps,
});
return {
flatObjectMetadataMaps: updatedFlatObjectMetadataMaps,
};
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerArgs<CreateFieldAction>,
): Promise<void> {
@@ -42,8 +63,12 @@ export class CreateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
async executeForWorkspaceSchema(
context: WorkspaceMigrationActionRunnerArgs<CreateFieldAction>,
): Promise<void> {
const { action, queryRunner, flatObjectMetadataMaps, workspaceId } =
context;
const {
action,
queryRunner,
allFlatEntityMaps: { flatObjectMetadataMaps },
workspaceId,
} = context;
const { flatFieldMetadata } = action;
const flatObjectMetadataWithFlatFieldMaps =
@@ -2,9 +2,14 @@ import { Injectable } from '@nestjs/common';
import { In } from 'typeorm';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import {
OptimisticallyApplyActionOnAllFlatEntityMapsArgs,
WorkspaceMigrationRunnerActionHandler,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import { AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { deleteFieldFromFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/delete-field-from-flat-object-metadata-maps-or-throw.util';
import { findFlatFieldMetadataInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-field-metadata-in-flat-object-metadata-maps-or-throw.util';
import { findFlatObjectMetadataInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-object-metadata-in-flat-object-metadata-maps-or-throw.util';
import { findFlatObjectMetadataWithFlatFieldMapsInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-object-metadata-with-flat-field-maps-in-flat-object-metadata-maps-or-throw.util';
@@ -29,6 +34,25 @@ export class DeleteFieldActionHandlerService extends WorkspaceMigrationRunnerAct
super();
}
optimisticallyApplyActionOnAllFlatEntityMaps({
action,
allFlatEntityMaps,
}: OptimisticallyApplyActionOnAllFlatEntityMapsArgs<DeleteFieldAction>): Partial<AllFlatEntityMaps> {
const { flatObjectMetadataMaps } = allFlatEntityMaps;
const { fieldMetadataId, objectMetadataId } = action;
const updatedFlatObjectMetadataMaps =
deleteFieldFromFlatObjectMetadataMapsOrThrow({
fieldMetadataId,
flatObjectMetadataMaps,
objectMetadataId,
});
return {
flatObjectMetadataMaps: updatedFlatObjectMetadataMaps,
};
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerArgs<DeleteFieldAction>,
) {
@@ -48,8 +72,12 @@ export class DeleteFieldActionHandlerService extends WorkspaceMigrationRunnerAct
async executeForWorkspaceSchema(
context: WorkspaceMigrationActionRunnerArgs<DeleteFieldAction>,
) {
const { action, queryRunner, flatObjectMetadataMaps, workspaceId } =
context;
const {
action,
queryRunner,
allFlatEntityMaps: { flatObjectMetadataMaps },
workspaceId,
} = context;
const { objectMetadataId, fieldMetadataId } = action;
const flatObjectMetadataWithFlatFieldMaps =
@@ -4,8 +4,12 @@ import { FieldMetadataType } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { ColumnType, type QueryRunner } from 'typeorm';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import {
OptimisticallyApplyActionOnAllFlatEntityMapsArgs,
WorkspaceMigrationRunnerActionHandler,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import { AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { MorphOrRelationFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/types/morph-or-relation-field-metadata-type.type';
import { computeCompositeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
@@ -17,7 +21,9 @@ import { isCompositeFlatFieldMetadata } from 'src/engine/metadata-modules/flat-f
import { isEnumFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-enum-flat-field-metadata.util';
import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
import { findFlatFieldMetadataInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-field-metadata-in-flat-object-metadata-maps-or-throw.util';
import { findFlatFieldMetadataInFlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-field-metadata-in-flat-object-metadata-maps.util';
import { findFlatObjectMetadataWithFlatFieldMapsInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-object-metadata-with-flat-field-maps-in-flat-object-metadata-maps-or-throw.util';
import { replaceFlatFieldMetadataInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/replace-flat-field-metadata-in-flat-object-metadata-maps-or-throw.util';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { fromFlatObjectMetadataWithFlatFieldMapsToFlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/utils/from-flat-object-metadata-with-flat-field-maps-to-flat-object-metadatas.util';
import { fieldMetadataTypeToColumnType } from 'src/engine/metadata-modules/workspace-migration/utils/field-metadata-type-to-column-type.util';
@@ -61,6 +67,43 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
super();
}
optimisticallyApplyActionOnAllFlatEntityMaps({
action,
allFlatEntityMaps,
}: OptimisticallyApplyActionOnAllFlatEntityMapsArgs<UpdateFieldAction>): Partial<AllFlatEntityMaps> {
const { flatObjectMetadataMaps } = allFlatEntityMaps;
const { fieldMetadataId, objectMetadataId } = action;
const existingFlatFieldMetadata =
findFlatFieldMetadataInFlatObjectMetadataMaps({
fieldMetadataId,
objectMetadataId,
flatObjectMetadataMaps,
});
if (!isDefined(existingFlatFieldMetadata)) {
throw new WorkspaceMigrationRunnerException(
`Workspace migration failed: Field metadata not found in cache`,
WorkspaceMigrationRunnerExceptionCode.FIELD_METADATA_NOT_FOUND,
);
}
const updatedFlatFieldMetadata = {
...existingFlatFieldMetadata,
...fromWorkspaceMigrationUpdateActionToPartialEntity(action),
};
const updatedFlatObjectMetadataMaps =
replaceFlatFieldMetadataInFlatObjectMetadataMapsOrThrow({
flatFieldMetadata: updatedFlatFieldMetadata,
flatObjectMetadataMaps,
});
return {
flatObjectMetadataMaps: updatedFlatObjectMetadataMaps,
};
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerArgs<UpdateFieldAction>,
): Promise<void> {
@@ -81,8 +124,12 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
async executeForWorkspaceSchema(
context: WorkspaceMigrationActionRunnerArgs<UpdateFieldAction>,
): Promise<void> {
const { action, queryRunner, flatObjectMetadataMaps, workspaceId } =
context;
const {
action,
queryRunner,
allFlatEntityMaps: { flatObjectMetadataMaps },
workspaceId,
} = context;
const { objectMetadataId, fieldMetadataId, updates } = action;
const flatObjectMetadataWithFlatFieldMaps =
@@ -1,7 +1,11 @@
import { Injectable } from '@nestjs/common';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import {
OptimisticallyApplyActionOnAllFlatEntityMapsArgs,
WorkspaceMigrationRunnerActionHandler,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import { AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { type CreateIndexAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-index-action-v2';
import { type WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/types/workspace-migration-action-runner-args.type';
@@ -9,6 +13,12 @@ import { type WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-ma
export class CreateIndexActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
'create_index',
) {
optimisticallyApplyActionOnAllFlatEntityMaps(
_args: OptimisticallyApplyActionOnAllFlatEntityMapsArgs<CreateIndexAction>,
): Partial<AllFlatEntityMaps> {
return {};
}
async executeForMetadata(
_context: WorkspaceMigrationActionRunnerArgs<CreateIndexAction>,
): Promise<void> {
@@ -1,7 +1,11 @@
import { Injectable } from '@nestjs/common';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import {
OptimisticallyApplyActionOnAllFlatEntityMapsArgs,
WorkspaceMigrationRunnerActionHandler,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import { AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { type DeleteIndexAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-index-action-v2';
import { type WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/types/workspace-migration-action-runner-args.type';
@@ -9,6 +13,12 @@ import { type WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-ma
export class DeleteIndexActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
'delete_index',
) {
optimisticallyApplyActionOnAllFlatEntityMaps(
_args: OptimisticallyApplyActionOnAllFlatEntityMapsArgs<DeleteIndexAction>,
): Partial<AllFlatEntityMaps> {
return {};
}
async executeForMetadata(
_context: WorkspaceMigrationActionRunnerArgs<DeleteIndexAction>,
): Promise<void> {
@@ -1,13 +1,17 @@
import { Injectable } from '@nestjs/common';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import {
OptimisticallyApplyActionOnAllFlatEntityMapsArgs,
WorkspaceMigrationRunnerActionHandler,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import { AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
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 { addFlatObjectMetadataToFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/add-flat-object-metadata-to-flat-object-metadata-maps-or-throw.util';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { WorkspaceSchemaManagerService } from 'src/engine/twenty-orm/workspace-schema-manager/workspace-schema-manager.service';
import { type CreateObjectAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2';
import { type WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/types/workspace-migration-action-runner-args.type';
@@ -25,11 +29,36 @@ export class CreateObjectActionHandlerService extends WorkspaceMigrationRunnerAc
) {
constructor(
private readonly workspaceSchemaManagerService: WorkspaceSchemaManagerService,
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
) {
super();
}
optimisticallyApplyActionOnAllFlatEntityMaps({
action,
allFlatEntityMaps,
}: OptimisticallyApplyActionOnAllFlatEntityMapsArgs<CreateObjectAction>): Partial<AllFlatEntityMaps> {
const { flatObjectMetadataMaps } = allFlatEntityMaps;
const { flatObjectMetadataWithoutFields, createFieldActions } = action;
const flatFieldMetadatas = createFieldActions.map(
(createFieldAction) => createFieldAction.flatFieldMetadata,
);
const updatedFlatObjectMetadataMaps =
addFlatObjectMetadataToFlatObjectMetadataMapsOrThrow({
flatObjectMetadata: {
...flatObjectMetadataWithoutFields,
flatIndexMetadatas: [],
flatFieldMetadatas,
},
flatObjectMetadataMaps,
});
return {
flatObjectMetadataMaps: updatedFlatObjectMetadataMaps,
};
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerArgs<CreateObjectAction>,
): Promise<void> {
@@ -1,10 +1,15 @@
import { Injectable } from '@nestjs/common';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import {
OptimisticallyApplyActionOnAllFlatEntityMapsArgs,
WorkspaceMigrationRunnerActionHandler,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import { AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { type 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 { deleteObjectFromFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/delete-object-from-flat-object-metadata-maps-or-throw.util';
import { findFlatObjectMetadataWithFlatFieldMapsInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-object-metadata-with-flat-field-maps-in-flat-object-metadata-maps-or-throw.util';
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';
@@ -27,6 +32,24 @@ export class DeleteObjectActionHandlerService extends WorkspaceMigrationRunnerAc
super();
}
optimisticallyApplyActionOnAllFlatEntityMaps({
action,
allFlatEntityMaps,
}: OptimisticallyApplyActionOnAllFlatEntityMapsArgs<DeleteObjectAction>): Partial<AllFlatEntityMaps> {
const { flatObjectMetadataMaps } = allFlatEntityMaps;
const { objectMetadataId } = action;
const updatedFlatObjectMetadataMaps =
deleteObjectFromFlatObjectMetadataMapsOrThrow({
flatObjectMetadataMaps,
objectMetadataId,
});
return {
flatObjectMetadataMaps: updatedFlatObjectMetadataMaps,
};
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerArgs<DeleteObjectAction>,
): Promise<void> {
@@ -44,8 +67,12 @@ export class DeleteObjectActionHandlerService extends WorkspaceMigrationRunnerAc
async executeForWorkspaceSchema(
context: WorkspaceMigrationActionRunnerArgs<DeleteObjectAction>,
): Promise<void> {
const { action, queryRunner, flatObjectMetadataMaps, workspaceId } =
context;
const {
action,
queryRunner,
allFlatEntityMaps: { flatObjectMetadataMaps },
workspaceId,
} = context;
const { objectMetadataId } = action;
const flatObjectMetadataWithFlatFieldMaps =
@@ -1,11 +1,17 @@
import { Injectable } from '@nestjs/common';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import {
OptimisticallyApplyActionOnAllFlatEntityMapsArgs,
WorkspaceMigrationRunnerActionHandler,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import { AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { type 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 { findFlatObjectMetadataInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-object-metadata-in-flat-object-metadata-maps-or-throw.util';
import { findFlatObjectMetadataWithFlatFieldMapsInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-object-metadata-with-flat-field-maps-in-flat-object-metadata-maps-or-throw.util';
import { replaceFlatObjectMetadataInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/replace-flat-object-metadata-in-flat-object-metadata-maps-or-throw.util';
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';
@@ -29,6 +35,35 @@ export class UpdateObjectActionHandlerService extends WorkspaceMigrationRunnerAc
super();
}
optimisticallyApplyActionOnAllFlatEntityMaps({
action,
allFlatEntityMaps,
}: OptimisticallyApplyActionOnAllFlatEntityMapsArgs<UpdateObjectAction>): Partial<AllFlatEntityMaps> {
const { flatObjectMetadataMaps } = allFlatEntityMaps;
const { objectMetadataId } = action;
const existingFlatObjectMetadata =
findFlatObjectMetadataInFlatObjectMetadataMapsOrThrow({
objectMetadataId,
flatObjectMetadataMaps,
});
const updatedFlatObjectMetadata = {
...existingFlatObjectMetadata,
...fromWorkspaceMigrationUpdateActionToPartialEntity(action),
};
const updatedFlatObjectMetadataMaps =
replaceFlatObjectMetadataInFlatObjectMetadataMapsOrThrow({
flatObjectMetadata: updatedFlatObjectMetadata,
flatObjectMetadataMaps,
});
return {
flatObjectMetadataMaps: updatedFlatObjectMetadataMaps,
};
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerArgs<UpdateObjectAction>,
): Promise<void> {
@@ -48,8 +83,12 @@ export class UpdateObjectActionHandlerService extends WorkspaceMigrationRunnerAc
async executeForWorkspaceSchema(
context: WorkspaceMigrationActionRunnerArgs<UpdateObjectAction>,
): Promise<void> {
const { action, queryRunner, flatObjectMetadataMaps, workspaceId } =
context;
const {
action,
queryRunner,
allFlatEntityMaps: { flatObjectMetadataMaps },
workspaceId,
} = context;
const { objectMetadataId, updates } = action;
const flatObjectMetadataWithFlatFieldMaps =
@@ -1,7 +1,12 @@
import { Injectable } from '@nestjs/common';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import {
OptimisticallyApplyActionOnAllFlatEntityMapsArgs,
WorkspaceMigrationRunnerActionHandler,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import { AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/core-modules/common/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
import { ViewFieldEntity } from 'src/engine/core-modules/view/entities/view-field.entity';
import { CreateViewFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-field-action-v2.type';
import { WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/types/workspace-migration-action-runner-args.type';
@@ -14,6 +19,23 @@ export class CreateViewFieldActionHandlerService extends WorkspaceMigrationRunne
super();
}
optimisticallyApplyActionOnAllFlatEntityMaps({
action,
allFlatEntityMaps,
}: OptimisticallyApplyActionOnAllFlatEntityMapsArgs<CreateViewFieldAction>): Partial<AllFlatEntityMaps> {
const { flatViewFieldMaps } = allFlatEntityMaps;
const { viewField } = action;
const updatedFlatViewFieldMaps = addFlatEntityToFlatEntityMapsOrThrow({
flatEntity: viewField,
flatEntityMaps: flatViewFieldMaps,
});
return {
flatViewFieldMaps: updatedFlatViewFieldMaps,
};
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerArgs<CreateViewFieldAction>,
): Promise<void> {
@@ -1,7 +1,12 @@
import { Injectable } from '@nestjs/common';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import {
OptimisticallyApplyActionOnAllFlatEntityMapsArgs,
WorkspaceMigrationRunnerActionHandler,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import { AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { deleteFlatEntityFromFlatEntityMapsOrThrow } from 'src/engine/core-modules/common/utils/delete-flat-entity-from-flat-entity-maps-or-throw.util';
import { ViewFieldEntity } from 'src/engine/core-modules/view/entities/view-field.entity';
import { DeleteViewFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-field-action-v2.type';
import { WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/types/workspace-migration-action-runner-args.type';
@@ -14,6 +19,23 @@ export class DeleteViewFieldActionHandlerService extends WorkspaceMigrationRunne
super();
}
optimisticallyApplyActionOnAllFlatEntityMaps({
action,
allFlatEntityMaps,
}: OptimisticallyApplyActionOnAllFlatEntityMapsArgs<DeleteViewFieldAction>): Partial<AllFlatEntityMaps> {
const { flatViewFieldMaps } = allFlatEntityMaps;
const { viewFieldId } = action;
const updatedFlatViewFieldMaps = deleteFlatEntityFromFlatEntityMapsOrThrow({
entityToDeleteId: viewFieldId,
flatEntityMaps: flatViewFieldMaps,
});
return {
flatViewFieldMaps: updatedFlatViewFieldMaps,
};
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerArgs<DeleteViewFieldAction>,
): Promise<void> {
@@ -1,7 +1,13 @@
import { Injectable } from '@nestjs/common';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import {
OptimisticallyApplyActionOnAllFlatEntityMapsArgs,
WorkspaceMigrationRunnerActionHandler,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import { AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/core-modules/common/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { replaceFlatEntityInFlatEntityMapsOrThrow } from 'src/engine/core-modules/common/utils/replace-flat-entity-in-flat-entity-maps-or-throw.util';
import { ViewFieldEntity } from 'src/engine/core-modules/view/entities/view-field.entity';
import { UpdateViewFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-field-action-v2.type';
import { WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/types/workspace-migration-action-runner-args.type';
@@ -15,6 +21,33 @@ export class UpdateViewFieldActionHandlerService extends WorkspaceMigrationRunne
super();
}
optimisticallyApplyActionOnAllFlatEntityMaps({
action,
allFlatEntityMaps,
}: OptimisticallyApplyActionOnAllFlatEntityMapsArgs<UpdateViewFieldAction>): Partial<AllFlatEntityMaps> {
const { flatViewFieldMaps } = allFlatEntityMaps;
const { viewFieldId } = action;
const existingViewField = findFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityId: viewFieldId,
flatEntityMaps: flatViewFieldMaps,
});
const updatedViewField = {
...existingViewField,
...fromWorkspaceMigrationUpdateActionToPartialEntity(action),
};
const updatedFlatViewFieldMaps = replaceFlatEntityInFlatEntityMapsOrThrow({
flatEntity: updatedViewField,
flatEntityMaps: flatViewFieldMaps,
});
return {
flatViewFieldMaps: updatedFlatViewFieldMaps,
};
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerArgs<UpdateViewFieldAction>,
): Promise<void> {
@@ -1,7 +1,12 @@
import { Injectable } from '@nestjs/common';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import {
OptimisticallyApplyActionOnAllFlatEntityMapsArgs,
WorkspaceMigrationRunnerActionHandler,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import { AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/core-modules/common/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
import { ViewEntity } from 'src/engine/core-modules/view/entities/view.entity';
import { CreateViewAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-action-v2.type';
import { WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/types/workspace-migration-action-runner-args.type';
@@ -14,6 +19,23 @@ export class CreateViewActionHandlerService extends WorkspaceMigrationRunnerActi
super();
}
optimisticallyApplyActionOnAllFlatEntityMaps({
action,
allFlatEntityMaps,
}: OptimisticallyApplyActionOnAllFlatEntityMapsArgs<CreateViewAction>): Partial<AllFlatEntityMaps> {
const { flatViewMaps } = allFlatEntityMaps;
const { view } = action;
const updatedFlatViewMaps = addFlatEntityToFlatEntityMapsOrThrow({
flatEntity: view,
flatEntityMaps: flatViewMaps,
});
return {
flatViewMaps: updatedFlatViewMaps,
};
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerArgs<CreateViewAction>,
): Promise<void> {
@@ -1,7 +1,12 @@
import { Injectable } from '@nestjs/common';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import {
OptimisticallyApplyActionOnAllFlatEntityMapsArgs,
WorkspaceMigrationRunnerActionHandler,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import { AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { deleteFlatEntityFromFlatEntityMapsOrThrow } from 'src/engine/core-modules/common/utils/delete-flat-entity-from-flat-entity-maps-or-throw.util';
import { ViewEntity } from 'src/engine/core-modules/view/entities/view.entity';
import { DeleteViewAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-action-v2.type';
import { WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/types/workspace-migration-action-runner-args.type';
@@ -14,6 +19,23 @@ export class DeleteViewActionHandlerService extends WorkspaceMigrationRunnerActi
super();
}
optimisticallyApplyActionOnAllFlatEntityMaps({
action,
allFlatEntityMaps,
}: OptimisticallyApplyActionOnAllFlatEntityMapsArgs<DeleteViewAction>): Partial<AllFlatEntityMaps> {
const { flatViewMaps } = allFlatEntityMaps;
const { viewId } = action;
const updatedFlatViewMaps = deleteFlatEntityFromFlatEntityMapsOrThrow({
entityToDeleteId: viewId,
flatEntityMaps: flatViewMaps,
});
return {
flatViewMaps: updatedFlatViewMaps,
};
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerArgs<DeleteViewAction>,
): Promise<void> {
@@ -1,7 +1,13 @@
import { Injectable } from '@nestjs/common';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import {
OptimisticallyApplyActionOnAllFlatEntityMapsArgs,
WorkspaceMigrationRunnerActionHandler,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import { AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/core-modules/common/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { replaceFlatEntityInFlatEntityMapsOrThrow } from 'src/engine/core-modules/common/utils/replace-flat-entity-in-flat-entity-maps-or-throw.util';
import { ViewEntity } from 'src/engine/core-modules/view/entities/view.entity';
import { UpdateViewAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-action-v2.type';
import { WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/types/workspace-migration-action-runner-args.type';
@@ -15,6 +21,33 @@ export class UpdateViewActionHandlerService extends WorkspaceMigrationRunnerActi
super();
}
optimisticallyApplyActionOnAllFlatEntityMaps({
action,
allFlatEntityMaps,
}: OptimisticallyApplyActionOnAllFlatEntityMapsArgs<UpdateViewAction>): Partial<AllFlatEntityMaps> {
const { flatViewMaps } = allFlatEntityMaps;
const { viewId } = action;
const existingView = findFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityId: viewId,
flatEntityMaps: flatViewMaps,
});
const updatedView = {
...existingView,
...fromWorkspaceMigrationUpdateActionToPartialEntity(action),
};
const updatedFlatViewMaps = replaceFlatEntityInFlatEntityMapsOrThrow({
flatEntity: updatedView,
flatEntityMaps: flatViewMaps,
});
return {
flatViewMaps: updatedFlatViewMaps,
};
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerArgs<UpdateViewAction>,
): Promise<void> {
@@ -14,4 +14,5 @@ export const WorkspaceMigrationRunnerExceptionCode = appendCommonExceptionCode({
UNSUPPORTED_COMPOSITE_COLUMN_TYPE: 'UNSUPPORTED_COMPOSITE_COLUMN_TYPE',
NOT_SUPPORTED: 'NOT_SUPPORTED',
INVALID_ACTION_TYPE: 'INVALID_ACTION_TYPE',
FLAT_ENTITY_NOT_FOUND: 'FLAT_ENTITY_NOT_FOUND',
} as const);
@@ -1,46 +1,68 @@
import { SetMetadata } from '@nestjs/common';
import { type AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import {
type ExtractAction,
type WorkspaceMigrationActionTypeV2,
type WorkspaceMigrationActionV2,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-action-common-v2';
import { WORKSPACE_MIGRATION_ACTION_HANDLER_METADATA_KEY } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/constants/workspace-migration-action-handler-metadata-key.constant';
import { type WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/types/workspace-migration-action-runner-args.type';
export interface WorkspaceMigrationRunnerActionHandlerService<
T extends WorkspaceMigrationActionTypeV2,
TActionType extends WorkspaceMigrationActionTypeV2,
> {
execute(
context: WorkspaceMigrationActionRunnerArgs<ExtractAction<T>>,
): Promise<void>;
context: WorkspaceMigrationActionRunnerArgs<ExtractAction<TActionType>>,
): Promise<Partial<AllFlatEntityMaps>>;
}
export type OptimisticallyApplyActionOnAllFlatEntityMapsArgs<
TActionType extends WorkspaceMigrationActionV2,
> = Pick<
WorkspaceMigrationActionRunnerArgs<TActionType>,
'allFlatEntityMaps' | 'action'
>;
export abstract class BaseWorkspaceMigrationRunnerActionHandlerService<
T extends WorkspaceMigrationActionTypeV2,
> implements WorkspaceMigrationRunnerActionHandlerService<T>
TActionType extends WorkspaceMigrationActionTypeV2,
> implements WorkspaceMigrationRunnerActionHandlerService<TActionType>
{
abstract executeForMetadata(
context: WorkspaceMigrationActionRunnerArgs<ExtractAction<T>>,
context: WorkspaceMigrationActionRunnerArgs<ExtractAction<TActionType>>,
): Promise<void>;
abstract executeForWorkspaceSchema(
context: WorkspaceMigrationActionRunnerArgs<ExtractAction<T>>,
context: WorkspaceMigrationActionRunnerArgs<ExtractAction<TActionType>>,
): Promise<void>;
abstract optimisticallyApplyActionOnAllFlatEntityMaps(
args: OptimisticallyApplyActionOnAllFlatEntityMapsArgs<
ExtractAction<TActionType>
>,
): Partial<AllFlatEntityMaps>;
async execute(
context: WorkspaceMigrationActionRunnerArgs<ExtractAction<T>>,
): Promise<void> {
context: WorkspaceMigrationActionRunnerArgs<ExtractAction<TActionType>>,
): Promise<Partial<AllFlatEntityMaps>> {
await Promise.all([
this.executeForMetadata(context),
this.executeForWorkspaceSchema(context),
]);
return this.optimisticallyApplyActionOnAllFlatEntityMaps({
action: context.action,
allFlatEntityMaps: context.allFlatEntityMaps,
});
}
}
export function WorkspaceMigrationRunnerActionHandler<
T extends WorkspaceMigrationActionTypeV2,
>(actionType: T): typeof BaseWorkspaceMigrationRunnerActionHandlerService<T> {
abstract class ActionHandlerService extends BaseWorkspaceMigrationRunnerActionHandlerService<T> {}
TActionType extends WorkspaceMigrationActionTypeV2,
>(
actionType: TActionType,
): typeof BaseWorkspaceMigrationRunnerActionHandlerService<TActionType> {
abstract class ActionHandlerService extends BaseWorkspaceMigrationRunnerActionHandlerService<TActionType> {}
SetMetadata(
WORKSPACE_MIGRATION_ACTION_HANDLER_METADATA_KEY,
@@ -3,6 +3,7 @@ import { DiscoveryService } from '@nestjs/core';
import { type WorkspaceMigrationRunnerActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface';
import { AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import {
type WorkspaceMigrationActionTypeV2,
type WorkspaceMigrationActionV2,
@@ -54,7 +55,7 @@ export class WorkspaceMigrationRunnerActionHandlerRegistryService
async executeActionHandler<T extends WorkspaceMigrationActionV2>(
actionType: WorkspaceMigrationActionTypeV2,
context: WorkspaceMigrationActionRunnerArgs<T>,
): Promise<void> {
): Promise<Partial<AllFlatEntityMaps>> {
const handler = this.actionHandlers.get(actionType);
if (!handler) {
@@ -64,6 +65,6 @@ export class WorkspaceMigrationRunnerActionHandlerRegistryService
);
}
await handler.execute(context);
return await handler.execute(context);
}
}
@@ -3,77 +3,81 @@ import { InjectDataSource } from '@nestjs/typeorm';
import { DataSource } from 'typeorm';
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
import { WorkspaceMetadataCacheService } from 'src/engine/metadata-modules/workspace-metadata-cache/services/workspace-metadata-cache.service';
import { WorkspaceMetadataVersionService } from 'src/engine/metadata-modules/workspace-metadata-version/services/workspace-metadata-version.service';
import { WorkspacePermissionsCacheService } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service';
import { type WorkspaceMigrationV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-v2';
import {
WorkspaceQueryRunnerException,
WorkspaceQueryRunnerExceptionCode,
} from 'src/engine/api/graphql/workspace-query-runner/workspace-query-runner.exception';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/core-modules/common/services/workspace-many-or-all-flat-entity-maps-cache.service.';
import { AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { WorkspaceMigrationV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-v2';
import { WorkspaceMigrationRunnerActionHandlerRegistryService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/registry/workspace-migration-runner-action-handler-registry.service';
import { applyWorkspaceMigrationActionOnFlatObjectMetadataMaps } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/utils/apply-workspace-migration-action-on-flat-object-metadata-maps';
@Injectable()
export class WorkspaceMigrationRunnerV2Service {
constructor(
private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService,
private readonly workspacePermissionsCacheService: WorkspacePermissionsCacheService,
private readonly workspaceMetadataCacheService: WorkspaceMetadataCacheService,
private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
@InjectDataSource()
private readonly coreDataSource: DataSource,
private readonly workspaceMigrationRunnerActionHandlerRegistry: WorkspaceMigrationRunnerActionHandlerRegistryService,
) {}
run = async (
workspaceMigration: WorkspaceMigrationV2,
): Promise<FlatObjectMetadataMaps> => {
run = async ({
actions,
workspaceId,
relatedFlatEntityMapsKeys,
}: WorkspaceMigrationV2): Promise<AllFlatEntityMaps> => {
const queryRunner = this.coreDataSource.createQueryRunner();
const { flatObjectMetadataMaps: existingFlatObjectMetadataMaps } =
await this.workspaceMetadataCacheService.getExistingOrRecomputeFlatObjectMetadataMaps(
let allFlatEntityMaps =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId: workspaceMigration.workspaceId,
workspaceId,
flatEntities: relatedFlatEntityMapsKeys,
},
);
await queryRunner.connect();
await queryRunner.startTransaction();
let optimisticFlatObjectMetadataMaps = structuredClone(
existingFlatObjectMetadataMaps,
);
let flatEntityMapsToInvalidate: (keyof AllFlatEntityMaps)[] = [];
try {
for (const action of workspaceMigration.actions) {
await this.workspaceMigrationRunnerActionHandlerRegistry.executeActionHandler(
action.type,
{
action,
flatObjectMetadataMaps: optimisticFlatObjectMetadataMaps,
queryRunner,
workspaceId: workspaceMigration.workspaceId,
},
);
for (const action of actions) {
const partialOptimisticCache =
await this.workspaceMigrationRunnerActionHandlerRegistry.executeActionHandler(
action.type,
{
action,
allFlatEntityMaps,
queryRunner,
workspaceId,
},
);
const optimisticallyUpdatedFlatEntityMapsKeys = Object.keys(
partialOptimisticCache,
) as (keyof AllFlatEntityMaps)[];
optimisticFlatObjectMetadataMaps =
applyWorkspaceMigrationActionOnFlatObjectMetadataMaps({
action,
flatObjectMetadataMaps: optimisticFlatObjectMetadataMaps,
workspaceId: workspaceMigration.workspaceId,
});
flatEntityMapsToInvalidate = [
...new Set([
...optimisticallyUpdatedFlatEntityMapsKeys,
...flatEntityMapsToInvalidate,
]),
];
allFlatEntityMaps = {
...allFlatEntityMaps,
...partialOptimisticCache,
};
}
await queryRunner.commitTransaction();
const { workspaceId } = workspaceMigration;
await this.workspaceMetadataVersionService.incrementMetadataVersion(
await this.flatEntityMapsCacheService.invalidateFlatEntityMaps({
workspaceId,
);
flatEntities: flatEntityMapsToInvalidate,
});
await this.workspacePermissionsCacheService.recomputeRolesPermissionsCache(
{
workspaceId,
},
);
return optimisticFlatObjectMetadataMaps;
return allFlatEntityMaps;
} catch (error) {
if (queryRunner.isTransactionActive) {
try {
@@ -83,7 +87,10 @@ export class WorkspaceMigrationRunnerV2Service {
console.trace(`Failed to rollback transaction: ${error.message}`);
}
}
throw error;
throw new WorkspaceQueryRunnerException(
error.message,
WorkspaceQueryRunnerExceptionCode.INTERNAL_SERVER_ERROR,
);
} finally {
await queryRunner.release();
}
@@ -1,6 +1,6 @@
import { type QueryRunner } from 'typeorm';
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
import { type AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
import { type WorkspaceMigrationActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-action-common-v2';
export type WorkspaceMigrationActionRunnerArgs<
@@ -8,6 +8,6 @@ export type WorkspaceMigrationActionRunnerArgs<
> = {
queryRunner: QueryRunner;
action: T;
flatObjectMetadataMaps: FlatObjectMetadataMaps;
allFlatEntityMaps: AllFlatEntityMaps;
workspaceId: string;
};
@@ -1,151 +0,0 @@
import { assertUnreachable, isDefined } from 'twenty-shared/utils';
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
import { addFlatFieldMetadataInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/add-flat-field-metadata-in-flat-object-metadata-maps-or-throw.util';
import { addFlatObjectMetadataToFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/add-flat-object-metadata-to-flat-object-metadata-maps-or-throw.util';
import { deleteFieldFromFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/delete-field-from-flat-object-metadata-maps-or-throw.util';
import { deleteObjectFromFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/delete-object-from-flat-object-metadata-maps-or-throw.util';
import { findFlatFieldMetadataInFlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-field-metadata-in-flat-object-metadata-maps.util';
import { findFlatObjectMetadataInFlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-object-metadata-in-flat-object-metadata-maps.util';
import { replaceFlatFieldMetadataInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/replace-flat-field-metadata-in-flat-object-metadata-maps-or-throw.util';
import { replaceFlatObjectMetadataInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/replace-flat-object-metadata-in-flat-object-metadata-maps-or-throw.util';
import { type WorkspaceMigrationActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-action-common-v2';
import {
WorkspaceMigrationRunnerException,
WorkspaceMigrationRunnerExceptionCode,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/exceptions/workspace-migration-runner.exception';
import { type WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/types/workspace-migration-action-runner-args.type';
import { fromWorkspaceMigrationUpdateActionToPartialEntity } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/utils/from-workspace-migration-update-action-to-partial-field-or-object-entity.util';
export const applyWorkspaceMigrationActionOnFlatObjectMetadataMaps = <
T extends WorkspaceMigrationActionV2,
>({
action,
flatObjectMetadataMaps,
}: Omit<
WorkspaceMigrationActionRunnerArgs<T>,
'queryRunner'
>): FlatObjectMetadataMaps => {
switch (action.type) {
case 'delete_object': {
return deleteObjectFromFlatObjectMetadataMapsOrThrow({
flatObjectMetadataMaps,
objectMetadataId: action.objectMetadataId,
});
}
case 'create_object': {
const flatObjectMetadataWithoutFields =
action.flatObjectMetadataWithoutFields;
const flatFieldMetadatas = action.createFieldActions.map(
(createFieldAction) => createFieldAction.flatFieldMetadata,
);
return addFlatObjectMetadataToFlatObjectMetadataMapsOrThrow({
flatObjectMetadata: {
...flatObjectMetadataWithoutFields,
flatIndexMetadatas: [],
flatFieldMetadatas,
},
flatObjectMetadataMaps,
});
}
case 'update_object': {
const { objectMetadataId } = action;
const existingFlatObjectMetadata =
findFlatObjectMetadataInFlatObjectMetadataMaps({
objectMetadataId,
flatObjectMetadataMaps,
});
if (!isDefined(existingFlatObjectMetadata)) {
throw new WorkspaceMigrationRunnerException(
`Workspace migration failed: Object metadata not found in cache`,
WorkspaceMigrationRunnerExceptionCode.OBJECT_METADATA_NOT_FOUND,
);
}
const updatedFlatObjectMetadata = {
...existingFlatObjectMetadata,
...fromWorkspaceMigrationUpdateActionToPartialEntity(action),
};
return replaceFlatObjectMetadataInFlatObjectMetadataMapsOrThrow({
flatObjectMetadata: updatedFlatObjectMetadata,
flatObjectMetadataMaps,
});
}
case 'create_field': {
const updatedFlatObjectMetadataMaps =
addFlatFieldMetadataInFlatObjectMetadataMapsOrThrow({
flatFieldMetadata: action.flatFieldMetadata,
flatObjectMetadataMaps,
});
if (!isDefined(updatedFlatObjectMetadataMaps)) {
throw new WorkspaceMigrationRunnerException(
`Workspace migration failed: dispatchAndAddFlatFieldMetadataInFlatObjectMetadataMaps failed`,
WorkspaceMigrationRunnerExceptionCode.FIELD_METADATA_NOT_FOUND,
);
}
return updatedFlatObjectMetadataMaps;
}
case 'update_field': {
const { fieldMetadataId, objectMetadataId } = action;
const existingFlatFieldMetadata =
findFlatFieldMetadataInFlatObjectMetadataMaps({
fieldMetadataId,
objectMetadataId,
flatObjectMetadataMaps,
});
if (!isDefined(existingFlatFieldMetadata)) {
throw new WorkspaceMigrationRunnerException(
`Workspace migration failed: Field metadata not found in cache`,
WorkspaceMigrationRunnerExceptionCode.FIELD_METADATA_NOT_FOUND,
);
}
const updatedFlatFieldMetadata = {
...existingFlatFieldMetadata,
...fromWorkspaceMigrationUpdateActionToPartialEntity(action),
};
const updatedFlatObjectMetadataMaps =
replaceFlatFieldMetadataInFlatObjectMetadataMapsOrThrow({
flatFieldMetadata: updatedFlatFieldMetadata,
flatObjectMetadataMaps,
});
if (!isDefined(updatedFlatObjectMetadataMaps)) {
throw new WorkspaceMigrationRunnerException(
`Workspace migration failed: dispatchAndReplaceFlatFieldMetadataInFlatObjectMetadataMaps failed`,
WorkspaceMigrationRunnerExceptionCode.FIELD_METADATA_NOT_FOUND,
);
}
return updatedFlatObjectMetadataMaps;
}
case 'delete_field': {
return deleteFieldFromFlatObjectMetadataMapsOrThrow({
fieldMetadataId: action.fieldMetadataId,
flatObjectMetadataMaps,
objectMetadataId: action.objectMetadataId,
});
}
case 'create_index':
case 'delete_index':
case 'create_view':
case 'update_view':
case 'delete_view':
case 'create_view_field':
case 'update_view_field':
case 'delete_view_field':
return flatObjectMetadataMaps;
default: {
assertUnreachable(
action,
'Should never occur, encountered an unsupported workspace migration action type',
);
}
}
};
@@ -2,11 +2,10 @@ import { Module } from '@nestjs/common';
import { DiscoveryModule } from '@nestjs/core';
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/core-modules/common/services/workspace-many-or-all-flat-entity-maps-cache.module';
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
import { WorkspaceMetadataCacheModule } from 'src/engine/metadata-modules/workspace-metadata-cache/workspace-metadata-cache.module';
import { WorkspaceMetadataVersionModule } from 'src/engine/metadata-modules/workspace-metadata-version/workspace-metadata-version.module';
import { WorkspacePermissionsCacheModule } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.module';
import { WorkspaceSchemaMigrationRunnerActionHandlersModule } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/workspace-schema-migration-runner-action-handlers.module';
import { WorkspaceMigrationRunnerActionHandlerRegistryService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/registry/workspace-migration-runner-action-handler-registry.service';
import { WorkspaceMigrationRunnerV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/services/workspace-migration-runner-v2.service';
@@ -16,10 +15,9 @@ import { WorkspaceMigrationRunnerV2Service } from 'src/engine/workspace-manager/
FeatureFlagModule,
TypeORMModule,
DataSourceModule,
WorkspaceMetadataVersionModule,
WorkspacePermissionsCacheModule,
WorkspaceMetadataCacheModule,
WorkspaceSchemaMigrationRunnerActionHandlersModule,
WorkspaceManyOrAllFlatEntityMapsCacheModule,
DiscoveryModule,
],
providers: [
@@ -1,6 +1,5 @@
import { Module } from '@nestjs/common';
import { ViewCacheModule } from 'src/engine/core-modules/view/cache/services/view-cache.module';
import { WorkspaceMetadataCacheModule } from 'src/engine/metadata-modules/workspace-metadata-cache/workspace-metadata-cache.module';
import { WorkspaceMigrationBuildOrchestratorService } from 'src/engine/workspace-manager/workspace-migration-v2/services/workspace-migration-build-orchestrator.service';
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration-v2/services/workspace-migration-validate-build-and-run-service';
@@ -12,7 +11,6 @@ import { WorkspaceMigrationRunnerV2Module } from 'src/engine/workspace-manager/w
WorkspaceMigrationBuilderV2Module,
WorkspaceMigrationRunnerV2Module,
WorkspaceMetadataCacheModule,
ViewCacheModule,
],
providers: [
WorkspaceMigrationValidateBuildAndRunService,