Add workspace migration orchestrator + refactor builders + view/viewField action builders (#14383)
This commit is contained in:
+6
@@ -0,0 +1,6 @@
|
||||
export class WorkspaceMigrationOrchestratorException extends Error {
|
||||
constructor(message = 'Workspace migration orchestrator failed') {
|
||||
super(message);
|
||||
this.name = 'WorkspaceMigrationOrchestratorException';
|
||||
}
|
||||
}
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'class-validator';
|
||||
|
||||
import { ViewCacheService } from 'src/engine/core-modules/view/cache/services/view-cache.service';
|
||||
import { WorkspaceMetadataCacheService } from 'src/engine/metadata-modules/workspace-metadata-cache/services/workspace-metadata-cache.service';
|
||||
import { WorkspaceMigrationOrchestratorException } from 'src/engine/workspace-manager/workspace-migration-v2/exceptions/workspace-migration-orchestrator-exception';
|
||||
import {
|
||||
WorkspaceMigrationOrchestratorBuildArgs,
|
||||
WorkspaceMigrationOrchestratorEntityMaps,
|
||||
WorkspaceMigrationOrchestratorFailedResult,
|
||||
WorkspaceMigrationOrchestratorOptimisticEntityMaps,
|
||||
} from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
|
||||
import { WorkspaceMigrationBuilderV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-builder-v2.service';
|
||||
import { WorkspaceViewFieldMigrationBuilderV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-view-field-migration-builder-v2.service';
|
||||
import { WorkspaceViewMigrationBuilderV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-view-migration-builder-v2.service';
|
||||
import { WorkspaceMigrationRunnerV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/services/workspace-migration-runner-v2.service';
|
||||
import {
|
||||
WorkspaceMigrationV2Exception,
|
||||
WorkspaceMigrationV2ExceptionCode,
|
||||
} from 'src/engine/workspace-manager/workspace-migration.exception';
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceMigrationBuildOrchestratorService {
|
||||
private readonly logger = new Logger(
|
||||
WorkspaceMigrationBuildOrchestratorService.name,
|
||||
);
|
||||
|
||||
constructor(
|
||||
private readonly workspaceMigrationBuilderV2Service: WorkspaceMigrationBuilderV2Service,
|
||||
private readonly workspaceViewMigrationBuilderV2Service: WorkspaceViewMigrationBuilderV2Service,
|
||||
private readonly workspaceViewFieldMigrationBuilderV2Service: WorkspaceViewFieldMigrationBuilderV2Service,
|
||||
private readonly migrationRunner: WorkspaceMigrationRunnerV2Service,
|
||||
private readonly workspaceMetadataCacheService: WorkspaceMetadataCacheService,
|
||||
private readonly viewCacheService: ViewCacheService,
|
||||
) {}
|
||||
|
||||
public async buildWorkspaceMigrations({
|
||||
workspaceId,
|
||||
buildOptions,
|
||||
entityMaps,
|
||||
}: WorkspaceMigrationOrchestratorBuildArgs): Promise<
|
||||
WorkspaceMigrationOrchestratorFailedResult | undefined
|
||||
> {
|
||||
try {
|
||||
const allObjectAndFieldActions = [];
|
||||
const allViewActions = [];
|
||||
const allViewFieldActions = [];
|
||||
const allFailures = [];
|
||||
|
||||
const optimisticEntityMaps = await this.prepareOptimisticEntityMaps({
|
||||
entityMaps,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
if (entityMaps.object) {
|
||||
const objectResult =
|
||||
await this.workspaceMigrationBuilderV2Service.validateAndBuild({
|
||||
fromFlatObjectMetadataMaps:
|
||||
entityMaps.object.fromFlatObjectMetadataMaps,
|
||||
toFlatObjectMetadataMaps:
|
||||
entityMaps.object.toFlatObjectMetadataMaps,
|
||||
workspaceId,
|
||||
buildOptions,
|
||||
});
|
||||
|
||||
if (objectResult.status === 'fail') {
|
||||
allFailures.push(...objectResult.errors);
|
||||
} else {
|
||||
optimisticEntityMaps.object = objectResult.optimisticFlatEntityMaps;
|
||||
allObjectAndFieldActions.push(
|
||||
...objectResult.workspaceMigration.actions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (entityMaps.view) {
|
||||
const viewResult =
|
||||
await this.workspaceViewMigrationBuilderV2Service.validateAndBuild({
|
||||
fromFlatViewMaps: entityMaps.view.fromFlatViewMaps,
|
||||
toFlatViewMaps: entityMaps.view.toFlatViewMaps,
|
||||
workspaceId,
|
||||
buildOptions,
|
||||
dependencyOptimisticEntityMaps: {
|
||||
object: optimisticEntityMaps.object,
|
||||
},
|
||||
});
|
||||
|
||||
if (viewResult.status === 'fail') {
|
||||
allFailures.push(...viewResult.errors);
|
||||
} else {
|
||||
optimisticEntityMaps.view = viewResult.optimisticFlatEntityMaps;
|
||||
allViewActions.push(...viewResult.workspaceMigration.actions);
|
||||
}
|
||||
}
|
||||
|
||||
if (entityMaps.viewField) {
|
||||
const viewFieldResult =
|
||||
await this.workspaceViewFieldMigrationBuilderV2Service.validateAndBuild(
|
||||
{
|
||||
fromFlatViewFieldMaps: entityMaps.viewField.fromFlatViewFieldMaps,
|
||||
toFlatViewFieldMaps: entityMaps.viewField.toFlatViewFieldMaps,
|
||||
workspaceId,
|
||||
buildOptions,
|
||||
dependencyOptimisticEntityMaps: {
|
||||
object: optimisticEntityMaps.object,
|
||||
view: optimisticEntityMaps.view,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (viewFieldResult.status === 'fail') {
|
||||
allFailures.push(...viewFieldResult.errors);
|
||||
} else {
|
||||
optimisticEntityMaps.viewField =
|
||||
viewFieldResult.optimisticFlatEntityMaps;
|
||||
allViewFieldActions.push(
|
||||
...viewFieldResult.workspaceMigration.actions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (allFailures.length > 0) {
|
||||
return {
|
||||
status: 'fail',
|
||||
errors: allFailures,
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: return workspace migrations
|
||||
|
||||
return;
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
throw new WorkspaceMigrationV2Exception(
|
||||
WorkspaceMigrationV2ExceptionCode.BUILDER_INTERNAL_SERVER_ERROR,
|
||||
error.message,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: move to dedicated service
|
||||
private async prepareOptimisticEntityMaps({
|
||||
entityMaps,
|
||||
workspaceId,
|
||||
}: {
|
||||
entityMaps: WorkspaceMigrationOrchestratorEntityMaps;
|
||||
workspaceId: string;
|
||||
}): Promise<WorkspaceMigrationOrchestratorOptimisticEntityMaps> {
|
||||
const optimisticObjectMaps =
|
||||
entityMaps.object?.fromFlatObjectMetadataMaps ??
|
||||
(
|
||||
await this.workspaceMetadataCacheService.getExistingOrRecomputeFlatObjectMetadataMaps(
|
||||
{ workspaceId },
|
||||
)
|
||||
).flatObjectMetadataMaps;
|
||||
|
||||
if (!isDefined(optimisticObjectMaps)) {
|
||||
throw new WorkspaceMigrationOrchestratorException(
|
||||
'Object metadata maps not found',
|
||||
);
|
||||
}
|
||||
|
||||
const optimisticViewMaps =
|
||||
entityMaps.view?.fromFlatViewMaps ??
|
||||
(
|
||||
await this.viewCacheService.getExistingOrRecomputeFlatViewMaps({
|
||||
workspaceId,
|
||||
})
|
||||
).flatViewMaps;
|
||||
|
||||
if (!isDefined(optimisticViewMaps)) {
|
||||
throw new WorkspaceMigrationOrchestratorException('View maps not found');
|
||||
}
|
||||
|
||||
// For ViewFields, if not provided, start with empty maps since ViewFields are optional
|
||||
const optimisticViewFieldMaps = entityMaps.viewField
|
||||
?.fromFlatViewFieldMaps ?? {
|
||||
byId: {},
|
||||
idByUniversalIdentifier: {},
|
||||
};
|
||||
|
||||
return {
|
||||
object: optimisticObjectMaps,
|
||||
view: optimisticViewMaps,
|
||||
viewField: optimisticViewFieldMaps,
|
||||
};
|
||||
}
|
||||
}
|
||||
+1
@@ -11,6 +11,7 @@ import {
|
||||
WorkspaceMigrationV2ExceptionCode,
|
||||
} from 'src/engine/workspace-manager/workspace-migration.exception';
|
||||
|
||||
// TODO: replace build logic by orchestrator service
|
||||
@Injectable()
|
||||
export class WorkspaceMigrationValidateBuildAndRunService {
|
||||
private readonly logger = new Logger(
|
||||
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
import { type ViewFieldEntity } from 'src/engine/core-modules/view/entities/view-field.entity';
|
||||
|
||||
export type FlatViewField = Pick<
|
||||
ViewFieldEntity,
|
||||
'fieldMetadataId' | 'position' | 'isVisible' | 'size'
|
||||
>;
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
import { type ViewEntity } from 'src/engine/core-modules/view/entities/view.entity';
|
||||
import { type FlatViewField } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-view-field.type';
|
||||
|
||||
export type FlatView = Pick<
|
||||
ViewEntity,
|
||||
'name' | 'objectMetadataId' | 'type' | 'isCustom' | 'key' | 'icon'
|
||||
> & {
|
||||
viewFields: FlatViewField[];
|
||||
};
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
import { type FromTo } from 'twenty-shared/types';
|
||||
|
||||
import { type FailedFlatViewFieldValidation } from 'src/engine/core-modules/view/flat-view/types/failed-flat-view-field-validation.type';
|
||||
import { type FailedFlatViewValidation } from 'src/engine/core-modules/view/flat-view/types/failed-flat-view-validation.type';
|
||||
import { type FlatViewFieldMaps } from 'src/engine/core-modules/view/flat-view/types/flat-view-field-maps.type';
|
||||
import { type FlatViewMaps } from 'src/engine/core-modules/view/flat-view/types/flat-view-maps.type';
|
||||
import { type FailedFlatFieldMetadataValidation } from 'src/engine/metadata-modules/flat-field-metadata/types/failed-flat-field-metadata-validation.type';
|
||||
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
|
||||
import { type FailedFlatObjectMetadataValidation } from 'src/engine/metadata-modules/flat-object-metadata/types/failed-flat-object-metadata-validation.type';
|
||||
import { type WorkspaceMigrationV2BuilderOptions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-builder-v2.service';
|
||||
|
||||
export type WorkspaceMigrationOrchestratorEntityMaps = {
|
||||
object?: FromTo<FlatObjectMetadataMaps, 'FlatObjectMetadataMaps'>;
|
||||
field?: FromTo<FlatObjectMetadataMaps, 'FlatObjectMetadataMaps'>; // Fields are part of object maps for now
|
||||
view?: FromTo<FlatViewMaps, 'FlatViewMaps'>;
|
||||
viewField?: FromTo<FlatViewFieldMaps, 'FlatViewFieldMaps'>;
|
||||
};
|
||||
|
||||
type UnwrapFromTo<T> = T extends FromTo<infer U, infer _Tag> ? U : T;
|
||||
|
||||
export type WorkspaceMigrationOrchestratorOptimisticEntityMaps = {
|
||||
[K in keyof WorkspaceMigrationOrchestratorEntityMaps]?: UnwrapFromTo<
|
||||
WorkspaceMigrationOrchestratorEntityMaps[K]
|
||||
>;
|
||||
};
|
||||
|
||||
export type WorkspaceMigrationOrchestratorBuildArgs = {
|
||||
workspaceId: string;
|
||||
buildOptions: WorkspaceMigrationV2BuilderOptions;
|
||||
entityMaps: WorkspaceMigrationOrchestratorEntityMaps;
|
||||
};
|
||||
|
||||
export type WorkspaceMigrationOrchestratorFailedResult = {
|
||||
status: 'fail';
|
||||
errors: (
|
||||
| FailedFlatObjectMetadataValidation
|
||||
| FailedFlatFieldMetadataValidation
|
||||
| FailedFlatViewValidation
|
||||
| FailedFlatViewFieldValidation
|
||||
)[];
|
||||
};
|
||||
-333
@@ -1033,85 +1033,6 @@ exports[`Workspace migration builder object actions test suite It should build a
|
||||
},
|
||||
"type": "create_object",
|
||||
},
|
||||
{
|
||||
"type": "create_view",
|
||||
"view": {
|
||||
"icon": "IconList",
|
||||
"isCustom": false,
|
||||
"key": "INDEX",
|
||||
"name": "All {objectLabelPlural}",
|
||||
"objectMetadataId": Any<String>,
|
||||
"type": "TABLE",
|
||||
"viewFields": [
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 0,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 1,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 2,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 3,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 4,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 5,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 6,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 7,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 8,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 9,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 10,
|
||||
"size": 180,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
@@ -2419,181 +2340,6 @@ exports[`Workspace migration builder object actions test suite It should build a
|
||||
},
|
||||
"type": "create_object",
|
||||
},
|
||||
{
|
||||
"type": "create_view",
|
||||
"view": {
|
||||
"icon": "IconList",
|
||||
"isCustom": false,
|
||||
"key": "INDEX",
|
||||
"name": "All {objectLabelPlural}",
|
||||
"objectMetadataId": Any<String>,
|
||||
"type": "TABLE",
|
||||
"viewFields": [
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 0,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 1,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 2,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 3,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 4,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 5,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 6,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 7,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 8,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 9,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 10,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 11,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 12,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 13,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 14,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 15,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 16,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 17,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 18,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 19,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 20,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 21,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 22,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 23,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 24,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 25,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 26,
|
||||
"size": 180,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
@@ -3246,85 +2992,6 @@ exports[`Workspace migration builder object actions test suite It should build a
|
||||
},
|
||||
"type": "create_index",
|
||||
},
|
||||
{
|
||||
"type": "create_view",
|
||||
"view": {
|
||||
"icon": "IconList",
|
||||
"isCustom": false,
|
||||
"key": "INDEX",
|
||||
"name": "All {objectLabelPlural}",
|
||||
"objectMetadataId": Any<String>,
|
||||
"type": "TABLE",
|
||||
"viewFields": [
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 0,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 1,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 2,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 3,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 4,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 5,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 6,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 7,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 8,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 9,
|
||||
"size": 180,
|
||||
},
|
||||
{
|
||||
"fieldMetadataId": Any<String>,
|
||||
"isVisible": true,
|
||||
"position": 10,
|
||||
"size": 180,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
|
||||
+1
-4
@@ -44,7 +44,7 @@ const DELETE_OBJECT_TEST_CASES: WorkspaceMigrationBuilderTestCase[] = [
|
||||
context: {
|
||||
input: {
|
||||
buildOptions: {
|
||||
inferDeletionFromMissingObjectFieldIndex: true,
|
||||
inferDeletionFromMissingEntities: true,
|
||||
isSystemBuild: true,
|
||||
},
|
||||
fromFlatObjectMetadataMaps: FLAT_OBJECT_METADATA_MAPS_MOCKS,
|
||||
@@ -81,7 +81,6 @@ const CREATE_OBJECT_TEST_CASES: WorkspaceMigrationBuilderTestCase[] = [
|
||||
},
|
||||
expectedActionsTypeCounter: {
|
||||
createObject: 1,
|
||||
createView: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -103,7 +102,6 @@ const CREATE_OBJECT_TEST_CASES: WorkspaceMigrationBuilderTestCase[] = [
|
||||
},
|
||||
expectedActionsTypeCounter: {
|
||||
createObject: 1,
|
||||
createView: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -114,7 +112,6 @@ const CREATE_OBJECT_TEST_CASES: WorkspaceMigrationBuilderTestCase[] = [
|
||||
expectedActionsTypeCounter: {
|
||||
createIndex: 1,
|
||||
createObject: 1,
|
||||
createView: 1,
|
||||
},
|
||||
input: {
|
||||
fromFlatObjectMetadataMaps:
|
||||
|
||||
+1
-2
@@ -54,7 +54,6 @@ const expectedActionsTypeCounterChecker = ({
|
||||
deleteObject: 0,
|
||||
updateField: 0,
|
||||
updateObject: 0,
|
||||
createView: 0,
|
||||
};
|
||||
const actualActionsTypeCounter = workspaceMigration.actions.reduce(
|
||||
(acc, action) => {
|
||||
@@ -125,7 +124,7 @@ describe.each(allWorkspaceBuilderTestCases)(
|
||||
fromFlatObjectMetadataMaps,
|
||||
toFlatObjectMetadataMaps,
|
||||
buildOptions = {
|
||||
inferDeletionFromMissingObjectFieldIndex: true,
|
||||
inferDeletionFromMissingEntities: true,
|
||||
isSystemBuild: false,
|
||||
},
|
||||
} = typeof input === 'function' ? input() : input;
|
||||
|
||||
+1
-1
@@ -155,7 +155,7 @@ export class WorkspaceMigrationV2FieldActionsBuilderService {
|
||||
validateAndBuildResult.created.push(createFieldAction);
|
||||
}
|
||||
|
||||
for (const flatFieldMetadataToDelete of buildOptions.inferDeletionFromMissingObjectFieldIndex
|
||||
for (const flatFieldMetadataToDelete of buildOptions.inferDeletionFromMissingEntities
|
||||
? deletedFlatFieldMetadatas
|
||||
: []) {
|
||||
const validationErrors =
|
||||
|
||||
+1
-1
@@ -103,7 +103,7 @@ export class WorkspaceMigrationV2ObjectActionsBuilderService {
|
||||
validateAndBuildResult.created.push(createObjectAction);
|
||||
}
|
||||
|
||||
for (const flatObjectMetadataToDelete of buildOptions.inferDeletionFromMissingObjectFieldIndex
|
||||
for (const flatObjectMetadataToDelete of buildOptions.inferDeletionFromMissingEntities
|
||||
? deletedFlatObjectMetadatas
|
||||
: []) {
|
||||
const validationErrors =
|
||||
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { FromTo } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/core-modules/common/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
|
||||
import { deleteFlatEntityFromFlatEntityMapsOrThrow } from 'src/engine/core-modules/common/utils/delete-flat-entity-from-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 { FailedFlatViewFieldValidation } from 'src/engine/core-modules/view/flat-view/types/failed-flat-view-field-validation.type';
|
||||
import { FlatViewFieldMaps } from 'src/engine/core-modules/view/flat-view/types/flat-view-field-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 { WorkspaceMigrationOrchestratorOptimisticEntityMaps } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
|
||||
import { type CustomDeletedCreatedUpdatedMatrix } from 'src/engine/workspace-manager/workspace-migration-v2/utils/deleted-created-updated-matrix-dispatcher.util';
|
||||
import { WorkspaceViewFieldMigrationV2BuilderOptions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-view-field-migration-builder-v2.service';
|
||||
import { WorkspaceMigrationActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-action-common-v2';
|
||||
import {
|
||||
UpdateViewFieldAction,
|
||||
WorkspaceMigrationViewFieldActionV2,
|
||||
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-field-action-v2.type';
|
||||
import {
|
||||
getWorkspaceMigrationV2ViewFieldCreateAction,
|
||||
getWorkspaceMigrationV2ViewFieldDeleteAction,
|
||||
} 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 CreatedDeletedUpdatedViewFieldInputMatrix = FromTo<
|
||||
FlatViewFieldMaps,
|
||||
'FlatViewFieldMaps'
|
||||
> &
|
||||
CustomDeletedCreatedUpdatedMatrix<'flatViewField', FlatViewField> & {
|
||||
buildOptions: WorkspaceViewFieldMigrationV2BuilderOptions;
|
||||
fromFlatViewFieldMaps: FlatViewFieldMaps;
|
||||
dependencyOptimisticEntityMaps: WorkspaceMigrationOrchestratorOptimisticEntityMaps;
|
||||
};
|
||||
|
||||
type ValidateAndBuildViewFieldResult<T extends WorkspaceMigrationActionV2> = {
|
||||
failed: FailedFlatViewFieldValidation[];
|
||||
created: T[];
|
||||
deleted: T[];
|
||||
updated: T[];
|
||||
optimisticFlatViewFieldMaps: FlatViewFieldMaps;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceMigrationV2ViewFieldActionsBuilderService {
|
||||
constructor(
|
||||
private readonly flatViewFieldValidatorService: FlatViewFieldValidatorService,
|
||||
) {}
|
||||
|
||||
public async validateAndBuildViewFieldActions({
|
||||
createdFlatViewField,
|
||||
deletedFlatViewField,
|
||||
updatedFlatViewField,
|
||||
buildOptions,
|
||||
fromFlatViewFieldMaps,
|
||||
dependencyOptimisticEntityMaps,
|
||||
}: CreatedDeletedUpdatedViewFieldInputMatrix): Promise<
|
||||
ValidateAndBuildViewFieldResult<WorkspaceMigrationViewFieldActionV2>
|
||||
> {
|
||||
const validateAndBuildResult: ValidateAndBuildViewFieldResult<WorkspaceMigrationViewFieldActionV2> =
|
||||
{
|
||||
failed: [],
|
||||
created: [],
|
||||
deleted: [],
|
||||
updated: [],
|
||||
optimisticFlatViewFieldMaps: structuredClone(fromFlatViewFieldMaps),
|
||||
};
|
||||
|
||||
if (
|
||||
!isDefined(dependencyOptimisticEntityMaps.object) ||
|
||||
!isDefined(dependencyOptimisticEntityMaps.view)
|
||||
) {
|
||||
throw new Error('Dependency optimistic entity maps are not defined');
|
||||
}
|
||||
|
||||
for (const flatViewFieldToCreate of createdFlatViewField) {
|
||||
const validationErrors =
|
||||
await this.flatViewFieldValidatorService.validateFlatViewFieldCreation({
|
||||
_existingFlatViewFieldMaps:
|
||||
validateAndBuildResult.optimisticFlatViewFieldMaps,
|
||||
flatViewFieldToValidate: flatViewFieldToCreate,
|
||||
optimisticFlatObjectMetadataMaps:
|
||||
dependencyOptimisticEntityMaps.object,
|
||||
optimisticFlatViewMaps: dependencyOptimisticEntityMaps.view,
|
||||
});
|
||||
|
||||
if (validationErrors.viewFieldLevelErrors.length > 0) {
|
||||
validateAndBuildResult.failed.push(validationErrors);
|
||||
continue;
|
||||
}
|
||||
|
||||
validateAndBuildResult.optimisticFlatViewFieldMaps =
|
||||
addFlatEntityToFlatEntityMapsOrThrow({
|
||||
flatEntity: flatViewFieldToCreate,
|
||||
flatEntityMaps: validateAndBuildResult.optimisticFlatViewFieldMaps,
|
||||
});
|
||||
|
||||
const createViewFieldAction =
|
||||
getWorkspaceMigrationV2ViewFieldCreateAction({
|
||||
flatViewField: flatViewFieldToCreate,
|
||||
});
|
||||
|
||||
validateAndBuildResult.created.push(createViewFieldAction);
|
||||
}
|
||||
|
||||
for (const flatViewFieldToDelete of buildOptions.inferDeletionFromMissingEntities
|
||||
? deletedFlatViewField
|
||||
: []) {
|
||||
const validationErrors =
|
||||
this.flatViewFieldValidatorService.validateFlatViewFieldDeletion({
|
||||
existingFlatViewFieldMaps:
|
||||
validateAndBuildResult.optimisticFlatViewFieldMaps,
|
||||
viewFieldIdToDelete: flatViewFieldToDelete.id,
|
||||
optimisticFlatViewMaps: dependencyOptimisticEntityMaps.view,
|
||||
});
|
||||
|
||||
if (validationErrors.viewFieldLevelErrors.length > 0) {
|
||||
validateAndBuildResult.failed.push(validationErrors);
|
||||
continue;
|
||||
}
|
||||
|
||||
validateAndBuildResult.optimisticFlatViewFieldMaps =
|
||||
deleteFlatEntityFromFlatEntityMapsOrThrow({
|
||||
entityToDeleteId: flatViewFieldToDelete.id,
|
||||
flatEntityMaps: validateAndBuildResult.optimisticFlatViewFieldMaps,
|
||||
});
|
||||
|
||||
const deleteViewFieldAction =
|
||||
getWorkspaceMigrationV2ViewFieldDeleteAction(flatViewFieldToDelete);
|
||||
|
||||
validateAndBuildResult.deleted.push(deleteViewFieldAction);
|
||||
}
|
||||
|
||||
for (const {
|
||||
from: fromFlatViewField,
|
||||
to: toFlatViewField,
|
||||
} of updatedFlatViewField) {
|
||||
const viewFieldUpdatedProperties = compareTwoFlatViewField({
|
||||
fromFlatViewField,
|
||||
toFlatViewField,
|
||||
});
|
||||
|
||||
if (viewFieldUpdatedProperties.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const validationErrors =
|
||||
this.flatViewFieldValidatorService.validateFlatViewFieldUpdate({
|
||||
existingFlatViewFieldMaps:
|
||||
validateAndBuildResult.optimisticFlatViewFieldMaps,
|
||||
updatedFlatViewField: toFlatViewField,
|
||||
optimisticFlatViewMaps: dependencyOptimisticEntityMaps.view,
|
||||
});
|
||||
|
||||
if (validationErrors.viewFieldLevelErrors.length > 0) {
|
||||
validateAndBuildResult.failed.push(validationErrors);
|
||||
continue;
|
||||
}
|
||||
|
||||
validateAndBuildResult.optimisticFlatViewFieldMaps =
|
||||
replaceFlatEntityInFlatEntityMapsOrThrow({
|
||||
flatEntity: toFlatViewField,
|
||||
flatEntityMaps: validateAndBuildResult.optimisticFlatViewFieldMaps,
|
||||
});
|
||||
|
||||
const updateViewFieldAction: UpdateViewFieldAction = {
|
||||
type: 'update_view_field',
|
||||
viewFieldId: toFlatViewField.id,
|
||||
updates: viewFieldUpdatedProperties,
|
||||
};
|
||||
|
||||
validateAndBuildResult.updated.push(updateViewFieldAction);
|
||||
}
|
||||
|
||||
return validateAndBuildResult;
|
||||
}
|
||||
}
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { FromTo } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/core-modules/common/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
|
||||
import { deleteFlatEntityFromFlatEntityMapsOrThrow } from 'src/engine/core-modules/common/utils/delete-flat-entity-from-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 { FailedFlatViewValidation } from 'src/engine/core-modules/view/flat-view/types/failed-flat-view-validation.type';
|
||||
import { FlatViewMaps } from 'src/engine/core-modules/view/flat-view/types/flat-view-maps.type';
|
||||
import { FlatView } from 'src/engine/core-modules/view/flat-view/types/flat-view.type';
|
||||
import { compareTwoFlatView } from 'src/engine/core-modules/view/flat-view/utils/compare-two-flat-view.util';
|
||||
import { WorkspaceMigrationOrchestratorOptimisticEntityMaps } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
|
||||
import { type CustomDeletedCreatedUpdatedMatrix } from 'src/engine/workspace-manager/workspace-migration-v2/utils/deleted-created-updated-matrix-dispatcher.util';
|
||||
import { WorkspaceViewMigrationV2BuilderOptions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-view-migration-builder-v2.service';
|
||||
import { WorkspaceMigrationActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-action-common-v2';
|
||||
import {
|
||||
UpdateViewAction,
|
||||
WorkspaceMigrationViewActionV2,
|
||||
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-action-v2.type';
|
||||
import {
|
||||
getWorkspaceMigrationV2ViewCreateAction,
|
||||
getWorkspaceMigrationV2ViewDeleteAction,
|
||||
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-view-action';
|
||||
import { FlatViewValidatorService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/validators/services/flat-view-validator.service';
|
||||
|
||||
export type CreatedDeletedUpdatedViewInputMatrix = FromTo<
|
||||
FlatViewMaps,
|
||||
'FlatViewMaps'
|
||||
> &
|
||||
CustomDeletedCreatedUpdatedMatrix<'flatView', FlatView> & {
|
||||
buildOptions: WorkspaceViewMigrationV2BuilderOptions;
|
||||
fromFlatViewMaps: FlatViewMaps;
|
||||
dependencyOptimisticEntityMaps: WorkspaceMigrationOrchestratorOptimisticEntityMaps;
|
||||
};
|
||||
|
||||
type ValidateAndBuildViewResult<T extends WorkspaceMigrationActionV2> = {
|
||||
failed: FailedFlatViewValidation[];
|
||||
created: T[];
|
||||
deleted: T[];
|
||||
updated: T[];
|
||||
optimisticFlatViewMaps: FlatViewMaps;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceMigrationV2ViewActionsBuilderService {
|
||||
constructor(
|
||||
private readonly flatViewValidatorService: FlatViewValidatorService,
|
||||
) {}
|
||||
|
||||
public async validateAndBuildViewActions({
|
||||
createdFlatView,
|
||||
deletedFlatView,
|
||||
updatedFlatView,
|
||||
buildOptions,
|
||||
fromFlatViewMaps,
|
||||
dependencyOptimisticEntityMaps,
|
||||
}: CreatedDeletedUpdatedViewInputMatrix): Promise<
|
||||
ValidateAndBuildViewResult<WorkspaceMigrationViewActionV2>
|
||||
> {
|
||||
const validateAndBuildResult: ValidateAndBuildViewResult<WorkspaceMigrationViewActionV2> =
|
||||
{
|
||||
failed: [],
|
||||
created: [],
|
||||
deleted: [],
|
||||
updated: [],
|
||||
optimisticFlatViewMaps: structuredClone(fromFlatViewMaps),
|
||||
};
|
||||
|
||||
if (!isDefined(dependencyOptimisticEntityMaps.object)) {
|
||||
throw new Error('Dependency optimistic entity maps are not defined');
|
||||
}
|
||||
|
||||
for (const flatViewToCreate of createdFlatView) {
|
||||
const validationErrors =
|
||||
await this.flatViewValidatorService.validateFlatViewCreation({
|
||||
_existingFlatViewMaps: validateAndBuildResult.optimisticFlatViewMaps,
|
||||
flatViewToValidate: flatViewToCreate,
|
||||
optimisticFlatObjectMetadataMaps:
|
||||
dependencyOptimisticEntityMaps.object,
|
||||
});
|
||||
|
||||
if (validationErrors.viewLevelErrors.length > 0) {
|
||||
validateAndBuildResult.failed.push(validationErrors);
|
||||
continue;
|
||||
}
|
||||
|
||||
validateAndBuildResult.optimisticFlatViewMaps =
|
||||
addFlatEntityToFlatEntityMapsOrThrow({
|
||||
flatEntity: flatViewToCreate,
|
||||
flatEntityMaps: validateAndBuildResult.optimisticFlatViewMaps,
|
||||
});
|
||||
|
||||
const createViewAction = getWorkspaceMigrationV2ViewCreateAction({
|
||||
flatView: flatViewToCreate,
|
||||
});
|
||||
|
||||
validateAndBuildResult.created.push(createViewAction);
|
||||
}
|
||||
|
||||
for (const flatViewToDelete of buildOptions.inferDeletionFromMissingEntities
|
||||
? deletedFlatView
|
||||
: []) {
|
||||
const validationErrors =
|
||||
this.flatViewValidatorService.validateFlatViewDeletion({
|
||||
existingFlatViewMaps: validateAndBuildResult.optimisticFlatViewMaps,
|
||||
viewIdToDelete: flatViewToDelete.id,
|
||||
});
|
||||
|
||||
if (validationErrors.viewLevelErrors.length > 0) {
|
||||
validateAndBuildResult.failed.push(validationErrors);
|
||||
continue;
|
||||
}
|
||||
|
||||
validateAndBuildResult.optimisticFlatViewMaps =
|
||||
deleteFlatEntityFromFlatEntityMapsOrThrow({
|
||||
entityToDeleteId: flatViewToDelete.id,
|
||||
flatEntityMaps: validateAndBuildResult.optimisticFlatViewMaps,
|
||||
});
|
||||
|
||||
const deleteViewAction =
|
||||
getWorkspaceMigrationV2ViewDeleteAction(flatViewToDelete);
|
||||
|
||||
validateAndBuildResult.deleted.push(deleteViewAction);
|
||||
}
|
||||
|
||||
for (const { from: fromFlatView, to: toFlatView } of updatedFlatView) {
|
||||
const viewUpdatedProperties = compareTwoFlatView({
|
||||
fromFlatView,
|
||||
toFlatView,
|
||||
});
|
||||
|
||||
if (viewUpdatedProperties.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const validationErrors =
|
||||
this.flatViewValidatorService.validateFlatViewUpdate({
|
||||
existingFlatViewMaps: validateAndBuildResult.optimisticFlatViewMaps,
|
||||
updatedFlatView: toFlatView,
|
||||
});
|
||||
|
||||
if (validationErrors.viewLevelErrors.length > 0) {
|
||||
validateAndBuildResult.failed.push(validationErrors);
|
||||
continue;
|
||||
}
|
||||
|
||||
validateAndBuildResult.optimisticFlatViewMaps =
|
||||
replaceFlatEntityInFlatEntityMapsOrThrow({
|
||||
flatEntity: toFlatView,
|
||||
flatEntityMaps: validateAndBuildResult.optimisticFlatViewMaps,
|
||||
});
|
||||
|
||||
const updateViewAction: UpdateViewAction = {
|
||||
type: 'update_view',
|
||||
viewId: toFlatView.id,
|
||||
updates: viewUpdatedProperties,
|
||||
};
|
||||
|
||||
validateAndBuildResult.updated.push(updateViewAction);
|
||||
}
|
||||
|
||||
return validateAndBuildResult;
|
||||
}
|
||||
}
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
import { ViewKey } from 'src/engine/core-modules/view/enums/view-key.enum';
|
||||
import { ViewType } from 'src/engine/core-modules/view/enums/view-type.enum';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import {
|
||||
type CreateViewAction,
|
||||
type WorkspaceMigrationViewActionV2,
|
||||
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-action-v2.type';
|
||||
|
||||
type BuildWorkspaceMigrationViewActionsArgs = {
|
||||
createdFlatObjectMetadatas: FlatObjectMetadata[];
|
||||
};
|
||||
|
||||
const getCreateViewAction = (
|
||||
flatObjectMetadata: FlatObjectMetadata,
|
||||
): CreateViewAction => {
|
||||
return {
|
||||
type: 'create_view',
|
||||
view: {
|
||||
objectMetadataId: flatObjectMetadata.id,
|
||||
type: ViewType.TABLE,
|
||||
name: `All {objectLabelPlural}`,
|
||||
key: ViewKey.INDEX,
|
||||
isCustom: false,
|
||||
icon: 'IconList',
|
||||
viewFields: flatObjectMetadata.flatFieldMetadatas
|
||||
.filter((field) => field.name !== 'id' && field.name !== 'deletedAt')
|
||||
.map((field, index) => ({
|
||||
fieldMetadataId: field.id,
|
||||
position: index,
|
||||
isVisible: true,
|
||||
size: 180,
|
||||
})),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const buildWorkspaceMigrationViewActions = ({
|
||||
createdFlatObjectMetadatas,
|
||||
}: BuildWorkspaceMigrationViewActionsArgs): WorkspaceMigrationViewActionV2[] => {
|
||||
return createdFlatObjectMetadatas.map(getCreateViewAction);
|
||||
};
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
import { type FromTo } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatEntityMaps } from 'src/engine/core-modules/common/types/flat-entity-maps.type';
|
||||
import { type FlatEntity } from 'src/engine/core-modules/common/types/flat-entity.type';
|
||||
import { deletedCreatedUpdatedMatrixDispatcher } from 'src/engine/workspace-manager/workspace-migration-v2/utils/deleted-created-updated-matrix-dispatcher.util';
|
||||
import { type WorkspaceMigrationActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-action-common-v2';
|
||||
import { type WorkspaceMigrationV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-v2';
|
||||
|
||||
export type SuccessfulEntityMigrationBuildResult<TFlatEntityMaps> = {
|
||||
status: 'success';
|
||||
workspaceMigration: WorkspaceMigrationV2;
|
||||
optimisticFlatEntityMaps: TFlatEntityMaps;
|
||||
};
|
||||
|
||||
export type FailedEntityMigrationBuildResult<TFailedValidation> = {
|
||||
status: 'fail';
|
||||
errors: TFailedValidation[];
|
||||
};
|
||||
|
||||
export abstract class WorkspaceEntityMigrationBuilderV2Service<
|
||||
TFlatEntityMaps extends FlatEntityMaps<TFlatEntity>,
|
||||
TFlatEntity extends FlatEntity,
|
||||
TFailedValidation,
|
||||
TActionType extends WorkspaceMigrationActionV2,
|
||||
TBuildArgs extends { workspaceId: string } & FromTo<TFlatEntityMaps, string>,
|
||||
> {
|
||||
public async validateAndBuild(
|
||||
args: TBuildArgs,
|
||||
): Promise<
|
||||
| SuccessfulEntityMigrationBuildResult<TFlatEntityMaps>
|
||||
| FailedEntityMigrationBuildResult<TFailedValidation>
|
||||
> {
|
||||
const { from: fromEntityMaps, to: toEntityMaps } =
|
||||
this.extractFromToEntityMaps(args);
|
||||
|
||||
const fromEntities = Object.values(fromEntityMaps.byId).filter(isDefined);
|
||||
const toEntities = Object.values(toEntityMaps.byId).filter(isDefined);
|
||||
|
||||
const { created, deleted, updated } = deletedCreatedUpdatedMatrixDispatcher(
|
||||
{
|
||||
from: fromEntities,
|
||||
to: toEntities,
|
||||
},
|
||||
);
|
||||
|
||||
const result = await this.validateAndBuildActions({
|
||||
...args,
|
||||
created,
|
||||
updated,
|
||||
deleted,
|
||||
});
|
||||
|
||||
if (result.failed.length > 0) {
|
||||
return {
|
||||
status: 'fail',
|
||||
errors: result.failed,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: 'success',
|
||||
workspaceMigration: {
|
||||
workspaceId: args.workspaceId,
|
||||
actions: [...result.deleted, ...result.created, ...result.updated],
|
||||
},
|
||||
optimisticFlatEntityMaps: result.optimisticMaps,
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: Refactor, this is too hacky
|
||||
private extractFromToEntityMaps(args: TBuildArgs): {
|
||||
from: TFlatEntityMaps;
|
||||
to: TFlatEntityMaps;
|
||||
} {
|
||||
const fromKey = Object.keys(args).find((key) =>
|
||||
key.startsWith('from'),
|
||||
) as keyof TBuildArgs;
|
||||
const toKey = Object.keys(args).find((key) =>
|
||||
key.startsWith('to'),
|
||||
) as keyof TBuildArgs;
|
||||
|
||||
return {
|
||||
from: args[fromKey] as TFlatEntityMaps,
|
||||
to: args[toKey] as TFlatEntityMaps,
|
||||
};
|
||||
}
|
||||
|
||||
protected abstract validateAndBuildActions(
|
||||
args: TBuildArgs & {
|
||||
created: TFlatEntity[];
|
||||
updated: { from: TFlatEntity; to: TFlatEntity }[];
|
||||
deleted: TFlatEntity[];
|
||||
},
|
||||
): Promise<{
|
||||
failed: TFailedValidation[];
|
||||
created: TActionType[];
|
||||
deleted: TActionType[];
|
||||
updated: TActionType[];
|
||||
optimisticMaps: TFlatEntityMaps;
|
||||
}>;
|
||||
}
|
||||
+11
-13
@@ -10,20 +10,20 @@ import { deletedCreatedUpdatedMatrixDispatcher } from 'src/engine/workspace-mana
|
||||
import { WorkspaceMigrationV2FieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/services/workspace-migration-v2-field-actions-builder.service';
|
||||
import { buildWorkspaceMigrationIndexActions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/index/workspace-migration-v2-index-actions-builder';
|
||||
import { WorkspaceMigrationV2ObjectActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/object/services/workspace-migration-v2-object-actions-builder.service';
|
||||
import { buildWorkspaceMigrationViewActions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view/workspace-migration-v2-view-actions-builder';
|
||||
import { WorkspaceMigrationV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-v2';
|
||||
import { computeUpdatedObjectMetadataDeletedCreatedUpdatedFieldMatrix } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/compute-updated-object-metadata-deleted-created-updated-field-matrix.util';
|
||||
import { computeUpdatedObjectMetadataDeletedCreatedUpdatedIndexMatrix } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/compute-updated-object-metadata-deleted-created-updated-index-matrix.util';
|
||||
import { getWorkspaceMigrationV2CreateIndexAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-index-actions';
|
||||
|
||||
export type WorkspaceMigrationV2BuilderOptions = {
|
||||
inferDeletionFromMissingObjectFieldIndex: boolean;
|
||||
inferDeletionFromMissingEntities: boolean;
|
||||
isSystemBuild: boolean;
|
||||
};
|
||||
|
||||
type SuccessfulWorkspaceMigrationBuildResult = {
|
||||
status: 'success';
|
||||
workspaceMigration: WorkspaceMigrationV2;
|
||||
optimisticFlatEntityMaps: FlatObjectMetadataMaps;
|
||||
};
|
||||
|
||||
export type FailedWorkspaceMigrationBuildResult = {
|
||||
@@ -71,11 +71,13 @@ export class WorkspaceMigrationBuilderV2Service {
|
||||
to: toFlatObjectMetadatas,
|
||||
});
|
||||
|
||||
// Should be handled separately from objects
|
||||
const objectMetadataDeletedCreatedUpdatedIndex =
|
||||
computeUpdatedObjectMetadataDeletedCreatedUpdatedIndexMatrix(
|
||||
updatedFlatObjectMetadatas,
|
||||
);
|
||||
|
||||
// Should be handled separately from objects
|
||||
const objectMetadataDeletedCreatedUpdatedFields =
|
||||
computeUpdatedObjectMetadataDeletedCreatedUpdatedFieldMatrix(
|
||||
updatedFlatObjectMetadatas,
|
||||
@@ -116,12 +118,7 @@ export class WorkspaceMigrationBuilderV2Service {
|
||||
const indexWorkspaceMigrationActions = buildWorkspaceMigrationIndexActions({
|
||||
objectMetadataDeletedCreatedUpdatedIndex,
|
||||
inferDeletionFromMissingObjectFieldIndex:
|
||||
buildOptions.inferDeletionFromMissingObjectFieldIndex,
|
||||
});
|
||||
|
||||
// TODO: Remove this from here when we have a proper builder that handles views diffing independently
|
||||
const viewWorkspaceMigrationActions = buildWorkspaceMigrationViewActions({
|
||||
createdFlatObjectMetadatas, // should be flatViews, not objects.
|
||||
buildOptions.inferDeletionFromMissingEntities,
|
||||
});
|
||||
|
||||
const allValidateAndBuildResultFailures = [
|
||||
@@ -141,17 +138,18 @@ export class WorkspaceMigrationBuilderV2Service {
|
||||
workspaceMigration: {
|
||||
workspaceId,
|
||||
actions: [
|
||||
...fieldActionsValidateAndBuildResult.deleted,
|
||||
...fieldActionsValidateAndBuildResult.deleted, // Should be handled separately from objects
|
||||
...objectActionsValidateAndBuildResult.deleted,
|
||||
...objectActionsValidateAndBuildResult.created,
|
||||
...objectActionsValidateAndBuildResult.updated,
|
||||
...fieldActionsValidateAndBuildResult.created,
|
||||
...fieldActionsValidateAndBuildResult.updated,
|
||||
...fieldActionsValidateAndBuildResult.created, // Should be handled separately from objects
|
||||
...fieldActionsValidateAndBuildResult.updated, // Should be handled separately from objects
|
||||
...createdObjectMetadataCreateIndexActions,
|
||||
...indexWorkspaceMigrationActions,
|
||||
...viewWorkspaceMigrationActions,
|
||||
...indexWorkspaceMigrationActions, // Should be handled separately from objects
|
||||
],
|
||||
},
|
||||
optimisticFlatEntityMaps:
|
||||
fieldActionsValidateAndBuildResult.optimisticFlatObjectMetadataMaps,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { type FromTo } from 'twenty-shared/types';
|
||||
|
||||
import { FailedFlatViewFieldValidation } from 'src/engine/core-modules/view/flat-view/types/failed-flat-view-field-validation.type';
|
||||
import { FlatViewFieldMaps } from 'src/engine/core-modules/view/flat-view/types/flat-view-field-maps.type';
|
||||
import { FlatViewField } from 'src/engine/core-modules/view/flat-view/types/flat-view-field.type';
|
||||
import { WorkspaceMigrationOrchestratorOptimisticEntityMaps } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
|
||||
import { WorkspaceMigrationV2ViewFieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view-field/workspace-migration-v2-view-field-actions-builder.service';
|
||||
import {
|
||||
FailedEntityMigrationBuildResult,
|
||||
WorkspaceEntityMigrationBuilderV2Service,
|
||||
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-entity-migration-builder-v2.service';
|
||||
import { WorkspaceMigrationViewFieldActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-field-action-v2.type';
|
||||
|
||||
export type WorkspaceViewFieldMigrationV2BuilderOptions = {
|
||||
isSystemBuild: boolean;
|
||||
inferDeletionFromMissingEntities: boolean;
|
||||
};
|
||||
|
||||
export type FailedWorkspaceViewFieldMigrationBuildResult =
|
||||
FailedEntityMigrationBuildResult<FailedFlatViewFieldValidation>;
|
||||
|
||||
export type WorkspaceViewFieldMigrationBuildArgs = {
|
||||
workspaceId: string;
|
||||
buildOptions: WorkspaceViewFieldMigrationV2BuilderOptions;
|
||||
dependencyOptimisticEntityMaps: WorkspaceMigrationOrchestratorOptimisticEntityMaps;
|
||||
} & FromTo<FlatViewFieldMaps, 'FlatViewFieldMaps'>;
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceViewFieldMigrationBuilderV2Service extends WorkspaceEntityMigrationBuilderV2Service<
|
||||
FlatViewFieldMaps,
|
||||
FlatViewField,
|
||||
FailedFlatViewFieldValidation,
|
||||
WorkspaceMigrationViewFieldActionV2,
|
||||
WorkspaceViewFieldMigrationBuildArgs
|
||||
> {
|
||||
constructor(
|
||||
private readonly workspaceMigrationV2ViewFieldActionsBuilderService: WorkspaceMigrationV2ViewFieldActionsBuilderService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async validateAndBuildActions(
|
||||
args: WorkspaceViewFieldMigrationBuildArgs & {
|
||||
created: FlatViewField[];
|
||||
updated: { from: FlatViewField; to: FlatViewField }[];
|
||||
deleted: FlatViewField[];
|
||||
},
|
||||
): Promise<{
|
||||
failed: FailedFlatViewFieldValidation[];
|
||||
created: WorkspaceMigrationViewFieldActionV2[];
|
||||
deleted: WorkspaceMigrationViewFieldActionV2[];
|
||||
updated: WorkspaceMigrationViewFieldActionV2[];
|
||||
optimisticMaps: FlatViewFieldMaps;
|
||||
}> {
|
||||
const viewFieldActionsValidateAndBuildResult =
|
||||
await this.workspaceMigrationV2ViewFieldActionsBuilderService.validateAndBuildViewFieldActions(
|
||||
{
|
||||
fromFlatViewFieldMaps: args.fromFlatViewFieldMaps,
|
||||
toFlatViewFieldMaps: args.toFlatViewFieldMaps,
|
||||
createdFlatViewField: args.created,
|
||||
updatedFlatViewField: args.updated,
|
||||
deletedFlatViewField: args.deleted,
|
||||
buildOptions: args.buildOptions,
|
||||
dependencyOptimisticEntityMaps: args.dependencyOptimisticEntityMaps,
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
failed: viewFieldActionsValidateAndBuildResult.failed,
|
||||
created: viewFieldActionsValidateAndBuildResult.created,
|
||||
deleted: viewFieldActionsValidateAndBuildResult.deleted,
|
||||
updated: viewFieldActionsValidateAndBuildResult.updated,
|
||||
optimisticMaps:
|
||||
viewFieldActionsValidateAndBuildResult.optimisticFlatViewFieldMaps,
|
||||
};
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { type FromTo } from 'twenty-shared/types';
|
||||
|
||||
import { FailedFlatViewValidation } from 'src/engine/core-modules/view/flat-view/types/failed-flat-view-validation.type';
|
||||
import { FlatViewMaps } from 'src/engine/core-modules/view/flat-view/types/flat-view-maps.type';
|
||||
import { FlatView } from 'src/engine/core-modules/view/flat-view/types/flat-view.type';
|
||||
import { WorkspaceMigrationOrchestratorOptimisticEntityMaps } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
|
||||
import { WorkspaceMigrationV2ViewActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view/workspace-migration-v2-view-actions-builder.service';
|
||||
import {
|
||||
FailedEntityMigrationBuildResult,
|
||||
WorkspaceEntityMigrationBuilderV2Service,
|
||||
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-entity-migration-builder-v2.service';
|
||||
import { WorkspaceMigrationViewActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-action-v2.type';
|
||||
|
||||
export type WorkspaceViewMigrationV2BuilderOptions = {
|
||||
isSystemBuild: boolean;
|
||||
inferDeletionFromMissingEntities: boolean;
|
||||
};
|
||||
|
||||
export type FailedWorkspaceViewMigrationBuildResult =
|
||||
FailedEntityMigrationBuildResult<FailedFlatViewValidation>;
|
||||
|
||||
export type WorkspaceViewMigrationBuildArgs = {
|
||||
workspaceId: string;
|
||||
buildOptions: WorkspaceViewMigrationV2BuilderOptions;
|
||||
dependencyOptimisticEntityMaps: WorkspaceMigrationOrchestratorOptimisticEntityMaps;
|
||||
} & FromTo<FlatViewMaps, 'FlatViewMaps'>;
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceViewMigrationBuilderV2Service extends WorkspaceEntityMigrationBuilderV2Service<
|
||||
FlatViewMaps,
|
||||
FlatView,
|
||||
FailedFlatViewValidation,
|
||||
WorkspaceMigrationViewActionV2,
|
||||
WorkspaceViewMigrationBuildArgs
|
||||
> {
|
||||
constructor(
|
||||
private readonly workspaceMigrationV2ViewActionsBuilderService: WorkspaceMigrationV2ViewActionsBuilderService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async validateAndBuildActions(
|
||||
args: WorkspaceViewMigrationBuildArgs & {
|
||||
created: FlatView[];
|
||||
updated: { from: FlatView; to: FlatView }[];
|
||||
deleted: FlatView[];
|
||||
},
|
||||
): Promise<{
|
||||
failed: FailedFlatViewValidation[];
|
||||
created: WorkspaceMigrationViewActionV2[];
|
||||
deleted: WorkspaceMigrationViewActionV2[];
|
||||
updated: WorkspaceMigrationViewActionV2[];
|
||||
optimisticMaps: FlatViewMaps;
|
||||
}> {
|
||||
const viewActionsValidateAndBuildResult =
|
||||
await this.workspaceMigrationV2ViewActionsBuilderService.validateAndBuildViewActions(
|
||||
{
|
||||
fromFlatViewMaps: args.fromFlatViewMaps,
|
||||
toFlatViewMaps: args.toFlatViewMaps,
|
||||
createdFlatView: args.created,
|
||||
updatedFlatView: args.updated,
|
||||
deletedFlatView: args.deleted,
|
||||
buildOptions: args.buildOptions,
|
||||
dependencyOptimisticEntityMaps: args.dependencyOptimisticEntityMaps,
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
failed: viewActionsValidateAndBuildResult.failed,
|
||||
created: viewActionsValidateAndBuildResult.created,
|
||||
deleted: viewActionsValidateAndBuildResult.deleted,
|
||||
updated: viewActionsValidateAndBuildResult.updated,
|
||||
optimisticMaps: viewActionsValidateAndBuildResult.optimisticFlatViewMaps,
|
||||
};
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { type FailedFlatViewValidation } from 'src/engine/core-modules/view/flat-view/types/failed-flat-view-validation.type';
|
||||
import { type FlatViewMaps } from 'src/engine/core-modules/view/flat-view/types/flat-view-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 ValidateAndBuildViewResult<T extends WorkspaceMigrationActionV2> = {
|
||||
failed: FailedFlatViewValidation[];
|
||||
created: T[];
|
||||
deleted: T[];
|
||||
updated: T[];
|
||||
optimisticFlatViewMaps: FlatViewMaps;
|
||||
};
|
||||
+3
-1
@@ -2,12 +2,14 @@ import { type WorkspaceMigrationFieldActionV2 } from 'src/engine/workspace-manag
|
||||
import { type WorkspaceMigrationIndexActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-index-action-v2';
|
||||
import { type WorkspaceMigrationObjectActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2';
|
||||
import { type WorkspaceMigrationViewActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-action-v2.type';
|
||||
import { type WorkspaceMigrationViewFieldActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-field-action-v2.type';
|
||||
|
||||
export type WorkspaceMigrationActionV2 =
|
||||
| WorkspaceMigrationObjectActionV2
|
||||
| WorkspaceMigrationFieldActionV2
|
||||
| WorkspaceMigrationIndexActionV2
|
||||
| WorkspaceMigrationViewActionV2;
|
||||
| WorkspaceMigrationViewActionV2
|
||||
| WorkspaceMigrationViewFieldActionV2;
|
||||
|
||||
export type WorkspaceMigrationActionTypeV2 = WorkspaceMigrationActionV2['type'];
|
||||
|
||||
|
||||
+28
-2
@@ -1,11 +1,37 @@
|
||||
import { type FlatView } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-view.type';
|
||||
import { type FromTo } from 'twenty-shared/types';
|
||||
|
||||
import { type ViewEntity } from 'src/engine/core-modules/view/entities/view.entity';
|
||||
import { type FlatViewPropertiesToCompare } from 'src/engine/core-modules/view/flat-view/types/flat-view-properties-to-compare.type';
|
||||
import { type FlatView } from 'src/engine/core-modules/view/flat-view/types/flat-view.type';
|
||||
|
||||
export type FlatViewPropertyUpdate<P extends FlatViewPropertiesToCompare> = {
|
||||
property: P;
|
||||
} & FromTo<ViewEntity[P]>;
|
||||
|
||||
export type CreateViewAction = {
|
||||
type: 'create_view';
|
||||
view: FlatView;
|
||||
};
|
||||
|
||||
export type WorkspaceMigrationViewActionV2 = CreateViewAction;
|
||||
export type UpdateViewAction = {
|
||||
type: 'update_view';
|
||||
viewId: string;
|
||||
updates: Array<
|
||||
{
|
||||
[P in FlatViewPropertiesToCompare]: FlatViewPropertyUpdate<P>;
|
||||
}[FlatViewPropertiesToCompare]
|
||||
>;
|
||||
};
|
||||
|
||||
export type DeleteViewAction = {
|
||||
type: 'delete_view';
|
||||
viewId: string;
|
||||
};
|
||||
|
||||
export type WorkspaceMigrationViewActionV2 =
|
||||
| CreateViewAction
|
||||
| UpdateViewAction
|
||||
| DeleteViewAction;
|
||||
|
||||
export type WorkspaceMigrationViewActionTypeV2 =
|
||||
WorkspaceMigrationViewActionV2['type'];
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
import { type FromTo } from 'twenty-shared/types';
|
||||
|
||||
import { type ViewFieldEntity } from 'src/engine/core-modules/view/entities/view-field.entity';
|
||||
import { type FlatViewFieldPropertiesToCompare } from 'src/engine/core-modules/view/flat-view/types/flat-view-field-properties-to-compare.type';
|
||||
import { type FlatViewField } from 'src/engine/core-modules/view/flat-view/types/flat-view-field.type';
|
||||
|
||||
export type FlatViewFieldPropertyUpdate<
|
||||
P extends FlatViewFieldPropertiesToCompare,
|
||||
> = {
|
||||
property: P;
|
||||
} & FromTo<ViewFieldEntity[P]>;
|
||||
|
||||
export type CreateViewFieldAction = {
|
||||
type: 'create_view_field';
|
||||
viewField: FlatViewField;
|
||||
};
|
||||
|
||||
export type UpdateViewFieldAction = {
|
||||
type: 'update_view_field';
|
||||
viewFieldId: string;
|
||||
updates: Array<
|
||||
{
|
||||
[P in FlatViewFieldPropertiesToCompare]: FlatViewFieldPropertyUpdate<P>;
|
||||
}[FlatViewFieldPropertiesToCompare]
|
||||
>;
|
||||
};
|
||||
|
||||
export type DeleteViewFieldAction = {
|
||||
type: 'delete_view_field';
|
||||
viewFieldId: string;
|
||||
};
|
||||
|
||||
export type WorkspaceMigrationViewFieldActionV2 =
|
||||
| CreateViewFieldAction
|
||||
| UpdateViewFieldAction
|
||||
| DeleteViewFieldAction;
|
||||
|
||||
export type WorkspaceMigrationViewFieldActionTypeV2 =
|
||||
WorkspaceMigrationViewFieldActionV2['type'];
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import { type FlatView } from 'src/engine/core-modules/view/flat-view/types/flat-view.type';
|
||||
import {
|
||||
type CreateViewAction,
|
||||
type DeleteViewAction,
|
||||
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-action-v2.type';
|
||||
|
||||
export const getWorkspaceMigrationV2ViewCreateAction = ({
|
||||
flatView,
|
||||
}: {
|
||||
flatView: FlatView;
|
||||
}): CreateViewAction => ({
|
||||
type: 'create_view',
|
||||
view: flatView,
|
||||
});
|
||||
|
||||
export const getWorkspaceMigrationV2ViewDeleteAction = (
|
||||
flatView: FlatView,
|
||||
): DeleteViewAction => ({
|
||||
type: 'delete_view',
|
||||
viewId: flatView.id,
|
||||
});
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import { type FlatViewField } from 'src/engine/core-modules/view/flat-view/types/flat-view-field.type';
|
||||
import {
|
||||
type CreateViewFieldAction,
|
||||
type DeleteViewFieldAction,
|
||||
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-field-action-v2.type';
|
||||
|
||||
export const getWorkspaceMigrationV2ViewFieldCreateAction = ({
|
||||
flatViewField,
|
||||
}: {
|
||||
flatViewField: FlatViewField;
|
||||
}): CreateViewFieldAction => ({
|
||||
type: 'create_view_field',
|
||||
viewField: flatViewField,
|
||||
});
|
||||
|
||||
export const getWorkspaceMigrationV2ViewFieldDeleteAction = (
|
||||
flatViewField: FlatViewField,
|
||||
): DeleteViewFieldAction => ({
|
||||
type: 'delete_view_field',
|
||||
viewFieldId: flatViewField.id,
|
||||
});
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ViewExceptionCode } from 'src/engine/core-modules/view/exceptions/view.exception';
|
||||
import { FailedFlatViewFieldValidation } from 'src/engine/core-modules/view/flat-view/types/failed-flat-view-field-validation.type';
|
||||
import { FlatViewFieldMaps } from 'src/engine/core-modules/view/flat-view/types/flat-view-field-maps.type';
|
||||
import { FlatViewField } from 'src/engine/core-modules/view/flat-view/types/flat-view-field.type';
|
||||
import { FlatViewMaps } from 'src/engine/core-modules/view/flat-view/types/flat-view-maps.type';
|
||||
import { FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.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';
|
||||
|
||||
@Injectable()
|
||||
export class FlatViewFieldValidatorService {
|
||||
constructor() {}
|
||||
|
||||
public validateFlatViewFieldUpdate({
|
||||
existingFlatViewFieldMaps,
|
||||
updatedFlatViewField,
|
||||
optimisticFlatViewMaps,
|
||||
}: {
|
||||
existingFlatViewFieldMaps: FlatViewFieldMaps;
|
||||
updatedFlatViewField: FlatViewField;
|
||||
optimisticFlatViewMaps: FlatViewMaps;
|
||||
}): FailedFlatViewFieldValidation {
|
||||
const errors = [];
|
||||
|
||||
const optimisticFlatView =
|
||||
optimisticFlatViewMaps.byId[updatedFlatViewField.viewId];
|
||||
|
||||
if (!isDefined(optimisticFlatView)) {
|
||||
errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`View not found`,
|
||||
userFriendlyMessage: t`View not found`,
|
||||
});
|
||||
}
|
||||
|
||||
const existingFlatViewField =
|
||||
existingFlatViewFieldMaps.byId[updatedFlatViewField.id];
|
||||
|
||||
if (!isDefined(existingFlatViewField)) {
|
||||
errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`View field not found`,
|
||||
userFriendlyMessage: t`View field not found`,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'update_view_field',
|
||||
viewFieldLevelErrors: errors,
|
||||
failedViewFieldValidationMinimalInformation: {
|
||||
id: updatedFlatViewField.id,
|
||||
viewId: updatedFlatViewField.viewId,
|
||||
fieldMetadataId: updatedFlatViewField.fieldMetadataId,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public validateFlatViewFieldDeletion({
|
||||
existingFlatViewFieldMaps,
|
||||
viewFieldIdToDelete,
|
||||
optimisticFlatViewMaps,
|
||||
}: {
|
||||
existingFlatViewFieldMaps: FlatViewFieldMaps;
|
||||
viewFieldIdToDelete: string;
|
||||
optimisticFlatViewMaps: FlatViewMaps;
|
||||
}): FailedFlatViewFieldValidation {
|
||||
const errors = [];
|
||||
|
||||
const optimisticFlatView = optimisticFlatViewMaps.byId[viewFieldIdToDelete];
|
||||
|
||||
if (!isDefined(optimisticFlatView)) {
|
||||
errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`View not found`,
|
||||
userFriendlyMessage: t`View not found`,
|
||||
});
|
||||
}
|
||||
|
||||
const existingFlatViewField =
|
||||
existingFlatViewFieldMaps.byId[viewFieldIdToDelete];
|
||||
|
||||
if (!isDefined(existingFlatViewField)) {
|
||||
errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`View field not found`,
|
||||
userFriendlyMessage: t`View field not found`,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'delete_view_field',
|
||||
viewFieldLevelErrors: errors,
|
||||
failedViewFieldValidationMinimalInformation: {
|
||||
id: viewFieldIdToDelete,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public async validateFlatViewFieldCreation({
|
||||
_existingFlatViewFieldMaps,
|
||||
flatViewFieldToValidate,
|
||||
optimisticFlatObjectMetadataMaps,
|
||||
optimisticFlatViewMaps,
|
||||
}: {
|
||||
_existingFlatViewFieldMaps: FlatViewFieldMaps;
|
||||
flatViewFieldToValidate: FlatViewField;
|
||||
optimisticFlatObjectMetadataMaps: FlatObjectMetadataMaps;
|
||||
optimisticFlatViewMaps: FlatViewMaps;
|
||||
}): Promise<FailedFlatViewFieldValidation> {
|
||||
const errors = [];
|
||||
|
||||
const relatedFlatFieldMetadata =
|
||||
findFlatFieldMetadataInFlatObjectMetadataMapsWithOnlyFieldId({
|
||||
fieldMetadataId: flatViewFieldToValidate.fieldMetadataId,
|
||||
flatObjectMetadataMaps: optimisticFlatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(relatedFlatFieldMetadata)) {
|
||||
errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`Field metadata not found`,
|
||||
userFriendlyMessage: t`Field metadata not found`,
|
||||
});
|
||||
}
|
||||
|
||||
const optimisticFlatView =
|
||||
optimisticFlatViewMaps.byId[flatViewFieldToValidate.viewId];
|
||||
|
||||
if (!isDefined(optimisticFlatView)) {
|
||||
errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`View not found`,
|
||||
userFriendlyMessage: t`View not found`,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'create_view_field',
|
||||
viewFieldLevelErrors: errors,
|
||||
failedViewFieldValidationMinimalInformation: {
|
||||
id: flatViewFieldToValidate.id,
|
||||
viewId: flatViewFieldToValidate.viewId,
|
||||
fieldMetadataId: flatViewFieldToValidate.fieldMetadataId,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ViewExceptionCode } from 'src/engine/core-modules/view/exceptions/view.exception';
|
||||
import { FailedFlatViewValidation } from 'src/engine/core-modules/view/flat-view/types/failed-flat-view-validation.type';
|
||||
import { FlatViewMaps } from 'src/engine/core-modules/view/flat-view/types/flat-view-maps.type';
|
||||
import { FlatView } from 'src/engine/core-modules/view/flat-view/types/flat-view.type';
|
||||
import { FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
|
||||
|
||||
@Injectable()
|
||||
export class FlatViewValidatorService {
|
||||
constructor() {}
|
||||
|
||||
public validateFlatViewUpdate({
|
||||
existingFlatViewMaps,
|
||||
updatedFlatView,
|
||||
}: {
|
||||
existingFlatViewMaps: FlatViewMaps;
|
||||
updatedFlatView: FlatView;
|
||||
}): FailedFlatViewValidation {
|
||||
const errors = [];
|
||||
|
||||
const existingFlatView = existingFlatViewMaps.byId[updatedFlatView.id];
|
||||
|
||||
if (!isDefined(existingFlatView)) {
|
||||
errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`View not found`,
|
||||
userFriendlyMessage: t`View not found`,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'update_view',
|
||||
viewLevelErrors: errors,
|
||||
failedViewValidationMinimalInformation: {
|
||||
id: updatedFlatView.id,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public validateFlatViewDeletion({
|
||||
existingFlatViewMaps,
|
||||
viewIdToDelete,
|
||||
}: {
|
||||
existingFlatViewMaps: FlatViewMaps;
|
||||
viewIdToDelete: string;
|
||||
}): FailedFlatViewValidation {
|
||||
const errors = [];
|
||||
|
||||
const existingFlatView = existingFlatViewMaps.byId[viewIdToDelete];
|
||||
|
||||
if (!isDefined(existingFlatView)) {
|
||||
errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`View not found`,
|
||||
userFriendlyMessage: t`View not found`,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'delete_view',
|
||||
viewLevelErrors: errors,
|
||||
failedViewValidationMinimalInformation: {
|
||||
id: viewIdToDelete,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public async validateFlatViewCreation({
|
||||
_existingFlatViewMaps,
|
||||
flatViewToValidate,
|
||||
optimisticFlatObjectMetadataMaps,
|
||||
}: {
|
||||
_existingFlatViewMaps: FlatViewMaps;
|
||||
flatViewToValidate: FlatView;
|
||||
optimisticFlatObjectMetadataMaps: FlatObjectMetadataMaps;
|
||||
}): Promise<FailedFlatViewValidation> {
|
||||
const optimisticFlatObjectMetadata =
|
||||
optimisticFlatObjectMetadataMaps.byId[
|
||||
flatViewToValidate.objectMetadataId
|
||||
];
|
||||
|
||||
const errors = [];
|
||||
|
||||
if (!isDefined(optimisticFlatObjectMetadata)) {
|
||||
errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`Object metadata not found`,
|
||||
userFriendlyMessage: t`Object metadata not found`,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'create_view',
|
||||
viewLevelErrors: errors,
|
||||
failedViewValidationMinimalInformation: {
|
||||
id: flatViewToValidate.id,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { FlatViewFieldValidatorService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/validators/services/flat-view-field-validator.service';
|
||||
import { FlatViewValidatorService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/validators/services/flat-view-validator.service';
|
||||
|
||||
@Module({
|
||||
providers: [FlatViewValidatorService, FlatViewFieldValidatorService],
|
||||
exports: [FlatViewValidatorService, FlatViewFieldValidatorService],
|
||||
})
|
||||
export class WorkspaceMigrationBuilderValidatorsModule {}
|
||||
+15
-2
@@ -6,10 +6,15 @@ import { FlatFieldMetadataValidatorService } from 'src/engine/metadata-modules/f
|
||||
import { FlatObjectMetadataValidatorService } from 'src/engine/metadata-modules/flat-object-metadata/services/flat-object-metadata-validator.service';
|
||||
import { WorkspaceMigrationV2FieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/services/workspace-migration-v2-field-actions-builder.service';
|
||||
import { WorkspaceMigrationV2ObjectActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/object/services/workspace-migration-v2-object-actions-builder.service';
|
||||
import { WorkspaceMigrationV2ViewFieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view-field/workspace-migration-v2-view-field-actions-builder.service';
|
||||
import { WorkspaceMigrationV2ViewActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view/workspace-migration-v2-view-actions-builder.service';
|
||||
import { WorkspaceMigrationBuilderV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-builder-v2.service';
|
||||
import { WorkspaceViewFieldMigrationBuilderV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-view-field-migration-builder-v2.service';
|
||||
import { WorkspaceViewMigrationBuilderV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-view-migration-builder-v2.service';
|
||||
import { WorkspaceMigrationBuilderValidatorsModule } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/validators/workspace-migration-builder-validators.module';
|
||||
|
||||
@Module({
|
||||
imports: [FeatureFlagModule],
|
||||
imports: [FeatureFlagModule, WorkspaceMigrationBuilderValidatorsModule],
|
||||
providers: [
|
||||
WorkspaceMigrationBuilderV2Service,
|
||||
FlatFieldMetadataValidatorService,
|
||||
@@ -17,7 +22,15 @@ import { WorkspaceMigrationBuilderV2Service } from 'src/engine/workspace-manager
|
||||
WorkspaceMigrationV2ObjectActionsBuilderService,
|
||||
FlatObjectMetadataValidatorService,
|
||||
WorkspaceMigrationV2FieldActionsBuilderService,
|
||||
WorkspaceMigrationV2ViewActionsBuilderService,
|
||||
WorkspaceViewMigrationBuilderV2Service,
|
||||
WorkspaceViewFieldMigrationBuilderV2Service,
|
||||
WorkspaceMigrationV2ViewFieldActionsBuilderService,
|
||||
],
|
||||
exports: [
|
||||
WorkspaceMigrationBuilderV2Service,
|
||||
WorkspaceViewMigrationBuilderV2Service,
|
||||
WorkspaceViewFieldMigrationBuilderV2Service,
|
||||
],
|
||||
exports: [WorkspaceMigrationBuilderV2Service],
|
||||
})
|
||||
export class WorkspaceMigrationBuilderV2Module {}
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
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 { 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';
|
||||
|
||||
@Injectable()
|
||||
export class CreateViewFieldActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
|
||||
'create_view_field',
|
||||
) {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async executeForMetadata(
|
||||
context: WorkspaceMigrationActionRunnerArgs<CreateViewFieldAction>,
|
||||
): Promise<void> {
|
||||
const { action, queryRunner, workspaceId } = context;
|
||||
const { viewField } = action;
|
||||
|
||||
const viewFieldRepository =
|
||||
queryRunner.manager.getRepository<ViewFieldEntity>(ViewFieldEntity);
|
||||
|
||||
await viewFieldRepository.save({
|
||||
...viewField,
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
async executeForWorkspaceSchema(
|
||||
_context: WorkspaceMigrationActionRunnerArgs<CreateViewFieldAction>,
|
||||
): Promise<void> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
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 { 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';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteViewFieldActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
|
||||
'delete_view_field',
|
||||
) {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async executeForMetadata(
|
||||
context: WorkspaceMigrationActionRunnerArgs<DeleteViewFieldAction>,
|
||||
): Promise<void> {
|
||||
const { action, queryRunner, workspaceId } = context;
|
||||
const { viewFieldId } = action;
|
||||
|
||||
const viewFieldRepository =
|
||||
queryRunner.manager.getRepository<ViewFieldEntity>(ViewFieldEntity);
|
||||
|
||||
await viewFieldRepository.delete({
|
||||
id: viewFieldId,
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
async executeForWorkspaceSchema(
|
||||
_context: WorkspaceMigrationActionRunnerArgs<DeleteViewFieldAction>,
|
||||
): Promise<void> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
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 { ViewEntity } from 'src/engine/core-modules/view/entities/view.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';
|
||||
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';
|
||||
|
||||
@Injectable()
|
||||
export class UpdateViewFieldActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
|
||||
'update_view_field',
|
||||
) {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async executeForMetadata(
|
||||
context: WorkspaceMigrationActionRunnerArgs<UpdateViewFieldAction>,
|
||||
): Promise<void> {
|
||||
const { action, queryRunner } = context;
|
||||
const { viewFieldId } = action;
|
||||
|
||||
const viewFieldRepository =
|
||||
queryRunner.manager.getRepository<ViewEntity>(ViewEntity);
|
||||
|
||||
await viewFieldRepository.update(
|
||||
viewFieldId,
|
||||
fromWorkspaceMigrationUpdateActionToPartialEntity(action),
|
||||
);
|
||||
}
|
||||
|
||||
async executeForWorkspaceSchema(
|
||||
_context: WorkspaceMigrationActionRunnerArgs<UpdateViewFieldAction>,
|
||||
): Promise<void> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
+1
-14
@@ -2,7 +2,6 @@ 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 { ViewFieldEntity } from 'src/engine/core-modules/view/entities/view-field.entity';
|
||||
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';
|
||||
@@ -21,25 +20,13 @@ export class CreateViewActionHandlerService extends WorkspaceMigrationRunnerActi
|
||||
const { action, queryRunner, workspaceId } = context;
|
||||
const { view } = action;
|
||||
|
||||
const { viewFields } = view;
|
||||
|
||||
const viewRepository =
|
||||
queryRunner.manager.getRepository<ViewEntity>(ViewEntity);
|
||||
const viewFieldRepository =
|
||||
queryRunner.manager.getRepository<ViewFieldEntity>(ViewFieldEntity);
|
||||
|
||||
const createdView = await viewRepository.save({
|
||||
await viewRepository.save({
|
||||
...view,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
await viewFieldRepository.save(
|
||||
viewFields.map((viewField) => ({
|
||||
...viewField,
|
||||
viewId: createdView.id,
|
||||
workspaceId,
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
async executeForWorkspaceSchema(
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
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 { 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';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteViewActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
|
||||
'delete_view',
|
||||
) {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async executeForMetadata(
|
||||
context: WorkspaceMigrationActionRunnerArgs<DeleteViewAction>,
|
||||
): Promise<void> {
|
||||
const { action, queryRunner, workspaceId } = context;
|
||||
const { viewId } = action;
|
||||
|
||||
const viewRepository =
|
||||
queryRunner.manager.getRepository<ViewEntity>(ViewEntity);
|
||||
|
||||
await viewRepository.delete({
|
||||
id: viewId,
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
async executeForWorkspaceSchema(
|
||||
_context: WorkspaceMigrationActionRunnerArgs<DeleteViewAction>,
|
||||
): Promise<void> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
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 { 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';
|
||||
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';
|
||||
|
||||
@Injectable()
|
||||
export class UpdateViewActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
|
||||
'update_view',
|
||||
) {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async executeForMetadata(
|
||||
context: WorkspaceMigrationActionRunnerArgs<UpdateViewAction>,
|
||||
): Promise<void> {
|
||||
const { action, queryRunner } = context;
|
||||
const { viewId } = action;
|
||||
|
||||
const viewRepository =
|
||||
queryRunner.manager.getRepository<ViewEntity>(ViewEntity);
|
||||
|
||||
await viewRepository.update(
|
||||
viewId,
|
||||
fromWorkspaceMigrationUpdateActionToPartialEntity(action),
|
||||
);
|
||||
}
|
||||
|
||||
async executeForWorkspaceSchema(
|
||||
_context: WorkspaceMigrationActionRunnerArgs<UpdateViewAction>,
|
||||
): Promise<void> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
+11
@@ -9,7 +9,12 @@ import { DeleteIndexActionHandlerService } from 'src/engine/workspace-manager/wo
|
||||
import { CreateObjectActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/object/services/create-object-action-handler.service';
|
||||
import { DeleteObjectActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/object/services/delete-object-action-handler.service';
|
||||
import { UpdateObjectActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/object/services/update-object-action-handler.service';
|
||||
import { CreateViewFieldActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view-field/services/create-view-field-action-handler.service';
|
||||
import { DeleteViewFieldActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view-field/services/delete-view-field-action-handler.service';
|
||||
import { UpdateViewFieldActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view-field/services/update-view-field-action-handler.service';
|
||||
import { CreateViewActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view/services/create-view-action-handler.service';
|
||||
import { DeleteViewActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view/services/delete-view-action-handler.service';
|
||||
import { UpdateViewActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view/services/update-view-action-handler.service';
|
||||
|
||||
@Module({
|
||||
imports: [WorkspaceSchemaManagerModule],
|
||||
@@ -26,6 +31,12 @@ import { CreateViewActionHandlerService } from 'src/engine/workspace-manager/wor
|
||||
DeleteIndexActionHandlerService,
|
||||
|
||||
CreateViewActionHandlerService,
|
||||
UpdateViewActionHandlerService,
|
||||
DeleteViewActionHandlerService,
|
||||
|
||||
CreateViewFieldActionHandlerService,
|
||||
UpdateViewFieldActionHandlerService,
|
||||
DeleteViewFieldActionHandlerService,
|
||||
],
|
||||
})
|
||||
export class WorkspaceSchemaMigrationRunnerActionHandlersModule {}
|
||||
|
||||
+5
@@ -135,6 +135,11 @@ export const applyWorkspaceMigrationActionOnFlatObjectMetadataMaps = <
|
||||
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(
|
||||
|
||||
+7
-1
@@ -1,8 +1,14 @@
|
||||
import { type UpdateFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2';
|
||||
import { type UpdateObjectAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2';
|
||||
import { type UpdateViewAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-action-v2.type';
|
||||
import { type UpdateViewFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-field-action-v2.type';
|
||||
|
||||
export const fromWorkspaceMigrationUpdateActionToPartialEntity = <
|
||||
T extends UpdateFieldAction | UpdateObjectAction,
|
||||
T extends
|
||||
| UpdateFieldAction
|
||||
| UpdateObjectAction
|
||||
| UpdateViewAction
|
||||
| UpdateViewFieldAction,
|
||||
>(
|
||||
action: T,
|
||||
) => {
|
||||
|
||||
+13
-2
@@ -1,5 +1,8 @@
|
||||
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';
|
||||
import { WorkspaceMigrationBuilderV2Module } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-builder-v2.module';
|
||||
import { WorkspaceMigrationRunnerV2Module } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/workspace-migration-runner-v2.module';
|
||||
@@ -8,8 +11,16 @@ import { WorkspaceMigrationRunnerV2Module } from 'src/engine/workspace-manager/w
|
||||
imports: [
|
||||
WorkspaceMigrationBuilderV2Module,
|
||||
WorkspaceMigrationRunnerV2Module,
|
||||
WorkspaceMetadataCacheModule,
|
||||
ViewCacheModule,
|
||||
],
|
||||
providers: [
|
||||
WorkspaceMigrationValidateBuildAndRunService,
|
||||
WorkspaceMigrationBuildOrchestratorService,
|
||||
],
|
||||
exports: [
|
||||
WorkspaceMigrationValidateBuildAndRunService,
|
||||
WorkspaceMigrationBuildOrchestratorService,
|
||||
],
|
||||
providers: [WorkspaceMigrationValidateBuildAndRunService],
|
||||
exports: [WorkspaceMigrationValidateBuildAndRunService],
|
||||
})
|
||||
export class WorkspaceMigrationV2Module {}
|
||||
|
||||
Reference in New Issue
Block a user