Workspace migration v2 Metadadata runner object and field (#13377)

# Introduction
Created the runner metadata for the field and object
We should keep in mind that any runner handler will only iterate over an
atomic instance of entity ( object field index etc )
Never triggerring any side effect or whats over

In this way we will need to implement a deferred transaction, as for
when we create a relation we will inject to the first created field of
both the `relationTargetFieldMetadataId` deterministically computed
before its own creation
This would result in pg constraint brokage if not deferred

## Updates
- We decided gather create_fields under the create_object as they will
be building within the same sql query. This will ease both generation
and computation and avoid disassembling to reassemble afterwards
- Refactored FlatFieldMetadata to handle relation typing with flat
occurences
```ts
  runCreateFieldSchemaMigration = async ({
    action,
    queryRunner,
  }: WorkspaceMigrationActionRunnerArgs<CreateFieldAction>) => {
    if (isFlatFieldMetadataEntityOfType(action.flatFieldMetadata, FieldMetadataType.RELATION)) {
      action.flatFieldMetadata.flatRelationTargetObjectMetadata
    }else {
      action.flatFieldMetadata.flatRelationTargetObjectMetadata // tsc-error never
    }
    return;
  };
```

## TODO
- ~~Discuss action signature with @Weiko in order to anticipate `schema`
runner needed grain~~
- ~~Refactor the object actions to contain picked `flatObjectMetadata`~~
- Implem index service
This commit is contained in:
Paul Rastoin
2025-07-24 17:04:01 +02:00
committed by GitHub
parent 099694411c
commit 7bfa003682
28 changed files with 629 additions and 1729 deletions

View File

@ -1,4 +1,4 @@
import { FieldMetadataType, IsExactly } from 'twenty-shared/types'; import { FieldMetadataType } from 'twenty-shared/types';
import { import {
Column, Column,
CreateDateColumn, CreateDateColumn,
@ -18,19 +18,11 @@ import { FieldMetadataOptions } from 'src/engine/metadata-modules/field-metadata
import { FieldMetadataSettings } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface'; import { FieldMetadataSettings } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
import { FieldStandardOverridesDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-standard-overrides.dto'; import { FieldStandardOverridesDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-standard-overrides.dto';
import { AssignTypeIfIsRelationFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/types/assign-type-if-is-relation-field-metadata-type.type';
import { IndexFieldMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-field-metadata.entity'; import { IndexFieldMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-field-metadata.entity';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { FieldPermissionEntity } from 'src/engine/metadata-modules/object-permission/field-permission/field-permission.entity'; import { FieldPermissionEntity } from 'src/engine/metadata-modules/object-permission/field-permission/field-permission.entity';
type IsRelationType<Ttype, T extends FieldMetadataType = FieldMetadataType> =
IsExactly<T, FieldMetadataType> extends true
? null | Ttype // Could be improved to be | unknown
: T extends FieldMetadataType.RELATION
? Ttype
: T extends FieldMetadataType.MORPH_RELATION
? Ttype
: never;
@Entity('fieldMetadata') @Entity('fieldMetadata')
@Index( @Index(
'IDX_FIELD_METADATA_NAME_OBJMID_WORKSPACE_ID_EXCEPT_MORPH_UNIQUE', 'IDX_FIELD_METADATA_NAME_OBJMID_WORKSPACE_ID_EXCEPT_MORPH_UNIQUE',
@ -127,7 +119,10 @@ export class FieldMetadataEntity<
isLabelSyncedWithName: boolean; isLabelSyncedWithName: boolean;
@Column({ nullable: true, type: 'uuid' }) @Column({ nullable: true, type: 'uuid' })
relationTargetFieldMetadataId: IsRelationType<string, T>; relationTargetFieldMetadataId: AssignTypeIfIsRelationFieldMetadataType<
string,
T
>;
@OneToOne( @OneToOne(
() => FieldMetadataEntity, () => FieldMetadataEntity,
@ -136,10 +131,16 @@ export class FieldMetadataEntity<
{ nullable: true }, { nullable: true },
) )
@JoinColumn({ name: 'relationTargetFieldMetadataId' }) @JoinColumn({ name: 'relationTargetFieldMetadataId' })
relationTargetFieldMetadata: IsRelationType<Relation<FieldMetadataEntity>, T>; relationTargetFieldMetadata: AssignTypeIfIsRelationFieldMetadataType<
Relation<FieldMetadataEntity>,
T
>;
@Column({ nullable: true, type: 'uuid' }) @Column({ nullable: true, type: 'uuid' })
relationTargetObjectMetadataId: IsRelationType<string, T>; relationTargetObjectMetadataId: AssignTypeIfIsRelationFieldMetadataType<
string,
T
>;
@ManyToOne( @ManyToOne(
() => ObjectMetadataEntity, () => ObjectMetadataEntity,
@ -148,7 +149,7 @@ export class FieldMetadataEntity<
{ onDelete: 'CASCADE', nullable: true }, { onDelete: 'CASCADE', nullable: true },
) )
@JoinColumn({ name: 'relationTargetObjectMetadataId' }) @JoinColumn({ name: 'relationTargetObjectMetadataId' })
relationTargetObjectMetadata: IsRelationType< relationTargetObjectMetadata: AssignTypeIfIsRelationFieldMetadataType<
Relation<ObjectMetadataEntity>, Relation<ObjectMetadataEntity>,
T T
>; >;

View File

@ -0,0 +1,13 @@
import { FieldMetadataType, IsExactly } from 'twenty-shared/types';
export type AssignTypeIfIsRelationFieldMetadataType<
Ttype,
T extends FieldMetadataType,
> =
IsExactly<T, FieldMetadataType> extends true
? null | Ttype // Could be improved to be | unknown
: T extends FieldMetadataType.RELATION
? Ttype
: T extends FieldMetadataType.MORPH_RELATION
? Ttype
: never;

View File

@ -3,6 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm';
import { Query, QueryOptions } from '@ptc-org/nestjs-query-core'; import { Query, QueryOptions } from '@ptc-org/nestjs-query-core';
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm'; import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
import { FieldMetadataType } from 'twenty-shared/types';
import { capitalize, isDefined } from 'twenty-shared/utils'; import { capitalize, isDefined } from 'twenty-shared/utils';
import { import {
FindManyOptions, FindManyOptions,
@ -11,7 +12,6 @@ import {
QueryRunner, QueryRunner,
Repository, Repository,
} from 'typeorm'; } from 'typeorm';
import { FieldMetadataType } from 'twenty-shared/types';
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
@ -43,11 +43,11 @@ import { WorkspaceMetadataCacheService } from 'src/engine/metadata-modules/works
import { WorkspaceMetadataVersionService } from 'src/engine/metadata-modules/workspace-metadata-version/services/workspace-metadata-version.service'; import { WorkspaceMetadataVersionService } from 'src/engine/metadata-modules/workspace-metadata-version/services/workspace-metadata-version.service';
import { WorkspacePermissionsCacheService } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service'; import { WorkspacePermissionsCacheService } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service';
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
import { isFieldMetadataEntityOfType } from 'src/engine/utils/is-field-metadata-of-type.util';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service'; import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service';
import { CUSTOM_OBJECT_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; import { CUSTOM_OBJECT_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
import { isSearchableFieldType } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/is-searchable-field.util'; import { isSearchableFieldType } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/is-searchable-field.util';
import { isFieldMetadataEntityOfType } from 'src/engine/utils/is-field-metadata-of-type.util';
import { ObjectMetadataEntity } from './object-metadata.entity'; import { ObjectMetadataEntity } from './object-metadata.entity';

View File

@ -16,6 +16,9 @@ export const getFlatFieldMetadataMock = <T extends FieldMetadataType>(
const createdAt = faker.date.anytime(); const createdAt = faker.date.anytime();
return { return {
defaultValue: null,
options: null,
settings: null,
createdAt, createdAt,
description: 'default flat field metadata description', description: 'default flat field metadata description',
icon: 'icon', icon: 'icon',
@ -30,14 +33,11 @@ export const getFlatFieldMetadataMock = <T extends FieldMetadataType>(
isSystem: false, isSystem: false,
standardId: null, standardId: null,
standardOverrides: null, standardOverrides: null,
settings: null,
updatedAt: createdAt, updatedAt: createdAt,
workspaceId: faker.string.uuid(), workspaceId: faker.string.uuid(),
defaultValue: null, flatRelationTargetFieldMetadata: undefined as never,
options: null,
relationTargetFieldMetadata: undefined as never,
relationTargetFieldMetadataId: undefined as never, relationTargetFieldMetadataId: undefined as never,
relationTargetObjectMetadata: undefined as never, flatRelationTargetObjectMetadata: undefined as never,
relationTargetObjectMetadataId: undefined as never, relationTargetObjectMetadataId: undefined as never,
...overrides, ...overrides,
}; };

View File

@ -34,8 +34,8 @@ export const getFlatObjectMetadataMock = (
namePlural: 'defaultflatObjectMetadataNamePlural', namePlural: 'defaultflatObjectMetadataNamePlural',
nameSingular: 'defaultflatObjectMetadataNameSingular', nameSingular: 'defaultflatObjectMetadataNameSingular',
shortcut: 'shortcut', shortcut: 'shortcut',
standardId: undefined, standardId: null,
standardOverrides: undefined, standardOverrides: null,
targetTableName: '', targetTableName: '',
updatedAt: createdAt, updatedAt: createdAt,
workspaceId: faker.string.uuid(), workspaceId: faker.string.uuid(),

View File

@ -1,16 +1,32 @@
import { FieldMetadataType } from 'twenty-shared/types'; import { FieldMetadataType } from 'twenty-shared/types';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { ExtractRecordTypeOrmRelationProperties } from 'src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type'; import { AssignTypeIfIsRelationFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/types/assign-type-if-is-relation-field-metadata-type.type';
import { MetadataEntitiesRelationTarget } from 'src/engine/workspace-manager/workspace-migration-v2/types/metadata-entities-relation-targets.type'; import { FlatObjectMetadataWithoutFields } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-object-metadata';
const fieldMetadataRelationProperties = [
'relationTargetFieldMetadata',
'relationTargetObjectMetadata',
'fieldPermissions',
'indexFieldMetadatas',
'object',
] as const satisfies (keyof FieldMetadataEntity)[];
type FieldMetadataEntityRelationProperties = type FieldMetadataEntityRelationProperties =
ExtractRecordTypeOrmRelationProperties< (typeof fieldMetadataRelationProperties)[number];
FieldMetadataEntity,
MetadataEntitiesRelationTarget
>;
export type FlatFieldMetadata<T extends FieldMetadataType = FieldMetadataType> = export type FlatFieldMetadata<T extends FieldMetadataType = FieldMetadataType> =
Omit<FieldMetadataEntity<T>, FieldMetadataEntityRelationProperties> & { Omit<FieldMetadataEntity<T>, FieldMetadataEntityRelationProperties> & {
uniqueIdentifier: string; uniqueIdentifier: string;
flatRelationTargetFieldMetadata: AssignTypeIfIsRelationFieldMetadataType<
Omit<
FlatFieldMetadata,
'flatRelationTargetFieldMetadata' | 'flatRelationTargetObjectMetadata'
>,
T
>;
flatRelationTargetObjectMetadata: AssignTypeIfIsRelationFieldMetadataType<
FlatObjectMetadataWithoutFields,
T
>;
}; };

View File

@ -9,8 +9,9 @@ type ObjectMetadataRelationProperties = ExtractRecordTypeOrmRelationProperties<
MetadataEntitiesRelationTarget MetadataEntitiesRelationTarget
>; >;
export type FlatObjectMetadata = Partial< export type FlatObjectMetadata = Omit<
Omit<ObjectMetadataEntity, ObjectMetadataRelationProperties> ObjectMetadataEntity,
ObjectMetadataRelationProperties
> & { > & {
uniqueIdentifier: string; uniqueIdentifier: string;
flatIndexMetadatas: FlatIndexMetadata[]; flatIndexMetadatas: FlatIndexMetadata[];

View File

@ -1,10 +1,16 @@
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 { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { IndexFieldMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-field-metadata.entity'; import { IndexFieldMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-field-metadata.entity';
import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { FieldPermissionEntity } from 'src/engine/metadata-modules/object-permission/field-permission/field-permission.entity'; import { FieldPermissionEntity } from 'src/engine/metadata-modules/object-permission/field-permission/field-permission.entity';
import { ObjectPermissionEntity } from 'src/engine/metadata-modules/object-permission/object-permission.entity';
export type MetadataEntitiesRelationTarget = export type MetadataEntitiesRelationTarget =
| ObjectMetadataEntity | ObjectMetadataEntity
| FieldMetadataEntity | FieldMetadataEntity
| IndexFieldMetadataEntity | IndexFieldMetadataEntity
| FieldPermissionEntity; | FieldPermissionEntity
| DataSourceEntity
| IndexMetadataEntity
| ObjectPermissionEntity;

View File

@ -0,0 +1,13 @@
import { FieldMetadataType } from 'twenty-shared/types';
import { FlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-field-metadata';
export function isFlatFieldMetadataEntityOfType<
Field extends FlatFieldMetadata<FieldMetadataType>,
Type extends FieldMetadataType,
>(
fieldMetadata: Pick<Field, 'type'>,
type: Type,
): fieldMetadata is Field & FlatFieldMetadata<Type> {
return fieldMetadata.type === type;
}

View File

@ -25,13 +25,21 @@ const relationTestCases: WorkspaceMigrationBuilderTestCase[] = [
context: { context: {
input: () => { input: () => {
const objectMetadataId = faker.string.uuid(); const objectMetadataId = faker.string.uuid();
const targetObjectMetadataId = faker.string.uuid();
const createdFlatRelationFieldMetadata = getFlatFieldMetadataMock({ const createdFlatRelationFieldMetadata = getFlatFieldMetadataMock({
uniqueIdentifier: 'field-metadata-unique-identifier-1', uniqueIdentifier: 'field-metadata-unique-identifier-1',
objectMetadataId, objectMetadataId,
type: FieldMetadataType.RELATION, type: FieldMetadataType.RELATION,
relationTargetFieldMetadataId: faker.string.uuid(), relationTargetFieldMetadataId: faker.string.uuid(),
relationTargetObjectMetadataId: faker.string.uuid(), relationTargetObjectMetadataId: faker.string.uuid(),
flatRelationTargetFieldMetadata: getFlatFieldMetadataMock({
objectMetadataId: targetObjectMetadataId,
type: FieldMetadataType.RELATION,
uniqueIdentifier: 'field-metadata-unique-identifier-2',
}),
flatRelationTargetObjectMetadata: getFlatObjectMetadataMock({
uniqueIdentifier: 'object-metadata-unique-identifier-2',
}),
}); });
const flatObjectMetadata = getFlatObjectMetadataMock({ const flatObjectMetadata = getFlatObjectMetadataMock({
uniqueIdentifier: 'object-metadata-unique-identifier-1', uniqueIdentifier: 'object-metadata-unique-identifier-1',

View File

@ -2,6 +2,7 @@ import { faker } from '@faker-js/faker';
import { FieldMetadataType } from 'twenty-shared/types'; import { FieldMetadataType } from 'twenty-shared/types';
import { getFlatFieldMetadataMock } from 'src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-field-metadata.mock'; import { getFlatFieldMetadataMock } from 'src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-field-metadata.mock';
import { getFlatIndexMetadataMock } from 'src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-index-metadata.mock';
import { getFlatObjectMetadataMock } from 'src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-object-metadata.mock'; import { getFlatObjectMetadataMock } from 'src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-object-metadata.mock';
import { WorkspaceMigrationBuilderTestCase } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/types/workspace-migration-builder-test-case.type'; import { WorkspaceMigrationBuilderTestCase } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/types/workspace-migration-builder-test-case.type';
@ -59,7 +60,7 @@ export const WORKSPACE_MIGRATION_OBJECT_BUILDER_TEST_CASES: WorkspaceMigrationBu
}, },
{ {
title: title:
'It should build a create_object and create_field actions for each of this fieldMetadata', 'It should build a create_object and create_field and create_index actions for each of this fieldMetadata',
context: { context: {
input: () => { input: () => {
const objectMetadataId = faker.string.uuid(); const objectMetadataId = faker.string.uuid();
@ -72,6 +73,10 @@ export const WORKSPACE_MIGRATION_OBJECT_BUILDER_TEST_CASES: WorkspaceMigrationBu
uniqueIdentifier: `field_${index}`, uniqueIdentifier: `field_${index}`,
}), }),
); );
const flatIndexMetadata = getFlatIndexMetadataMock({
uniqueIdentifier: 'field-metadata-unique-identifier-1',
objectMetadataId,
});
const flatObjectMetadata = getFlatObjectMetadataMock({ const flatObjectMetadata = getFlatObjectMetadataMock({
uniqueIdentifier: 'pomme', uniqueIdentifier: 'pomme',
nameSingular: 'toto', nameSingular: 'toto',
@ -79,6 +84,7 @@ export const WORKSPACE_MIGRATION_OBJECT_BUILDER_TEST_CASES: WorkspaceMigrationBu
isLabelSyncedWithName: true, isLabelSyncedWithName: true,
id: objectMetadataId, id: objectMetadataId,
flatFieldMetadatas, flatFieldMetadatas,
flatIndexMetadatas: [flatIndexMetadata],
}); });
return { return {
@ -89,7 +95,8 @@ export const WORKSPACE_MIGRATION_OBJECT_BUILDER_TEST_CASES: WorkspaceMigrationBu
expectedActionsTypeCounter: { expectedActionsTypeCounter: {
createObject: 1, createObject: 1,
createField: 5, createField: 0,
createIndex: 1,
}, },
}, },
}, },

View File

@ -6,7 +6,7 @@ import { WorkspaceMigrationBuilderV2Service } from 'src/engine/workspace-manager
type WorkspaceBuilderArgs = Parameters< type WorkspaceBuilderArgs = Parameters<
typeof WorkspaceMigrationBuilderV2Service.prototype.build typeof WorkspaceMigrationBuilderV2Service.prototype.build
>[0]; >[0]['objectMetadataFromToInputs'];
export type CamelCasedWorkspaceMigrationActionsType = export type CamelCasedWorkspaceMigrationActionsType =
ConvertActionTypeToCamelCase<WorkspaceMigrationActionTypeV2>; ConvertActionTypeToCamelCase<WorkspaceMigrationActionTypeV2>;

View File

@ -83,8 +83,11 @@ describe.each(allWorkspaceBuilderTestCases)(
({ context: { input, expectedActionsTypeCounter } }) => { ({ context: { input, expectedActionsTypeCounter } }) => {
const { from, to } = typeof input === 'function' ? input() : input; const { from, to } = typeof input === 'function' ? input() : input;
const workspaceMigration = service.build({ const workspaceMigration = service.build({
from, objectMetadataFromToInputs: {
to, from,
to,
},
workspaceId: '20202020-52cc-4c64-ad63-76c26fc3a1e1',
}); });
expectedActionsTypeCounterChecker({ expectedActionsTypeCounterChecker({

View File

@ -4,28 +4,31 @@ import { FlatObjectMetadataWithoutFields } from 'src/engine/workspace-manager/wo
import { FromTo } from 'src/engine/workspace-manager/workspace-migration-v2/types/from-to.type'; import { FromTo } from 'src/engine/workspace-manager/workspace-migration-v2/types/from-to.type';
import { FlatFieldMetadataPropertiesToCompare } from 'src/engine/workspace-manager/workspace-migration-v2/utils/flat-field-metadata-comparator.util'; import { FlatFieldMetadataPropertiesToCompare } from 'src/engine/workspace-manager/workspace-migration-v2/utils/flat-field-metadata-comparator.util';
export type FieldAndObjectMetadataWorkspaceMigrationInput = {
flatFieldMetadata: FlatFieldMetadata;
flatObjectMetadata: FlatObjectMetadataWithoutFields;
};
export type CreateFieldAction = { export type CreateFieldAction = {
type: 'create_field'; type: 'create_field';
} & FieldAndObjectMetadataWorkspaceMigrationInput; flatFieldMetadata: FlatFieldMetadata;
flatObjectMetadataWithoutFields: FlatObjectMetadataWithoutFields;
};
export type UpdateFieldAction = { export type UpdateFieldAction = {
type: 'update_field'; type: 'update_field';
updates: Partial< workspaceId: string;
flatFieldMetadata: FlatFieldMetadata;
flatObjectMetadataWithoutFields: FlatObjectMetadataWithoutFields;
updates: Array<
{ {
[P in FlatFieldMetadataPropertiesToCompare]: { [P in FlatFieldMetadataPropertiesToCompare]: {
property: P; property: P;
} & FromTo<FieldMetadataEntity[P]>; } & FromTo<FieldMetadataEntity[P]>;
}[FlatFieldMetadataPropertiesToCompare] }[FlatFieldMetadataPropertiesToCompare]
>[]; >;
} & FieldAndObjectMetadataWorkspaceMigrationInput; };
export type DeleteFieldAction = { export type DeleteFieldAction = {
type: 'delete_field'; type: 'delete_field';
} & FieldAndObjectMetadataWorkspaceMigrationInput; flatFieldMetadata: FlatFieldMetadata;
flatObjectMetadataWithoutFields: FlatObjectMetadataWithoutFields;
};
export type WorkspaceMigrationFieldActionV2 = export type WorkspaceMigrationFieldActionV2 =
| CreateFieldAction | CreateFieldAction

View File

@ -2,28 +2,30 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat
import { FlatObjectMetadataWithoutFields } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-object-metadata'; import { FlatObjectMetadataWithoutFields } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-object-metadata';
import { FromTo } from 'src/engine/workspace-manager/workspace-migration-v2/types/from-to.type'; import { FromTo } from 'src/engine/workspace-manager/workspace-migration-v2/types/from-to.type';
import { FlatObjectMetadataPropertiesToCompare } from 'src/engine/workspace-manager/workspace-migration-v2/utils/flat-object-metadata-comparator.util'; import { FlatObjectMetadataPropertiesToCompare } from 'src/engine/workspace-manager/workspace-migration-v2/utils/flat-object-metadata-comparator.util';
import { CreateFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2';
type ObjectActionCommon = {
flatObjectMetadata: FlatObjectMetadataWithoutFields;
};
export type CreateObjectAction = { export type CreateObjectAction = {
type: 'create_object'; type: 'create_object';
} & ObjectActionCommon; flatObjectMetadataWithoutFields: FlatObjectMetadataWithoutFields;
createFieldActions: CreateFieldAction[];
};
export type UpdateObjectAction = { export type UpdateObjectAction = {
type: 'update_object'; type: 'update_object';
updates: Partial< flatObjectMetadataWithoutFields: FlatObjectMetadataWithoutFields;
updates: Array<
{ {
[P in FlatObjectMetadataPropertiesToCompare]: { [P in FlatObjectMetadataPropertiesToCompare]: {
property: P; property: P;
} & FromTo<ObjectMetadataEntity[P]>; } & FromTo<ObjectMetadataEntity[P]>;
}[FlatObjectMetadataPropertiesToCompare] }[FlatObjectMetadataPropertiesToCompare]
>[]; >;
} & ObjectActionCommon; };
export type DeleteObjectAction = { export type DeleteObjectAction = {
type: 'delete_object'; type: 'delete_object';
} & ObjectActionCommon; flatObjectMetadataWithoutFields: FlatObjectMetadataWithoutFields;
};
export type WorkspaceMigrationObjectActionV2 = export type WorkspaceMigrationObjectActionV2 =
| CreateObjectAction | CreateObjectAction

View File

@ -8,5 +8,6 @@ export type WorkspaceMigrationV2<
// name: string; // name: string;
// description?: string; // description?: string;
actions: TActions[]; actions: TActions[];
workspaceId: string;
// objectActions: TActions[] // could be cool ? // objectActions: TActions[] // could be cool ?
}; };

View File

@ -1,8 +1,5 @@
import { FlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-field-metadata'; import { FlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-field-metadata';
import { import { FlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-object-metadata';
FlatObjectMetadata,
FlatObjectMetadataWithoutFields,
} from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-object-metadata';
import { FromTo } from 'src/engine/workspace-manager/workspace-migration-v2/types/from-to.type'; import { FromTo } from 'src/engine/workspace-manager/workspace-migration-v2/types/from-to.type';
import { import {
CustomDeletedCreatedUpdatedMatrix, CustomDeletedCreatedUpdatedMatrix,
@ -10,7 +7,7 @@ import {
} from 'src/engine/workspace-manager/workspace-migration-v2/utils/deleted-created-updated-matrix-dispatcher.util'; } from 'src/engine/workspace-manager/workspace-migration-v2/utils/deleted-created-updated-matrix-dispatcher.util';
export type UpdatedObjectMetadataDeletedCreatedUpdatedFieldMatrix = { export type UpdatedObjectMetadataDeletedCreatedUpdatedFieldMatrix = {
flatObjectMetadata: FlatObjectMetadataWithoutFields; flatObjectMetadata: FlatObjectMetadata;
} & CustomDeletedCreatedUpdatedMatrix<'fieldMetadata', FlatFieldMetadata>; } & CustomDeletedCreatedUpdatedMatrix<'fieldMetadata', FlatFieldMetadata>;
export const computeUpdatedObjectMetadataDeletedCreatedUpdatedFieldMatrix = ( export const computeUpdatedObjectMetadataDeletedCreatedUpdatedFieldMatrix = (

View File

@ -0,0 +1,10 @@
import {
FlatObjectMetadata,
FlatObjectMetadataWithoutFields,
} from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-object-metadata';
export const fromFlatObjectMetadataToFlatObjectMetadataWithoutFields = ({
flatFieldMetadatas: _flatFieldMetadatas,
flatIndexMetadatas: _flatIndexMetadatas,
...rest
}: FlatObjectMetadata): FlatObjectMetadataWithoutFields => rest;

View File

@ -1,23 +1,32 @@
import { FlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-field-metadata';
import { FlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-object-metadata';
import { import {
CreateFieldAction, CreateFieldAction,
DeleteFieldAction, DeleteFieldAction,
FieldAndObjectMetadataWorkspaceMigrationInput,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2'; } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2';
import { fromFlatObjectMetadataToFlatObjectMetadataWithoutFields } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/from-flat-object-metadata-to-flat-object-metadata-without-fields.util';
type FlatFieldMetadataAndFlatObjectMetadata = {
flatFieldMetadata: FlatFieldMetadata;
flatObjectMetadata: FlatObjectMetadata;
};
export const getWorkspaceMigrationV2FieldCreateAction = ({ export const getWorkspaceMigrationV2FieldCreateAction = ({
flatFieldMetadata, flatFieldMetadata,
flatObjectMetadata, flatObjectMetadata,
}: FieldAndObjectMetadataWorkspaceMigrationInput): CreateFieldAction => ({ }: FlatFieldMetadataAndFlatObjectMetadata): CreateFieldAction => ({
type: 'create_field', type: 'create_field',
flatFieldMetadata, flatFieldMetadata,
flatObjectMetadata, flatObjectMetadataWithoutFields:
fromFlatObjectMetadataToFlatObjectMetadataWithoutFields(flatObjectMetadata),
}); });
export const getWorkspaceMigrationV2FieldDeleteAction = ({ export const getWorkspaceMigrationV2FieldDeleteAction = ({
flatFieldMetadata, flatFieldMetadata,
flatObjectMetadata, flatObjectMetadata,
}: FieldAndObjectMetadataWorkspaceMigrationInput): DeleteFieldAction => ({ }: FlatFieldMetadataAndFlatObjectMetadata): DeleteFieldAction => ({
type: 'delete_field', type: 'delete_field',
flatFieldMetadata, flatFieldMetadata,
flatObjectMetadata, flatObjectMetadataWithoutFields:
fromFlatObjectMetadataToFlatObjectMetadataWithoutFields(flatObjectMetadata),
}); });

View File

@ -1,19 +1,28 @@
import { FlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-object-metadata'; import { FlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-object-metadata';
import { CreateFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2';
import { import {
CreateObjectAction, CreateObjectAction,
DeleteObjectAction, DeleteObjectAction,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2'; } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2';
import { fromFlatObjectMetadataToFlatObjectMetadataWithoutFields } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/from-flat-object-metadata-to-flat-object-metadata-without-fields.util';
export const getWorkspaceMigrationV2ObjectCreateAction = ( export const getWorkspaceMigrationV2ObjectCreateAction = ({
flatObjectMetadata: FlatObjectMetadata, createFieldActions,
): CreateObjectAction => ({
type: 'create_object',
flatObjectMetadata, flatObjectMetadata,
}: {
flatObjectMetadata: FlatObjectMetadata;
createFieldActions: CreateFieldAction[];
}): CreateObjectAction => ({
type: 'create_object',
flatObjectMetadataWithoutFields:
fromFlatObjectMetadataToFlatObjectMetadataWithoutFields(flatObjectMetadata),
createFieldActions,
}); });
export const getWorkspaceMigrationV2ObjectDeleteAction = ( export const getWorkspaceMigrationV2ObjectDeleteAction = (
flatObjectMetadata: FlatObjectMetadata, flatObjectMetadata: FlatObjectMetadata,
): DeleteObjectAction => ({ ): DeleteObjectAction => ({
type: 'delete_object', type: 'delete_object',
flatObjectMetadata, flatObjectMetadataWithoutFields:
fromFlatObjectMetadataToFlatObjectMetadataWithoutFields(flatObjectMetadata),
}); });

View File

@ -6,7 +6,7 @@ import { deletedCreatedUpdatedMatrixDispatcher } from 'src/engine/workspace-mana
import { WorkspaceMigrationV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-v2'; 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 { 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 { 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 { getWorkspaceMigrationV2FieldCreateAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-field-actions'; import { getWorkspaceMigrationV2FieldDeleteAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-field-actions';
import { getWorkspaceMigrationV2CreateIndexAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-index-actions'; import { getWorkspaceMigrationV2CreateIndexAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-index-actions';
import { buildWorkspaceMigrationV2FieldActions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-field-actions-builder'; import { buildWorkspaceMigrationV2FieldActions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-field-actions-builder';
import { buildWorkspaceMigrationIndexActions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-index-actions-builder'; import { buildWorkspaceMigrationIndexActions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-index-actions-builder';
@ -15,9 +15,13 @@ import { buildWorkspaceMigrationV2ObjectActions } from 'src/engine/workspace-man
export class WorkspaceMigrationBuilderV2Service { export class WorkspaceMigrationBuilderV2Service {
constructor() {} constructor() {}
build( build({
objectMetadataFromToInputs: FromTo<FlatObjectMetadata[]>, objectMetadataFromToInputs,
): WorkspaceMigrationV2 { workspaceId,
}: {
objectMetadataFromToInputs: FromTo<FlatObjectMetadata[]>;
workspaceId: string;
}): WorkspaceMigrationV2 {
const { const {
created: createdObjectMetadata, created: createdObjectMetadata,
deleted: deletedObjectMetadata, deleted: deletedObjectMetadata,
@ -31,16 +35,6 @@ export class WorkspaceMigrationBuilderV2Service {
updatedObjectMetadata, updatedObjectMetadata,
}); });
const createdObjectWorkspaceMigrationCreateFieldActions =
createdObjectMetadata.flatMap((flatObjectMetadata) =>
flatObjectMetadata.flatFieldMetadatas.map((flatFieldMetadata) =>
getWorkspaceMigrationV2FieldCreateAction({
flatFieldMetadata,
flatObjectMetadata,
}),
),
);
const createdObjectMetadataCreateIndexActions = const createdObjectMetadataCreateIndexActions =
createdObjectMetadata.flatMap((objectMetadata) => createdObjectMetadata.flatMap((objectMetadata) =>
objectMetadata.flatIndexMetadatas.map( objectMetadata.flatIndexMetadatas.map(
@ -48,6 +42,16 @@ export class WorkspaceMigrationBuilderV2Service {
), ),
); );
const deletedObjectWorkspaceMigrationDeleteFieldActions =
deletedObjectMetadata.flatMap((flatObjectMetadata) =>
flatObjectMetadata.flatFieldMetadatas.map((flatFieldMetadata) =>
getWorkspaceMigrationV2FieldDeleteAction({
flatFieldMetadata,
flatObjectMetadata,
}),
),
);
const updatedObjectMetadataDeletedCreatedUpdatedFieldMatrix = const updatedObjectMetadataDeletedCreatedUpdatedFieldMatrix =
computeUpdatedObjectMetadataDeletedCreatedUpdatedFieldMatrix( computeUpdatedObjectMetadataDeletedCreatedUpdatedFieldMatrix(
updatedObjectMetadata, updatedObjectMetadata,
@ -67,9 +71,10 @@ export class WorkspaceMigrationBuilderV2Service {
); );
return { return {
workspaceId,
actions: [ actions: [
...objectWorkspaceMigrationActions, ...objectWorkspaceMigrationActions,
...createdObjectWorkspaceMigrationCreateFieldActions, ...deletedObjectWorkspaceMigrationDeleteFieldActions,
...createdObjectMetadataCreateIndexActions, ...createdObjectMetadataCreateIndexActions,
...fieldWorkspaceMigrationActions, ...fieldWorkspaceMigrationActions,
...indexWorkspaceMigrationActions, ...indexWorkspaceMigrationActions,

View File

@ -4,6 +4,7 @@ import {
WorkspaceMigrationFieldActionV2, WorkspaceMigrationFieldActionV2,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2'; } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2';
import { UpdatedObjectMetadataDeletedCreatedUpdatedFieldMatrix } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/compute-updated-object-metadata-deleted-created-updated-field-matrix.util'; import { UpdatedObjectMetadataDeletedCreatedUpdatedFieldMatrix } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/compute-updated-object-metadata-deleted-created-updated-field-matrix.util';
import { fromFlatObjectMetadataToFlatObjectMetadataWithoutFields } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/from-flat-object-metadata-to-flat-object-metadata-without-fields.util';
import { import {
getWorkspaceMigrationV2FieldCreateAction, getWorkspaceMigrationV2FieldCreateAction,
getWorkspaceMigrationV2FieldDeleteAction, getWorkspaceMigrationV2FieldDeleteAction,
@ -35,7 +36,11 @@ export const buildWorkspaceMigrationV2FieldActions = (
return { return {
type: 'update_field', type: 'update_field',
flatFieldMetadata: to, flatFieldMetadata: to,
flatObjectMetadata, flatObjectMetadataWithoutFields:
fromFlatObjectMetadataToFlatObjectMetadataWithoutFields(
flatObjectMetadata,
),
workspaceId: to.workspaceId,
updates, updates,
}; };
}, },

View File

@ -5,6 +5,8 @@ import {
UpdateObjectAction, UpdateObjectAction,
WorkspaceMigrationObjectActionV2, WorkspaceMigrationObjectActionV2,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2'; } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2';
import { fromFlatObjectMetadataToFlatObjectMetadataWithoutFields } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/from-flat-object-metadata-to-flat-object-metadata-without-fields.util';
import { getWorkspaceMigrationV2FieldCreateAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-field-actions';
import { import {
getWorkspaceMigrationV2ObjectCreateAction, getWorkspaceMigrationV2ObjectCreateAction,
getWorkspaceMigrationV2ObjectDeleteAction, getWorkspaceMigrationV2ObjectDeleteAction,
@ -18,7 +20,20 @@ export const buildWorkspaceMigrationV2ObjectActions = ({
updatedObjectMetadata, updatedObjectMetadata,
}: CreatedDeletedUpdatedObjectMetadataInputMatrix): WorkspaceMigrationObjectActionV2[] => { }: CreatedDeletedUpdatedObjectMetadataInputMatrix): WorkspaceMigrationObjectActionV2[] => {
const createdObjectActions = createdObjectMetadata.map( const createdObjectActions = createdObjectMetadata.map(
getWorkspaceMigrationV2ObjectCreateAction, (flatObjectMetadata) => {
const createFieldActions = flatObjectMetadata.flatFieldMetadatas.map(
(flatFieldMetadata) =>
getWorkspaceMigrationV2FieldCreateAction({
flatFieldMetadata,
flatObjectMetadata,
}),
);
return getWorkspaceMigrationV2ObjectCreateAction({
flatObjectMetadata,
createFieldActions,
});
},
); );
const deletedObjectActions = deletedObjectMetadata.map( const deletedObjectActions = deletedObjectMetadata.map(
@ -38,7 +53,8 @@ export const buildWorkspaceMigrationV2ObjectActions = ({
return { return {
type: 'update_object', type: 'update_object',
flatObjectMetadata: to, flatObjectMetadataWithoutFields:
fromFlatObjectMetadataToFlatObjectMetadataWithoutFields(to),
updates: objectUpdatedProperties, updates: objectUpdatedProperties,
}; };
}); });

View File

@ -1,5 +1,8 @@
import { Injectable } from '@nestjs/common'; import { In } from 'typeorm';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { FlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-field-metadata';
import { FlatFieldMetadataPropertiesToCompare } from 'src/engine/workspace-manager/workspace-migration-v2/utils/flat-field-metadata-comparator.util';
import { import {
CreateFieldAction, CreateFieldAction,
DeleteFieldAction, DeleteFieldAction,
@ -9,24 +12,59 @@ import {
import { RunnerMethodForActionType } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/types/runner-method-for-action-type'; import { RunnerMethodForActionType } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/types/runner-method-for-action-type';
import { WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/types/workspace-migration-action-runner-args.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 WorkspaceMetadataFieldActionRunnerService export class WorkspaceMetadataFieldActionRunnerService
implements implements
RunnerMethodForActionType<WorkspaceMigrationFieldActionTypeV2, 'metadata'> RunnerMethodForActionType<WorkspaceMigrationFieldActionTypeV2, 'metadata'>
{ {
runDeleteFieldMetadataMigration = async ( runDeleteFieldMetadataMigration = async ({
_action: WorkspaceMigrationActionRunnerArgs<DeleteFieldAction>, action,
) => { queryRunner,
return; }: WorkspaceMigrationActionRunnerArgs<DeleteFieldAction>) => {
const fieldMetadataRepository =
queryRunner.manager.getRepository<FieldMetadataEntity>(
FieldMetadataEntity,
);
const { flatFieldMetadata } = action;
await fieldMetadataRepository.delete({
id: In([flatFieldMetadata.id]),
});
}; };
runCreateFieldMetadataMigration = async (
_action: WorkspaceMigrationActionRunnerArgs<CreateFieldAction>, runCreateFieldMetadataMigration = async ({
) => { action,
return; queryRunner,
}: WorkspaceMigrationActionRunnerArgs<CreateFieldAction>) => {
const fieldMetadataRepository =
queryRunner.manager.getRepository<FieldMetadataEntity>(
FieldMetadataEntity,
);
const { flatFieldMetadata } = action;
// We need to defer here in case we create a relation the relationTargetFieldMetadataId might not already be created here
await fieldMetadataRepository.save(flatFieldMetadata);
}; };
runUpdateFieldMetadataMigration = async ( runUpdateFieldMetadataMigration = async ({
_action: WorkspaceMigrationActionRunnerArgs<UpdateFieldAction>, action,
) => { queryRunner,
return; }: WorkspaceMigrationActionRunnerArgs<UpdateFieldAction>) => {
const fieldMetadataRepository =
queryRunner.manager.getRepository<FieldMetadataEntity>(
FieldMetadataEntity,
);
const { flatFieldMetadata, updates } = action;
const update = updates.reduce<
Partial<Pick<FlatFieldMetadata, FlatFieldMetadataPropertiesToCompare>>
>((acc, { property, to }) => {
return {
...acc,
[property]: to,
};
}, {});
await fieldMetadataRepository.update(flatFieldMetadata.id, update);
}; };
} }

View File

@ -1,5 +1,9 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { FlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-object-metadata';
import { FlatObjectMetadataPropertiesToCompare } from 'src/engine/workspace-manager/workspace-migration-v2/utils/flat-object-metadata-comparator.util';
import { import {
CreateObjectAction, CreateObjectAction,
DeleteObjectAction, DeleteObjectAction,
@ -14,19 +18,61 @@ export class WorkspaceMetadataObjectActionRunnerService
implements implements
RunnerMethodForActionType<WorkspaceMigrationObjectActionTypeV2, 'metadata'> RunnerMethodForActionType<WorkspaceMigrationObjectActionTypeV2, 'metadata'>
{ {
runDeleteObjectMetadataMigration = async ( constructor(private readonly dataSourceService: DataSourceService) {}
_action: WorkspaceMigrationActionRunnerArgs<DeleteObjectAction>,
) => { runDeleteObjectMetadataMigration = async ({
return; action: { flatObjectMetadataWithoutFields },
queryRunner,
}: WorkspaceMigrationActionRunnerArgs<DeleteObjectAction>) => {
const objectMetadataRepository =
queryRunner.manager.getRepository<ObjectMetadataEntity>(
ObjectMetadataEntity,
);
await objectMetadataRepository.delete(flatObjectMetadataWithoutFields.id);
}; };
runCreateObjectMetadataMigration = async (
_action: WorkspaceMigrationActionRunnerArgs<CreateObjectAction>, runCreateObjectMetadataMigration = async ({
) => { action: { flatObjectMetadataWithoutFields },
return; queryRunner,
}: WorkspaceMigrationActionRunnerArgs<CreateObjectAction>) => {
const objectMetadataRepository =
queryRunner.manager.getRepository<ObjectMetadataEntity>(
ObjectMetadataEntity,
);
const lastDataSourceMetadata =
await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail(
flatObjectMetadataWithoutFields.workspaceId,
);
await objectMetadataRepository.save({
...flatObjectMetadataWithoutFields,
dataSourceId: lastDataSourceMetadata.id,
targetTableName: 'DEPRECATED',
});
}; };
runUpdateObjectMetadataMigration = async (
_action: WorkspaceMigrationActionRunnerArgs<UpdateObjectAction>, runUpdateObjectMetadataMigration = async ({
) => { action: { flatObjectMetadataWithoutFields, updates },
return; queryRunner,
}: WorkspaceMigrationActionRunnerArgs<UpdateObjectAction>) => {
const objectMetadataRepository =
queryRunner.manager.getRepository<ObjectMetadataEntity>(
ObjectMetadataEntity,
);
const update = updates.reduce<
Partial<Pick<FlatObjectMetadata, FlatObjectMetadataPropertiesToCompare>>
>((acc, { property, to }) => {
return {
...acc,
[property]: to,
};
}, {});
await objectMetadataRepository.save({
...flatObjectMetadataWithoutFields, // could be stricter
...update,
});
}; };
} }

View File

@ -2,6 +2,9 @@ import { Module } from '@nestjs/common';
import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
import { WorkspaceMetadataVersionModule } from 'src/engine/metadata-modules/workspace-metadata-version/workspace-metadata-version.module';
import { WorkspacePermissionsCacheModule } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.module';
import { WorkspaceMetadataFieldActionRunnerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/workspace-metadata-migration-runner/workspace-metadata-field-action-runner.service'; import { WorkspaceMetadataFieldActionRunnerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/workspace-metadata-migration-runner/workspace-metadata-field-action-runner.service';
import { WorkspaceMetadataIndexActionRunnerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/workspace-metadata-migration-runner/workspace-metadata-index-action-runner.service'; import { WorkspaceMetadataIndexActionRunnerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/workspace-metadata-migration-runner/workspace-metadata-index-action-runner.service';
import { WorkspaceMetadataMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/workspace-metadata-migration-runner/workspace-metadata-migration-runner-service'; import { WorkspaceMetadataMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/workspace-metadata-migration-runner/workspace-metadata-migration-runner-service';
@ -13,7 +16,13 @@ import { WorkspaceSchemaMigrationRunnerService } from 'src/engine/workspace-mana
import { WorkspaceSchemaObjectActionRunnerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/workspace-schema-migration-runner/workspace-schema-object-action-runner.service'; import { WorkspaceSchemaObjectActionRunnerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/workspace-schema-migration-runner/workspace-schema-object-action-runner.service';
@Module({ @Module({
imports: [FeatureFlagModule, TypeORMModule], imports: [
FeatureFlagModule,
TypeORMModule,
DataSourceModule,
WorkspaceMetadataVersionModule,
WorkspacePermissionsCacheModule,
],
providers: [ providers: [
WorkspaceMetadataObjectActionRunnerService, WorkspaceMetadataObjectActionRunnerService,
WorkspaceMetadataIndexActionRunnerService, WorkspaceMetadataIndexActionRunnerService,

View File

@ -3,6 +3,8 @@ import { InjectDataSource } from '@nestjs/typeorm';
import { DataSource } from 'typeorm'; import { DataSource } from 'typeorm';
import { WorkspaceMetadataVersionService } from 'src/engine/metadata-modules/workspace-metadata-version/services/workspace-metadata-version.service';
import { WorkspacePermissionsCacheService } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service';
import { WorkspaceMigrationV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-v2'; import { WorkspaceMigrationV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-v2';
import { WorkspaceMetadataMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/workspace-metadata-migration-runner/workspace-metadata-migration-runner-service'; import { WorkspaceMetadataMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/workspace-metadata-migration-runner/workspace-metadata-migration-runner-service';
import { WorkspaceSchemaMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/workspace-schema-migration-runner/workspace-schema-migration-runner.service'; import { WorkspaceSchemaMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/workspace-schema-migration-runner/workspace-schema-migration-runner.service';
@ -12,6 +14,8 @@ export class WorkspaceMigrationRunnerV2Service {
constructor( constructor(
private readonly workspaceMetadataMigrationRunner: WorkspaceMetadataMigrationRunnerService, private readonly workspaceMetadataMigrationRunner: WorkspaceMetadataMigrationRunnerService,
private readonly workspaceSchemaMigrationRunner: WorkspaceSchemaMigrationRunnerService, private readonly workspaceSchemaMigrationRunner: WorkspaceSchemaMigrationRunnerService,
private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService,
private readonly workspacePermissionsCacheService: WorkspacePermissionsCacheService,
@InjectDataSource('core') @InjectDataSource('core')
private readonly coreDataSource: DataSource, private readonly coreDataSource: DataSource,
) {} ) {}
@ -34,6 +38,17 @@ export class WorkspaceMigrationRunnerV2Service {
]); ]);
await queryRunner.commitTransaction(); await queryRunner.commitTransaction();
const { workspaceId } = workspaceMigration;
await this.workspaceMetadataVersionService.incrementMetadataVersion(
workspaceId,
);
await this.workspacePermissionsCacheService.recomputeRolesPermissionsCache(
{
workspaceId,
},
);
} catch (error) { } catch (error) {
if (queryRunner.isTransactionActive) { if (queryRunner.isTransactionActive) {
await queryRunner.rollbackTransaction(); await queryRunner.rollbackTransaction();