Create related records after object creation with migration v2 (view, view filters, favorite) (#14068)

## Context
This PR introduces view actions for the migration v2. We should be able
to create, update and delete views through the migration runner
independently from object actions (this is not 100% true in this PR
though as I'm still passing the object metadata to build the view)
Note: Once favorite are moved out of the workspace schema, we will have
favorite actions as well, in the meantime I have to inject some code at
the end of the createOne method from the object metadata service
This commit is contained in:
Weiko
2025-08-26 10:54:03 +02:00
committed by GitHub
parent 0c8631c1c8
commit d433a576d7
21 changed files with 534 additions and 48 deletions
@@ -685,6 +685,9 @@ export class AuthService {
throw new AuthException(
'User does not have access to this workspace',
AuthExceptionCode.FORBIDDEN_EXCEPTION,
{
userFriendlyMessage: t`User does not have access to this workspace`,
},
);
}
}
@@ -1,7 +1,11 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { isDefined } from 'twenty-shared/utils';
import { Repository } from 'typeorm';
import { View } from 'src/engine/core-modules/view/entities/view.entity';
import { ViewKey } from 'src/engine/core-modules/view/enums/view-key.enum';
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';
@@ -22,6 +26,7 @@ import {
ObjectMetadataException,
ObjectMetadataExceptionCode,
} from 'src/engine/metadata-modules/object-metadata/object-metadata.exception';
import { ObjectMetadataRelatedRecordsService } from 'src/engine/metadata-modules/object-metadata/services/object-metadata-related-records.service';
import { WorkspaceMetadataCacheService } from 'src/engine/metadata-modules/workspace-metadata-cache/services/workspace-metadata-cache.service';
import { WorkspaceMigrationBuilderExceptionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/exceptions/workspace-migration-builder-exception-v2';
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration-v2/services/workspace-migration-validate-build-and-run-service';
@@ -31,6 +36,9 @@ export class ObjectMetadataServiceV2 {
constructor(
private readonly workspaceMetadataCacheService: WorkspaceMetadataCacheService,
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
private readonly objectMetadataRelatedRecordsService: ObjectMetadataRelatedRecordsService,
@InjectRepository(View, 'core')
private readonly viewRepository: Repository<View>,
) {}
async updateOne({
@@ -284,6 +292,26 @@ export class ObjectMetadataServiceV2 {
);
}
const [view] = await this.viewRepository.find({
where: {
objectMetadataId: createdFlatObjectMetadata.id,
key: ViewKey.INDEX,
workspaceId,
},
});
if (!isDefined(view)) {
throw new ObjectMetadataException(
'View not created',
ObjectMetadataExceptionCode.INTERNAL_SERVER_ERROR,
);
}
await this.objectMetadataRelatedRecordsService.createViewWorkspaceFavorite(
workspaceId,
view.id,
);
return createdFlatObjectMetadata;
}
}
@@ -11,6 +11,7 @@ import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
import { View } from 'src/engine/core-modules/view/entities/view.entity';
import { SettingsPermissionsGuard } from 'src/engine/guards/settings-permissions.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
@@ -55,7 +56,7 @@ import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspa
[ObjectMetadataEntity, FieldMetadataEntity],
'core',
),
TypeOrmModule.forFeature([FeatureFlag], 'core'),
TypeOrmModule.forFeature([FeatureFlag, View], 'core'),
DataSourceModule,
WorkspaceMigrationModule,
WorkspaceMigrationRunnerModule,
@@ -64,7 +64,7 @@ export class ObjectMetadataRelatedRecordsService {
await viewFieldRepository.insert(viewFields);
}
private async createViewWorkspaceFavorite(
public async createViewWorkspaceFavorite(
workspaceId: string,
viewId: string,
): Promise<void> {
@@ -0,0 +1,6 @@
import { type ViewField } from 'src/engine/core-modules/view/entities/view-field.entity';
export type FlatViewField = Pick<
ViewField,
'fieldMetadataId' | 'position' | 'isVisible' | 'size'
>;
@@ -0,0 +1,9 @@
import { type View } 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<
View,
'name' | 'objectMetadataId' | 'type' | 'isCustom' | 'key' | 'icon'
> & {
viewFields: FlatViewField[];
};
@@ -1031,6 +1031,85 @@ 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,
},
],
},
},
]
`;
@@ -2314,6 +2393,181 @@ 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,
},
],
},
},
]
`;
@@ -2958,6 +3212,85 @@ 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,
},
],
},
},
]
`;
@@ -81,6 +81,7 @@ const CREATE_OBJECT_TEST_CASES: WorkspaceMigrationBuilderTestCase[] = [
},
expectedActionsTypeCounter: {
createObject: 1,
createView: 1,
},
},
},
@@ -102,6 +103,7 @@ const CREATE_OBJECT_TEST_CASES: WorkspaceMigrationBuilderTestCase[] = [
},
expectedActionsTypeCounter: {
createObject: 1,
createView: 1,
},
},
},
@@ -112,6 +114,7 @@ const CREATE_OBJECT_TEST_CASES: WorkspaceMigrationBuilderTestCase[] = [
expectedActionsTypeCounter: {
createIndex: 1,
createObject: 1,
createView: 1,
},
input: {
fromFlatObjectMetadataMaps:
@@ -14,9 +14,9 @@ import {
type ExpectedActionCounters,
type WorkspaceMigrationBuilderTestCase,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/types/workspace-migration-builder-test-case.type';
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 { WorkspaceMigrationBuilderV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-builder-v2.service';
import { WorkspaceMigrationV2FieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-v2-field-actions-builder.service';
import { WorkspaceMigrationV2ObjectActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-v2-object-actions-builder.service';
import { type WorkspaceMigrationV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-v2';
const allWorkspaceBuilderTestCases: {
@@ -54,6 +54,7 @@ const expectedActionsTypeCounterChecker = ({
deleteObject: 0,
updateField: 0,
updateObject: 0,
createView: 0,
};
const actualActionsTypeCounter = workspaceMigration.actions.reduce(
(acc, action) => {
@@ -1,10 +1,10 @@
import { Injectable } from '@nestjs/common';
import { FieldMetadataType, FromTo } from 'twenty-shared/types';
import { FromTo } from 'twenty-shared/types';
import { FlatFieldMetadataValidatorService } from 'src/engine/metadata-modules/flat-field-metadata/services/flat-field-metadata-validator.service';
import { compareTwoFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/compare-two-flat-field-metadata.util';
import { isFlatFieldMetadataEntityOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
import { isRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-relation-flat-field-metadata.util';
import { 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 { deleteFieldFromFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/delete-field-from-flat-object-metadata-maps-or-throw.util';
@@ -115,20 +115,14 @@ export class WorkspaceMigrationV2FieldActionsBuilderService {
}
for (const flatFieldMetadataToCreate of createdFlatFieldMetadatas) {
const relationTargetFlatObjectMetadataMaps =
isFlatFieldMetadataEntityOfType(
flatFieldMetadataToCreate,
FieldMetadataType.RELATION,
) ||
isFlatFieldMetadataEntityOfType(
flatFieldMetadataToCreate,
FieldMetadataType.MORPH_RELATION,
)
? computeRelationTargetFlatObjectMetadataMaps({
flatFieldMetadata: flatFieldMetadataToCreate,
flatObjectMetadataMaps: toFlatObjectMetadataMaps,
})
: undefined;
const relationTargetFlatObjectMetadataMaps = isRelationFlatFieldMetadata(
flatFieldMetadataToCreate,
)
? computeRelationTargetFlatObjectMetadataMaps({
flatFieldMetadata: flatFieldMetadataToCreate,
flatObjectMetadataMaps: toFlatObjectMetadataMaps,
})
: undefined;
const validationErrors =
await this.flatFieldMetadataValidatorService.validateFlatFieldMetadataCreation(
@@ -0,0 +1,41 @@
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);
};
@@ -7,13 +7,14 @@ import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-ob
import { FailedFlatObjectMetadataValidation } from 'src/engine/metadata-modules/flat-object-metadata/types/failed-flat-object-metadata-validation.type';
import { fromFlatObjectMetadataMapsToFlatObjectMetadatas } from 'src/engine/metadata-modules/flat-object-metadata/utils/from-flat-object-metadata-maps-to-flat-object-metadatas.util';
import { deletedCreatedUpdatedMatrixDispatcher } from 'src/engine/workspace-manager/workspace-migration-v2/utils/deleted-created-updated-matrix-dispatcher.util';
import { WorkspaceMigrationV2FieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-v2-field-actions-builder.service';
import { WorkspaceMigrationV2ObjectActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-v2-object-actions-builder.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 { 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';
import { buildWorkspaceMigrationIndexActions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-index-actions-builder';
export type WorkspaceMigrationV2BuilderOptions = {
inferDeletionFromMissingObjectFieldIndex: boolean;
@@ -117,7 +118,11 @@ export class WorkspaceMigrationBuilderV2Service {
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.
});
const allValidateAndBuildResultFailures = [
...objectActionsValidateAndBuildResult.failed,
@@ -144,6 +149,7 @@ export class WorkspaceMigrationBuilderV2Service {
...fieldActionsValidateAndBuildResult.updated,
...createdObjectMetadataCreateIndexActions,
...indexWorkspaceMigrationActions,
...viewWorkspaceMigrationActions,
],
},
};
@@ -1,11 +1,13 @@
import { type WorkspaceMigrationFieldActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2';
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';
export type WorkspaceMigrationActionV2 =
| WorkspaceMigrationObjectActionV2
| WorkspaceMigrationFieldActionV2
| WorkspaceMigrationIndexActionV2;
| WorkspaceMigrationIndexActionV2
| WorkspaceMigrationViewActionV2;
export type WorkspaceMigrationActionTypeV2 = WorkspaceMigrationActionV2['type'];
@@ -0,0 +1,11 @@
import { type FlatView } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-view.type';
export type CreateViewAction = {
type: 'create_view';
view: FlatView;
};
export type WorkspaceMigrationViewActionV2 = CreateViewAction;
export type WorkspaceMigrationViewActionTypeV2 =
WorkspaceMigrationViewActionV2['type'];
@@ -4,9 +4,9 @@ import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-
import { FlatFieldMetadataTypeValidatorService } from 'src/engine/metadata-modules/flat-field-metadata/services/flat-field-metadata-type-validator.service';
import { FlatFieldMetadataValidatorService } from 'src/engine/metadata-modules/flat-field-metadata/services/flat-field-metadata-validator.service';
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 { WorkspaceMigrationBuilderV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-builder-v2.service';
import { WorkspaceMigrationV2FieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-v2-field-actions-builder.service';
import { WorkspaceMigrationV2ObjectActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-v2-object-actions-builder.service';
@Module({
imports: [FeatureFlagModule],
@@ -4,10 +4,10 @@ import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-mana
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 { 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 { 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,6 +25,7 @@ export class CreateObjectActionHandlerService extends WorkspaceMigrationRunnerAc
) {
constructor(
private readonly workspaceSchemaManagerService: WorkspaceSchemaManagerService,
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
) {
super();
}
@@ -74,27 +75,26 @@ export class CreateObjectActionHandlerService extends WorkspaceMigrationRunnerAc
const { action, queryRunner, workspaceId } = context;
const { flatObjectMetadataWithoutFields, createFieldActions } = action;
const flatObjectMetadata = flatObjectMetadataWithoutFields;
const { schemaName, tableName } = getWorkspaceSchemaContextForMigration({
workspaceId,
flatObjectMetadata: flatObjectMetadata,
flatObjectMetadata: flatObjectMetadataWithoutFields,
});
const columnDefinitions = createFieldActions.flatMap((createFieldAction) =>
const flatFieldMetadatas = createFieldActions.map(
(createFieldAction) => createFieldAction.flatFieldMetadata,
);
const columnDefinitions = flatFieldMetadatas.flatMap((flatFieldMetadata) =>
generateColumnDefinitions({
flatFieldMetadata: createFieldAction.flatFieldMetadata,
flatObjectMetadataWithoutFields: flatObjectMetadataWithoutFields,
flatFieldMetadata,
flatObjectMetadataWithoutFields,
}),
);
const enumOrCompositeFlatFieldMetadatas = createFieldActions
.map((createFieldAction) => createFieldAction.flatFieldMetadata)
.filter((field): field is FlatFieldMetadata => field != null)
.filter(
(field) =>
isEnumFlatFieldMetadata(field) || isCompositeFlatFieldMetadata(field),
);
const enumOrCompositeFlatFieldMetadatas = flatFieldMetadatas.filter(
(field) =>
isEnumFlatFieldMetadata(field) || isCompositeFlatFieldMetadata(field),
);
const enumOperations = collectEnumOperationsForObject({
flatFieldMetadatas: enumOrCompositeFlatFieldMetadatas,
@@ -0,0 +1,49 @@
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 { ViewField } from 'src/engine/core-modules/view/entities/view-field.entity';
import { View } 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';
@Injectable()
export class CreateViewActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
'create_view',
) {
constructor() {
super();
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerArgs<CreateViewAction>,
): Promise<void> {
const { action, queryRunner, workspaceId } = context;
const { view } = action;
const { viewFields } = view;
const viewRepository = queryRunner.manager.getRepository<View>(View);
const viewFieldRepository =
queryRunner.manager.getRepository<ViewField>(ViewField);
const createdView = await viewRepository.save({
...view,
workspaceId,
});
await viewFieldRepository.save(
viewFields.map((viewField) => ({
...viewField,
viewId: createdView.id,
workspaceId,
})),
);
}
async executeForWorkspaceSchema(
_context: WorkspaceMigrationActionRunnerArgs<CreateViewAction>,
): Promise<void> {
return;
}
}
@@ -9,6 +9,7 @@ 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 { CreateViewActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view/services/create-view-action-handler.service';
@Module({
imports: [WorkspaceSchemaManagerModule],
@@ -23,6 +24,8 @@ import { UpdateObjectActionHandlerService } from 'src/engine/workspace-manager/w
CreateIndexActionHandlerService,
DeleteIndexActionHandlerService,
CreateViewActionHandlerService,
],
})
export class WorkspaceSchemaMigrationRunnerActionHandlersModule {}
@@ -132,14 +132,10 @@ export const applyWorkspaceMigrationActionOnFlatObjectMetadataMaps = <
objectMetadataId: action.objectMetadataId,
});
}
case 'create_index': {
// TODO prastoin handle indexes
case 'create_index':
case 'delete_index':
case 'create_view':
return flatObjectMetadataMaps;
}
case 'delete_index': {
// TODO prastoin handle indexes
return flatObjectMetadataMaps;
}
default: {
assertUnreachable(
action,