Feat workspace migration maintains flat object metadata maps (#13620)

# Introduction
The workspace migration runner v2 now computes the next
flatObjectMetadataMaps post current ws migration action has been run
So the following one have an up to date informations

## Still TODO
~~Remove any contextual information from workspace migration v2 and
consume the optimistic cache to retrieve them~~

## Next steps
- Create flat-object-metadata-maps testing toolbox and flat-object/field
testing toolbox
- Implement strong coverage on every created utils/transpiler and
applyWorkspaceMigrationAction method
This commit is contained in:
Paul Rastoin
2025-08-06 13:10:14 +00:00
committed by GitHub
parent e1d169e51e
commit ca3383cd86
38 changed files with 897 additions and 592 deletions
@@ -10,7 +10,7 @@ import { ToMerge } from 'src/engine/workspace-manager/workspace-migration-v2/wor
export const mergeTwoFlatFieldMetadatas = ({
destFlatFieldMetadatas,
toMergeFlatFieldMetadatas,
}: ToMerge<FlatFieldMetadata[], 'field'>): FlatFieldMetadata[] => {
}: ToMerge<FlatFieldMetadata[], 'FlatFieldMetadatas'>): FlatFieldMetadata[] => {
const initialRecordAccumulator = fromArrayToUniqueKeyRecord({
array: destFlatFieldMetadatas,
uniqueKey: 'uniqueIdentifier',
@@ -8,9 +8,11 @@ type IndexMetadataRelationProperties = ExtractRecordTypeOrmRelationProperties<
MetadataEntitiesRelationTarget
>;
// TODO prastoin refactor FlatIndexMetadata to not be a Partial extension of IndexMetadataEntity
export type FlatIndexMetadata = Partial<
Omit<IndexMetadataEntity, IndexMetadataRelationProperties>
> & {
id: string;
flatIndexFieldMetadatas: FlatIndexFieldMetadata[];
uniqueIdentifier: string;
};
@@ -0,0 +1,15 @@
import {
appendCommonExceptionCode,
CustomException,
} from 'src/utils/custom-exception';
export class FlatObjectMetadataMapsException extends CustomException<
keyof typeof FlatObjectMetadataMapsExceptionCode
> {}
export const FlatObjectMetadataMapsExceptionCode = appendCommonExceptionCode({
FIELD_METADATA_NOT_FOUND: 'FIELD_METADATA_NOT_FOUND',
OBJECT_METADATA_NOT_FOUND: 'OBJECT_METADATA_NOT_FOUND',
FIELD_METADATA_ALREADY_EXISTS: 'FIELD_METADATA_ALREADY_EXISTS',
OBJECT_METADATA_ALREADY_EXISTS: 'OBJECT_METADATA_ALREADY_EXISTS',
} as const);
@@ -0,0 +1,39 @@
import { isDefined } from 'twenty-shared/utils';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import {
FlatObjectMetadataMapsException,
FlatObjectMetadataMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-object-metadata-maps/flat-object-metadata-maps.exception';
import { FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
import { addFlatFieldMetadataToFlatObjectMetadataWithFlatFieldMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/add-flat-field-metadata-to-flat-object-metadata-with-flat-field-maps-or-throw.util';
export const addFlatFieldMetadataInFlatObjectMetadataMapsOrThrow = ({
flatFieldMetadata,
flatObjectMetadataMaps,
}: {
flatFieldMetadata: FlatFieldMetadata;
flatObjectMetadataMaps: FlatObjectMetadataMaps;
}): FlatObjectMetadataMaps | undefined => {
const flatObjectMetadataWithFlatFieldMaps =
flatObjectMetadataMaps.byId[flatFieldMetadata.objectMetadataId];
if (!isDefined(flatObjectMetadataWithFlatFieldMaps)) {
throw new FlatObjectMetadataMapsException(
'addFlatFieldMetadataInFlatObjectMetadataMapsOrThrow field parent object metadata not found',
FlatObjectMetadataMapsExceptionCode.OBJECT_METADATA_NOT_FOUND,
);
}
return {
byId: {
...flatObjectMetadataMaps.byId,
[flatFieldMetadata.objectMetadataId]:
addFlatFieldMetadataToFlatObjectMetadataWithFlatFieldMapsOrThrow({
flatFieldMetadata,
flatObjectMetadataWithFlatFieldMaps,
}),
},
idByNameSingular: flatObjectMetadataMaps.idByNameSingular,
};
};
@@ -0,0 +1,70 @@
import { FieldMetadataType } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { isFlatFieldMetadataEntityOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
import {
FlatObjectMetadataMapsException,
FlatObjectMetadataMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-object-metadata-maps/flat-object-metadata-maps.exception';
import {
FlatFieldMetadataMaps,
FlatObjectMetadataWithFlatFieldMaps,
} from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-with-flat-field-metadata-maps.type';
export const addFlatFieldMetadataToFlatObjectMetadataWithFlatFieldMapsOrThrow =
({
flatFieldMetadata,
flatObjectMetadataWithFlatFieldMaps,
}: {
flatFieldMetadata: FlatFieldMetadata;
flatObjectMetadataWithFlatFieldMaps: FlatObjectMetadataWithFlatFieldMaps;
}): FlatObjectMetadataWithFlatFieldMaps => {
if (
isDefined(
flatObjectMetadataWithFlatFieldMaps.fieldsById[flatFieldMetadata.id],
)
) {
throw new FlatObjectMetadataMapsException(
'addFlatFieldMetadataToFlatObjectMetadataWithFlatFieldMaps added flatFieldMetadata already exists',
FlatObjectMetadataMapsExceptionCode.FIELD_METADATA_ALREADY_EXISTS,
);
}
let updatedFieldIdByJoinColumnName:
| FlatFieldMetadataMaps['fieldIdByJoinColumnName']
| undefined = undefined;
if (
isFlatFieldMetadataEntityOfType(
flatFieldMetadata,
FieldMetadataType.RELATION,
) ||
isFlatFieldMetadataEntityOfType(
flatFieldMetadata,
FieldMetadataType.MORPH_RELATION,
)
) {
if (isDefined(flatFieldMetadata.settings?.joinColumnName)) {
updatedFieldIdByJoinColumnName = {
[flatFieldMetadata.settings.joinColumnName]: flatFieldMetadata.id,
};
}
}
return {
...flatObjectMetadataWithFlatFieldMaps,
fieldIdByJoinColumnName: {
...flatObjectMetadataWithFlatFieldMaps.fieldIdByJoinColumnName,
...updatedFieldIdByJoinColumnName,
},
fieldIdByName: {
...flatObjectMetadataWithFlatFieldMaps.fieldIdByName,
[flatFieldMetadata.name]: flatFieldMetadata.id,
},
fieldsById: {
...flatObjectMetadataWithFlatFieldMaps.fieldsById,
[flatFieldMetadata.id]: flatFieldMetadata,
},
};
};
@@ -0,0 +1,39 @@
import { isDefined } from 'twenty-shared/utils';
import {
FlatObjectMetadataMapsException,
FlatObjectMetadataMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-object-metadata-maps/flat-object-metadata-maps.exception';
import { FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { fromFlatObjectMetadataToFlatObjectMetadataWithFlatFieldMaps } from 'src/engine/metadata-modules/flat-object-metadata/utils/from-flat-object-metadata-to-flat-object-metadata-with-flat-field-maps.util';
type AddFlatObjectMetadataToFlatObjectMetadataMapsOrThrowArgs = {
flatObjectMetadata: FlatObjectMetadata;
flatObjectMetadataMaps: FlatObjectMetadataMaps;
};
export const addFlatObjectMetadataToFlatObjectMetadataMapsOrThrow = ({
flatObjectMetadata,
flatObjectMetadataMaps,
}: AddFlatObjectMetadataToFlatObjectMetadataMapsOrThrowArgs): FlatObjectMetadataMaps => {
if (isDefined(flatObjectMetadataMaps.byId[flatObjectMetadata.id])) {
throw new FlatObjectMetadataMapsException(
'addFlatObjectMetadataToFlatObjectMetadataMapsOrThrow: flat object metadata to add already exists',
FlatObjectMetadataMapsExceptionCode.OBJECT_METADATA_ALREADY_EXISTS,
);
}
return {
byId: {
...flatObjectMetadataMaps.byId,
[flatObjectMetadata.id]:
fromFlatObjectMetadataToFlatObjectMetadataWithFlatFieldMaps(
flatObjectMetadata,
),
},
idByNameSingular: {
...flatObjectMetadataMaps.idByNameSingular,
[flatObjectMetadata.nameSingular]: flatObjectMetadata.id,
},
};
};
@@ -0,0 +1,41 @@
import { isDefined } from 'twenty-shared/utils';
import {
FlatObjectMetadataMapsException,
FlatObjectMetadataMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-object-metadata-maps/flat-object-metadata-maps.exception';
import { FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
import { deleteFieldFromFlatObjectMetadataWithFlatFieldMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/delete-field-from-flat-object-metadata-with-flat-field-maps-or-throw.util';
type DeleteFieldFromFlatObjectMetadataMapsArgs = {
fieldMetadataId: string;
objectMetadataId: string;
flatObjectMetadataMaps: FlatObjectMetadataMaps;
};
export const deleteFieldFromFlatObjectMetadataMapsOrThrow = ({
flatObjectMetadataMaps,
fieldMetadataId,
objectMetadataId,
}: DeleteFieldFromFlatObjectMetadataMapsArgs): FlatObjectMetadataMaps => {
const flatObjectMetadataWithFlatFieldMaps =
flatObjectMetadataMaps.byId[objectMetadataId];
if (!isDefined(flatObjectMetadataWithFlatFieldMaps)) {
throw new FlatObjectMetadataMapsException(
'deleteFieldFromFlatObjectMetadataMapsOrThrow: flat field metadata to delete parent flat object metadata not found',
FlatObjectMetadataMapsExceptionCode.OBJECT_METADATA_NOT_FOUND,
);
}
return {
byId: {
...flatObjectMetadataMaps.byId,
[objectMetadataId]:
deleteFieldFromFlatObjectMetadataWithFlatFieldMapsOrThrow({
fieldMetadataId,
flatObjectMetadataWithFlatFieldMaps,
}),
},
idByNameSingular: flatObjectMetadataMaps.idByNameSingular,
};
};
@@ -0,0 +1,50 @@
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import {
FlatObjectMetadataMapsException,
FlatObjectMetadataMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-object-metadata-maps/flat-object-metadata-maps.exception';
import { FlatObjectMetadataWithFlatFieldMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-with-flat-field-metadata-maps.type';
type DeleteFieldFromFlatObjectMetadataMapsArgs = {
fieldMetadataId: string;
flatObjectMetadataWithFlatFieldMaps: FlatObjectMetadataWithFlatFieldMaps;
};
export const deleteFieldFromFlatObjectMetadataWithFlatFieldMapsOrThrow = ({
flatObjectMetadataWithFlatFieldMaps,
fieldMetadataId: fieldMetadataIdToRemove,
}: DeleteFieldFromFlatObjectMetadataMapsArgs): FlatObjectMetadataWithFlatFieldMaps => {
const flatFieldMetadataToRemove =
flatObjectMetadataWithFlatFieldMaps.fieldsById[fieldMetadataIdToRemove];
if (!isDefined(flatFieldMetadataToRemove)) {
throw new FlatObjectMetadataMapsException(
'deleteFieldFromFlatObjectMetadataWithFlatFieldMapsOrThrow: field to delete not found',
FlatObjectMetadataMapsExceptionCode.FIELD_METADATA_NOT_FOUND,
);
}
const {
fieldIdByName,
fieldsById,
flatFieldMetadatas,
fieldIdByJoinColumnName,
} = flatObjectMetadataWithFlatFieldMaps;
const updatedFieldIdByJoinColumnName = Object.entries(
fieldIdByJoinColumnName,
).filter(([_joinColumnName, fieldId]) => fieldId !== fieldMetadataIdToRemove);
return {
...flatObjectMetadataWithFlatFieldMaps,
fieldIdByJoinColumnName: Object.fromEntries(updatedFieldIdByJoinColumnName),
fieldIdByName: removePropertiesFromRecord(fieldIdByName, [
flatFieldMetadataToRemove.name,
]),
fieldsById: removePropertiesFromRecord(fieldsById, [
fieldMetadataIdToRemove,
]),
flatFieldMetadatas: flatFieldMetadatas.filter(
(flatFieldMetadata) => flatFieldMetadata.id !== fieldMetadataIdToRemove,
),
};
};
@@ -0,0 +1,34 @@
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import {
FlatObjectMetadataMapsException,
FlatObjectMetadataMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-object-metadata-maps/flat-object-metadata-maps.exception';
import { FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
type DeleteObjectFromFlatObjectMetadataMapsOrThrowArgs = {
objectMetadataId: string;
flatObjectMetadataMaps: FlatObjectMetadataMaps;
};
export const deleteObjectFromFlatObjectMetadataMapsOrThrow = ({
flatObjectMetadataMaps,
objectMetadataId,
}: DeleteObjectFromFlatObjectMetadataMapsOrThrowArgs): FlatObjectMetadataMaps => {
if (!isDefined(flatObjectMetadataMaps.byId[objectMetadataId])) {
throw new FlatObjectMetadataMapsException(
'deleteObjectFromFlatObjectMetadataMapsOrThrow: object to delete not found',
FlatObjectMetadataMapsExceptionCode.OBJECT_METADATA_NOT_FOUND,
);
}
const updatedIdByNameSingularEntries = Object.entries(
flatObjectMetadataMaps.idByNameSingular,
).filter(([_nameSingular, id]) => id !== objectMetadataId);
return {
byId: removePropertiesFromRecord(flatObjectMetadataMaps.byId, [
objectMetadataId,
]),
idByNameSingular: Object.fromEntries(updatedIdByNameSingularEntries),
};
};
@@ -0,0 +1,30 @@
import { isDefined } from 'twenty-shared/utils';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
export const findFlatFieldMetadataInFlatObjectMetadataMaps = ({
flatObjectMetadataMaps,
fieldMetadataId,
objectMetadataId,
}: {
objectMetadataId: string;
fieldMetadataId: string;
flatObjectMetadataMaps: FlatObjectMetadataMaps;
}): FlatFieldMetadata | undefined => {
const flatObjectMetadataWithFlatFieldMaps =
flatObjectMetadataMaps.byId[objectMetadataId];
if (!isDefined(flatObjectMetadataWithFlatFieldMaps)) {
return undefined;
}
const flatFieldMetadata =
flatObjectMetadataWithFlatFieldMaps.fieldsById[fieldMetadataId];
if (!isDefined(flatFieldMetadata)) {
return undefined;
}
return flatFieldMetadata;
};
@@ -0,0 +1,24 @@
import { isDefined } from 'twenty-shared/utils';
import { FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { fromFlatObjectMetadataWithFlatFieldMapsToFlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/utils/from-flat-object-metadata-with-flat-field-maps-to-flat-object-metadatas.util';
export const findFlatObjectdMetadataInFlatObjectMetadataMaps = ({
flatObjectMetadataMaps,
objectMetadataId,
}: {
objectMetadataId: string;
flatObjectMetadataMaps: FlatObjectMetadataMaps;
}): FlatObjectMetadata | undefined => {
const flatObjectMetadataWithFlatFieldMaps =
flatObjectMetadataMaps.byId[objectMetadataId];
if (!isDefined(flatObjectMetadataWithFlatFieldMaps)) {
return undefined;
}
return fromFlatObjectMetadataWithFlatFieldMapsToFlatObjectMetadata(
flatObjectMetadataWithFlatFieldMaps,
);
};
@@ -0,0 +1,25 @@
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
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';
export const replaceFlatFieldMetadataInFlatObjectMetadataMapsOrThrow = ({
flatFieldMetadata,
flatObjectMetadataMaps,
}: {
flatFieldMetadata: FlatFieldMetadata;
flatObjectMetadataMaps: FlatObjectMetadataMaps;
}): FlatObjectMetadataMaps | undefined => {
const flatObjectMetadataMapsWithoutFlatFieldMetadataToReplace =
deleteFieldFromFlatObjectMetadataMapsOrThrow({
fieldMetadataId: flatFieldMetadata.id,
flatObjectMetadataMaps,
objectMetadataId: flatFieldMetadata.objectMetadataId,
});
return addFlatFieldMetadataInFlatObjectMetadataMapsOrThrow({
flatFieldMetadata,
flatObjectMetadataMaps:
flatObjectMetadataMapsWithoutFlatFieldMetadataToReplace,
});
};
@@ -0,0 +1,24 @@
import { FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
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 { deleteObjectFromFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/delete-object-from-flat-object-metadata-maps-or-throw.util';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
export const replaceFlatObjectMetadataInFlatObjectMetadataMaps = ({
flatObjectMetadata,
flatObjectMetadataMaps,
}: {
flatObjectMetadata: FlatObjectMetadata;
flatObjectMetadataMaps: FlatObjectMetadataMaps;
}) => {
const flatObjectMetadataMapsWithoutFlatObjectMetadataToReplace =
deleteObjectFromFlatObjectMetadataMapsOrThrow({
flatObjectMetadataMaps,
objectMetadataId: flatObjectMetadata.id,
});
return addFlatObjectMetadataToFlatObjectMetadataMapsOrThrow({
flatObjectMetadata,
flatObjectMetadataMaps:
flatObjectMetadataMapsWithoutFlatObjectMetadataToReplace,
});
};
@@ -1,7 +1,7 @@
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
export const removeFlatFieldMetadataFromFlatObjectMetadatas = ({
export const deleteFlatFieldMetadataFromFlatObjectMetadatas = ({
flatFieldMetadata: flatFieldMetadataToRemove,
flatObjectMetadatas,
}: {
@@ -0,0 +1,24 @@
import { FlatObjectMetadataWithFlatFieldMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-with-flat-field-metadata-maps.type';
import { addFlatFieldMetadataToFlatObjectMetadataWithFlatFieldMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/add-flat-field-metadata-to-flat-object-metadata-with-flat-field-maps-or-throw.util';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
export const fromFlatObjectMetadataToFlatObjectMetadataWithFlatFieldMaps = (
flatObjectMetadata: FlatObjectMetadata,
): FlatObjectMetadataWithFlatFieldMaps => {
const emptyFlatObjectMetadataWithFlatFieldMaps: FlatObjectMetadataWithFlatFieldMaps =
{
...flatObjectMetadata,
fieldIdByJoinColumnName: {},
fieldIdByName: {},
fieldsById: {},
};
return flatObjectMetadata.flatFieldMetadatas.reduce(
(flatObjectMetadataWithFlatFieldMaps, flatFieldMetadata) =>
addFlatFieldMetadataToFlatObjectMetadataWithFlatFieldMapsOrThrow({
flatFieldMetadata,
flatObjectMetadataWithFlatFieldMaps,
}),
emptyFlatObjectMetadataWithFlatFieldMaps,
);
};
@@ -11,7 +11,10 @@ import { ToMerge } from 'src/engine/workspace-manager/workspace-migration-v2/wor
export const mergeTwoFlatObjectMetadatas = ({
destFlatObjectMetadatas,
toMergeFlatObjectMetadatas,
}: ToMerge<FlatObjectMetadata[], 'object'>): FlatObjectMetadata[] => {
}: ToMerge<
FlatObjectMetadata[],
'FlatObjectMetadatas'
>): FlatObjectMetadata[] => {
const initialObjectAccumulator = fromArrayToUniqueKeyRecord({
array: destFlatObjectMetadatas,
uniqueKey: 'uniqueIdentifier',
@@ -5,56 +5,8 @@ exports[`Workspace migration builder field actions test suite It should NOT buil
exports[`Workspace migration builder field actions test suite It should build a delete_field action 1`] = `
[
{
"flatFieldMetadata": {
"defaultValue": null,
"description": "default flat field metadata description",
"flatRelationTargetFieldMetadata": null,
"flatRelationTargetObjectMetadata": null,
"icon": "icon",
"id": Any<String>,
"isActive": true,
"isCustom": true,
"isLabelSyncedWithName": false,
"isNullable": true,
"isSystem": false,
"isUnique": false,
"label": "flat field metadata label",
"name": "flatFieldMetadataName",
"objectMetadataId": Any<String>,
"options": null,
"relationTargetFieldMetadataId": null,
"relationTargetObjectMetadataId": null,
"settings": null,
"standardId": null,
"standardOverrides": null,
"type": "TEXT",
"uniqueIdentifier": "field-metadata-unique-identifier-1",
"workspaceId": Any<String>,
},
"flatObjectMetadataWithoutFields": {
"description": "default flat object metadata description",
"icon": "icon",
"id": Any<String>,
"imageIdentifierFieldMetadataId": Any<String>,
"isActive": true,
"isAuditLogged": true,
"isCustom": true,
"isLabelSyncedWithName": false,
"isRemote": false,
"isSearchable": true,
"isSystem": false,
"labelIdentifierFieldMetadataId": Any<String>,
"labelPlural": "default flat object metadata label plural",
"labelSingular": "default flat object metadata label singular",
"namePlural": "defaultflatObjectMetadataNamePlural",
"nameSingular": "defaultflatObjectMetadataNameSingular",
"shortcut": "shortcut",
"standardId": null,
"standardOverrides": null,
"targetTableName": "",
"uniqueIdentifier": "object-metadata-unique-identifier-1",
"workspaceId": Any<String>,
},
"fieldMetadataId": Any<String>,
"objectMetadataId": Any<String>,
"type": "delete_field",
},
]
@@ -89,30 +41,6 @@ exports[`Workspace migration builder field actions test suite It should build an
"uniqueIdentifier": "field-metadata-unique-identifier-1",
"workspaceId": Any<String>,
},
"flatObjectMetadataWithoutFields": {
"description": "default flat object metadata description",
"icon": "icon",
"id": Any<String>,
"imageIdentifierFieldMetadataId": Any<String>,
"isActive": true,
"isAuditLogged": true,
"isCustom": true,
"isLabelSyncedWithName": true,
"isRemote": false,
"isSearchable": true,
"isSystem": false,
"labelIdentifierFieldMetadataId": Any<String>,
"labelPlural": "default flat object metadata label plural",
"labelSingular": "default flat object metadata label singular",
"namePlural": "defaultflatObjectMetadataNamePlural",
"nameSingular": "defaultflatObjectMetadataNameSingular",
"shortcut": "shortcut",
"standardId": null,
"standardOverrides": null,
"targetTableName": "",
"uniqueIdentifier": "object-metadata-unique-identifier-1",
"workspaceId": Any<String>,
},
"type": "create_field",
},
]
@@ -197,30 +125,6 @@ exports[`Workspace migration builder field actions test suite It should build an
"uniqueIdentifier": "field-metadata-unique-identifier-1",
"workspaceId": Any<String>,
},
"flatObjectMetadataWithoutFields": {
"description": "default flat object metadata description",
"icon": "icon",
"id": Any<String>,
"imageIdentifierFieldMetadataId": Any<String>,
"isActive": true,
"isAuditLogged": true,
"isCustom": true,
"isLabelSyncedWithName": true,
"isRemote": false,
"isSearchable": true,
"isSystem": false,
"labelIdentifierFieldMetadataId": Any<String>,
"labelPlural": "default flat object metadata label plural",
"labelSingular": "default flat object metadata label singular",
"namePlural": "defaultflatObjectMetadataNamePlural",
"nameSingular": "defaultflatObjectMetadataNameSingular",
"shortcut": "shortcut",
"standardId": null,
"standardOverrides": null,
"targetTableName": "",
"uniqueIdentifier": "object-metadata-unique-identifier-1",
"workspaceId": Any<String>,
},
"type": "create_field",
},
]
@@ -229,56 +133,8 @@ exports[`Workspace migration builder field actions test suite It should build an
exports[`Workspace migration builder field actions test suite It should build an update_field action 1`] = `
[
{
"flatFieldMetadata": {
"defaultValue": null,
"description": "new description",
"flatRelationTargetFieldMetadata": null,
"flatRelationTargetObjectMetadata": null,
"icon": "new icon",
"id": Any<String>,
"isActive": false,
"isCustom": true,
"isLabelSyncedWithName": false,
"isNullable": true,
"isSystem": false,
"isUnique": false,
"label": "flat field metadata label",
"name": "new name",
"objectMetadataId": Any<String>,
"options": null,
"relationTargetFieldMetadataId": null,
"relationTargetObjectMetadataId": null,
"settings": null,
"standardId": null,
"standardOverrides": null,
"type": "TEXT",
"uniqueIdentifier": "field-metadata-unique-identifier-1",
"workspaceId": Any<String>,
},
"flatObjectMetadataWithoutFields": {
"description": "default flat object metadata description",
"icon": "icon",
"id": Any<String>,
"imageIdentifierFieldMetadataId": Any<String>,
"isActive": true,
"isAuditLogged": true,
"isCustom": true,
"isLabelSyncedWithName": false,
"isRemote": false,
"isSearchable": true,
"isSystem": false,
"labelIdentifierFieldMetadataId": Any<String>,
"labelPlural": "default flat object metadata label plural",
"labelSingular": "default flat object metadata label singular",
"namePlural": "defaultflatObjectMetadataNamePlural",
"nameSingular": "defaultflatObjectMetadataNameSingular",
"shortcut": "shortcut",
"standardId": null,
"standardOverrides": null,
"targetTableName": "",
"uniqueIdentifier": "object-metadata-unique-identifier-1",
"workspaceId": Any<String>,
},
"fieldMetadataId": Any<String>,
"objectMetadataId": Any<String>,
"type": "update_field",
"updates": [
{
@@ -310,56 +166,8 @@ exports[`Workspace migration builder field actions test suite It should build an
exports[`Workspace migration builder field actions test suite It should build an update_field action for a RELATION field 1`] = `
[
{
"flatFieldMetadata": {
"defaultValue": null,
"description": "new description",
"flatRelationTargetFieldMetadata": null,
"flatRelationTargetObjectMetadata": null,
"icon": "icon",
"id": Any<String>,
"isActive": false,
"isCustom": true,
"isLabelSyncedWithName": false,
"isNullable": true,
"isSystem": false,
"isUnique": false,
"label": "new label",
"name": "flatFieldMetadataName",
"objectMetadataId": Any<String>,
"options": null,
"relationTargetFieldMetadataId": Any<String>,
"relationTargetObjectMetadataId": Any<String>,
"settings": null,
"standardId": null,
"standardOverrides": null,
"type": "RELATION",
"uniqueIdentifier": "field-metadata-unique-identifier-1",
"workspaceId": Any<String>,
},
"flatObjectMetadataWithoutFields": {
"description": "default flat object metadata description",
"icon": "icon",
"id": Any<String>,
"imageIdentifierFieldMetadataId": Any<String>,
"isActive": true,
"isAuditLogged": true,
"isCustom": true,
"isLabelSyncedWithName": true,
"isRemote": false,
"isSearchable": true,
"isSystem": false,
"labelIdentifierFieldMetadataId": Any<String>,
"labelPlural": "default flat object metadata label plural",
"labelSingular": "default flat object metadata label singular",
"namePlural": "defaultflatObjectMetadataNamePlural",
"nameSingular": "defaultflatObjectMetadataNameSingular",
"shortcut": "shortcut",
"standardId": null,
"standardOverrides": null,
"targetTableName": "",
"uniqueIdentifier": "object-metadata-unique-identifier-1",
"workspaceId": Any<String>,
},
"fieldMetadataId": Any<String>,
"objectMetadataId": Any<String>,
"type": "update_field",
"updates": [
{
@@ -388,20 +196,7 @@ exports[`Workspace migration builder field actions test suite It should not infe
exports[`Workspace migration builder index actions test suite It should build a delete_index action 1`] = `
[
{
"flatIndexMetadata": {
"createdAt": Any<ClockDate>,
"flatIndexFieldMetadatas": [],
"id": Any<String>,
"indexType": "BTREE",
"indexWhereClause": undefined,
"isCustom": false,
"isUnique": false,
"name": "defaultFlatIndexMetadataName",
"objectMetadataId": Any<String>,
"uniqueIdentifier": "field-metadata-unique-identifier-1",
"updatedAt": Any<ClockDate>,
"workspaceId": Any<String>,
},
"flatIndexMetadataId": Any<String>,
"type": "delete_index",
},
]
@@ -432,20 +227,7 @@ exports[`Workspace migration builder index actions test suite It should build an
exports[`Workspace migration builder index actions test suite It should build an delete_index and a create_index action ( the way we handle update ) 1`] = `
[
{
"flatIndexMetadata": {
"createdAt": Any<ClockDate>,
"flatIndexFieldMetadatas": [],
"id": Any<String>,
"indexType": "BTREE",
"indexWhereClause": undefined,
"isCustom": false,
"isUnique": false,
"name": "defaultFlatIndexMetadataName",
"objectMetadataId": Any<String>,
"uniqueIdentifier": "field-metadata-unique-identifier-1",
"updatedAt": Any<ClockDate>,
"workspaceId": Any<String>,
},
"flatIndexMetadataId": Any<String>,
"type": "delete_index",
},
{
@@ -534,30 +316,6 @@ exports[`Workspace migration builder object actions test suite It should build a
"uniqueIdentifier": "field_0",
"workspaceId": Any<String>,
},
"flatObjectMetadataWithoutFields": {
"description": "default flat object metadata description",
"icon": "icon",
"id": Any<String>,
"imageIdentifierFieldMetadataId": Any<String>,
"isActive": true,
"isAuditLogged": true,
"isCustom": true,
"isLabelSyncedWithName": true,
"isRemote": false,
"isSearchable": true,
"isSystem": false,
"labelIdentifierFieldMetadataId": Any<String>,
"labelPlural": "default flat object metadata label plural",
"labelSingular": "default flat object metadata label singular",
"namePlural": "totos",
"nameSingular": "toto",
"shortcut": "shortcut",
"standardId": null,
"standardOverrides": null,
"targetTableName": "",
"uniqueIdentifier": "pomme",
"workspaceId": Any<String>,
},
"type": "create_field",
},
{
@@ -587,30 +345,6 @@ exports[`Workspace migration builder object actions test suite It should build a
"uniqueIdentifier": "field_1",
"workspaceId": Any<String>,
},
"flatObjectMetadataWithoutFields": {
"description": "default flat object metadata description",
"icon": "icon",
"id": Any<String>,
"imageIdentifierFieldMetadataId": Any<String>,
"isActive": true,
"isAuditLogged": true,
"isCustom": true,
"isLabelSyncedWithName": true,
"isRemote": false,
"isSearchable": true,
"isSystem": false,
"labelIdentifierFieldMetadataId": Any<String>,
"labelPlural": "default flat object metadata label plural",
"labelSingular": "default flat object metadata label singular",
"namePlural": "totos",
"nameSingular": "toto",
"shortcut": "shortcut",
"standardId": null,
"standardOverrides": null,
"targetTableName": "",
"uniqueIdentifier": "pomme",
"workspaceId": Any<String>,
},
"type": "create_field",
},
{
@@ -640,30 +374,6 @@ exports[`Workspace migration builder object actions test suite It should build a
"uniqueIdentifier": "field_2",
"workspaceId": Any<String>,
},
"flatObjectMetadataWithoutFields": {
"description": "default flat object metadata description",
"icon": "icon",
"id": Any<String>,
"imageIdentifierFieldMetadataId": Any<String>,
"isActive": true,
"isAuditLogged": true,
"isCustom": true,
"isLabelSyncedWithName": true,
"isRemote": false,
"isSearchable": true,
"isSystem": false,
"labelIdentifierFieldMetadataId": Any<String>,
"labelPlural": "default flat object metadata label plural",
"labelSingular": "default flat object metadata label singular",
"namePlural": "totos",
"nameSingular": "toto",
"shortcut": "shortcut",
"standardId": null,
"standardOverrides": null,
"targetTableName": "",
"uniqueIdentifier": "pomme",
"workspaceId": Any<String>,
},
"type": "create_field",
},
{
@@ -693,30 +403,6 @@ exports[`Workspace migration builder object actions test suite It should build a
"uniqueIdentifier": "field_3",
"workspaceId": Any<String>,
},
"flatObjectMetadataWithoutFields": {
"description": "default flat object metadata description",
"icon": "icon",
"id": Any<String>,
"imageIdentifierFieldMetadataId": Any<String>,
"isActive": true,
"isAuditLogged": true,
"isCustom": true,
"isLabelSyncedWithName": true,
"isRemote": false,
"isSearchable": true,
"isSystem": false,
"labelIdentifierFieldMetadataId": Any<String>,
"labelPlural": "default flat object metadata label plural",
"labelSingular": "default flat object metadata label singular",
"namePlural": "totos",
"nameSingular": "toto",
"shortcut": "shortcut",
"standardId": null,
"standardOverrides": null,
"targetTableName": "",
"uniqueIdentifier": "pomme",
"workspaceId": Any<String>,
},
"type": "create_field",
},
{
@@ -746,30 +432,6 @@ exports[`Workspace migration builder object actions test suite It should build a
"uniqueIdentifier": "field_4",
"workspaceId": Any<String>,
},
"flatObjectMetadataWithoutFields": {
"description": "default flat object metadata description",
"icon": "icon",
"id": Any<String>,
"imageIdentifierFieldMetadataId": Any<String>,
"isActive": true,
"isAuditLogged": true,
"isCustom": true,
"isLabelSyncedWithName": true,
"isRemote": false,
"isSearchable": true,
"isSystem": false,
"labelIdentifierFieldMetadataId": Any<String>,
"labelPlural": "default flat object metadata label plural",
"labelSingular": "default flat object metadata label singular",
"namePlural": "totos",
"nameSingular": "toto",
"shortcut": "shortcut",
"standardId": null,
"standardOverrides": null,
"targetTableName": "",
"uniqueIdentifier": "pomme",
"workspaceId": Any<String>,
},
"type": "create_field",
},
],
@@ -822,30 +484,7 @@ exports[`Workspace migration builder object actions test suite It should build a
exports[`Workspace migration builder object actions test suite It should build a delete_object action 1`] = `
[
{
"flatObjectMetadataWithoutFields": {
"description": "default flat object metadata description",
"icon": "icon",
"id": Any<String>,
"imageIdentifierFieldMetadataId": Any<String>,
"isActive": true,
"isAuditLogged": true,
"isCustom": true,
"isLabelSyncedWithName": true,
"isRemote": false,
"isSearchable": true,
"isSystem": false,
"labelIdentifierFieldMetadataId": Any<String>,
"labelPlural": "default flat object metadata label plural",
"labelSingular": "default flat object metadata label singular",
"namePlural": "totos",
"nameSingular": "toto",
"shortcut": "shortcut",
"standardId": null,
"standardOverrides": null,
"targetTableName": "",
"uniqueIdentifier": "pomme",
"workspaceId": Any<String>,
},
"objectMetadataId": Any<String>,
"type": "delete_object",
},
]
@@ -854,30 +493,7 @@ exports[`Workspace migration builder object actions test suite It should build a
exports[`Workspace migration builder object actions test suite It should build an update_object action with all object updated fields 1`] = `
[
{
"flatObjectMetadataWithoutFields": {
"description": "default flat object metadata description",
"icon": "icon",
"id": Any<String>,
"imageIdentifierFieldMetadataId": Any<String>,
"isActive": true,
"isAuditLogged": true,
"isCustom": true,
"isLabelSyncedWithName": false,
"isRemote": false,
"isSearchable": true,
"isSystem": false,
"labelIdentifierFieldMetadataId": Any<String>,
"labelPlural": "default flat object metadata label plural",
"labelSingular": "default flat object metadata label singular",
"namePlural": "prastoins",
"nameSingular": "prastouin",
"shortcut": "shortcut",
"standardId": null,
"standardOverrides": null,
"targetTableName": "",
"uniqueIdentifier": "pomme",
"workspaceId": Any<String>,
},
"objectMetadataId": Any<String>,
"type": "update_object",
"updates": [
{
@@ -1,3 +1,3 @@
export type ToMerge<T, K extends 'object' | 'field'> = {
[P in ['toMerge', 'dest'][number] as `${P}Flat${Capitalize<K>}Metadatas`]: T;
export type ToMerge<T, K extends string> = {
[P in 'toMerge' | 'dest' as `${P}${Capitalize<K>}`]: T;
};
@@ -3,19 +3,17 @@ import { FromTo } from 'twenty-shared/types';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatFieldMetadataPropertiesToCompare } from 'src/engine/metadata-modules/flat-field-metadata/utils/compare-two-flat-field-metadata.util';
import { FlatObjectMetadataWithoutFields } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
export type CreateFieldAction = {
type: 'create_field';
flatFieldMetadata: FlatFieldMetadata;
flatObjectMetadataWithoutFields: FlatObjectMetadataWithoutFields;
};
export type UpdateFieldAction = {
type: 'update_field';
workspaceId: string;
flatFieldMetadata: FlatFieldMetadata;
flatObjectMetadataWithoutFields: FlatObjectMetadataWithoutFields;
fieldMetadataId: string;
objectMetadataId: string;
updates: Array<
{
[P in FlatFieldMetadataPropertiesToCompare]: {
@@ -27,8 +25,8 @@ export type UpdateFieldAction = {
export type DeleteFieldAction = {
type: 'delete_field';
flatFieldMetadata: FlatFieldMetadata;
flatObjectMetadataWithoutFields: FlatObjectMetadataWithoutFields;
fieldMetadataId: string;
objectMetadataId: string;
};
export type WorkspaceMigrationFieldActionV2 =
@@ -7,7 +7,7 @@ export type CreateIndexAction = {
export type DeleteIndexAction = {
type: 'delete_index';
flatIndexMetadata: FlatIndexMetadata;
flatIndexMetadataId: string;
};
export type WorkspaceMigrationIndexActionV2 =
@@ -13,7 +13,7 @@ export type CreateObjectAction = {
export type UpdateObjectAction = {
type: 'update_object';
flatObjectMetadataWithoutFields: FlatObjectMetadataWithoutFields;
objectMetadataId: string;
updates: Array<
{
[P in FlatObjectMetadataPropertiesToCompare]: {
@@ -25,7 +25,7 @@ export type UpdateObjectAction = {
export type DeleteObjectAction = {
type: 'delete_object';
flatObjectMetadataWithoutFields: FlatObjectMetadataWithoutFields;
objectMetadataId: string;
};
export type WorkspaceMigrationObjectActionV2 =
@@ -4,7 +4,6 @@ import {
CreateFieldAction,
DeleteFieldAction,
} 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;
@@ -13,12 +12,9 @@ type FlatFieldMetadataAndFlatObjectMetadata = {
export const getWorkspaceMigrationV2FieldCreateAction = ({
flatFieldMetadata,
flatObjectMetadata,
}: FlatFieldMetadataAndFlatObjectMetadata): CreateFieldAction => ({
type: 'create_field',
flatFieldMetadata,
flatObjectMetadataWithoutFields:
fromFlatObjectMetadataToFlatObjectMetadataWithoutFields(flatObjectMetadata),
});
export const getWorkspaceMigrationV2FieldDeleteAction = ({
@@ -26,7 +22,6 @@ export const getWorkspaceMigrationV2FieldDeleteAction = ({
flatObjectMetadata,
}: FlatFieldMetadataAndFlatObjectMetadata): DeleteFieldAction => ({
type: 'delete_field',
flatFieldMetadata,
flatObjectMetadataWithoutFields:
fromFlatObjectMetadataToFlatObjectMetadataWithoutFields(flatObjectMetadata),
fieldMetadataId: flatFieldMetadata.id,
objectMetadataId: flatObjectMetadata.id,
});
@@ -15,5 +15,5 @@ export const getWorkspaceMigrationV2DeleteIndexAction = (
flatIndexMetadata: FlatIndexMetadata,
): DeleteIndexAction => ({
type: 'delete_index',
flatIndexMetadata,
flatIndexMetadataId: flatIndexMetadata.id,
});
@@ -23,6 +23,5 @@ export const getWorkspaceMigrationV2ObjectDeleteAction = (
flatObjectMetadata: FlatObjectMetadata,
): DeleteObjectAction => ({
type: 'delete_object',
flatObjectMetadataWithoutFields:
fromFlatObjectMetadataToFlatObjectMetadataWithoutFields(flatObjectMetadata),
objectMetadataId: flatObjectMetadata.id,
});
@@ -4,7 +4,6 @@ import {
WorkspaceMigrationFieldActionV2,
} 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 { 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,
getWorkspaceMigrationV2FieldDeleteAction,
@@ -40,11 +39,8 @@ export const buildWorkspaceMigrationV2FieldActions = ({
return {
type: 'update_field',
flatFieldMetadata: to,
flatObjectMetadataWithoutFields:
fromFlatObjectMetadataToFlatObjectMetadataWithoutFields(
flatObjectMetadata,
),
fieldMetadataId: to.id,
objectMetadataId: to.objectMetadataId,
workspaceId: to.workspaceId,
updates,
};
@@ -5,7 +5,6 @@ import {
UpdateObjectAction,
WorkspaceMigrationObjectActionV2,
} 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 {
getWorkspaceMigrationV2ObjectCreateAction,
@@ -56,8 +55,7 @@ export const buildWorkspaceMigrationV2ObjectActions = ({
return {
type: 'update_object',
flatObjectMetadataWithoutFields:
fromFlatObjectMetadataToFlatObjectMetadataWithoutFields(to),
objectMetadataId: to.id,
updates: objectUpdatedProperties,
};
});
@@ -0,0 +1,147 @@
import { assertUnreachable, isDefined } from 'twenty-shared/utils';
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 { addFlatObjectMetadataToFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/add-flat-object-metadata-to-flat-object-metadata-maps-or-throw.util';
import { deleteFieldFromFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/delete-field-from-flat-object-metadata-maps-or-throw.util';
import { deleteObjectFromFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/delete-object-from-flat-object-metadata-maps-or-throw.util';
import { findFlatFieldMetadataInFlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-field-metadata-in-flat-object-metadata-maps.util';
import { findFlatObjectdMetadataInFlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-object-metadata-in-flat-object-metadata-maps.util';
import { replaceFlatFieldMetadataInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/replace-flat-field-metadata-in-flat-object-metadata-maps-or-throw.util';
import { replaceFlatObjectMetadataInFlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/replace-flat-object-metadata-in-flat-object-metadata-maps-or-throw.util';
import { WorkspaceMigrationRunnerArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/types/workspace-migration-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';
import {
WorkspaceMigrationRunnerException,
WorkspaceMigrationRunnerExceptionCode,
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/workspace-migration-runner.exception';
export const applyWorkspaceMigrationActionOnFlatObjectMetadataMaps = ({
action,
flatObjectMetadataMaps,
}: Omit<
WorkspaceMigrationRunnerArgs,
'queryRunner'
>): FlatObjectMetadataMaps => {
switch (action.type) {
case 'delete_object': {
return deleteObjectFromFlatObjectMetadataMapsOrThrow({
flatObjectMetadataMaps,
objectMetadataId: action.objectMetadataId,
});
}
case 'create_object': {
const flatObjectMetadataWithoutFields =
action.flatObjectMetadataWithoutFields;
const flatFieldMetadatas = action.createFieldActions.map(
(createFieldAction) => createFieldAction.flatFieldMetadata,
);
return addFlatObjectMetadataToFlatObjectMetadataMapsOrThrow({
flatObjectMetadata: {
...flatObjectMetadataWithoutFields,
flatIndexMetadatas: [],
flatFieldMetadatas,
},
flatObjectMetadataMaps,
});
}
case 'update_object': {
const { objectMetadataId } = action;
const existingFlatObjectMetadata =
findFlatObjectdMetadataInFlatObjectMetadataMaps({
objectMetadataId,
flatObjectMetadataMaps,
});
if (!isDefined(existingFlatObjectMetadata)) {
throw new WorkspaceMigrationRunnerException(
`Workspace migration failed: Object metadata not found in cache`,
WorkspaceMigrationRunnerExceptionCode.OBJECT_METADATA_NOT_FOUND,
);
}
const updatedFlatObjectMetadata = {
...existingFlatObjectMetadata,
...fromWorkspaceMigrationUpdateActionToPartialEntity(action),
};
return replaceFlatObjectMetadataInFlatObjectMetadataMaps({
flatObjectMetadata: updatedFlatObjectMetadata,
flatObjectMetadataMaps,
});
}
case 'create_field': {
const updatedFlatObjectMetadataMaps =
addFlatFieldMetadataInFlatObjectMetadataMapsOrThrow({
flatFieldMetadata: action.flatFieldMetadata,
flatObjectMetadataMaps,
});
if (!isDefined(updatedFlatObjectMetadataMaps)) {
throw new WorkspaceMigrationRunnerException(
`Workspace migration failed: dispatchAndAddFlatFieldMetadataInFlatObjectMetadataMaps failed`,
WorkspaceMigrationRunnerExceptionCode.FIELD_METADATA_NOT_FOUND,
);
}
return updatedFlatObjectMetadataMaps;
}
case 'update_field': {
const { fieldMetadataId, objectMetadataId } = action;
const existingFlatFieldMetadata =
findFlatFieldMetadataInFlatObjectMetadataMaps({
fieldMetadataId,
objectMetadataId,
flatObjectMetadataMaps,
});
if (!isDefined(existingFlatFieldMetadata)) {
throw new WorkspaceMigrationRunnerException(
`Workspace migration failed: Field metadata not found in cache`,
WorkspaceMigrationRunnerExceptionCode.FIELD_METADATA_NOT_FOUND,
);
}
const updatedFlatFieldMetadata = {
...existingFlatFieldMetadata,
...fromWorkspaceMigrationUpdateActionToPartialEntity(action),
};
const updatedFlatObjectMetadataMaps =
replaceFlatFieldMetadataInFlatObjectMetadataMapsOrThrow({
flatFieldMetadata: updatedFlatFieldMetadata,
flatObjectMetadataMaps,
});
if (!isDefined(updatedFlatObjectMetadataMaps)) {
throw new WorkspaceMigrationRunnerException(
`Workspace migration failed: dispatchAndReplaceFlatFieldMetadataInFlatObjectMetadataMaps failed`,
WorkspaceMigrationRunnerExceptionCode.FIELD_METADATA_NOT_FOUND,
);
}
return updatedFlatObjectMetadataMaps;
}
case 'delete_field': {
return deleteFieldFromFlatObjectMetadataMapsOrThrow({
fieldMetadataId: action.fieldMetadataId,
flatObjectMetadataMaps,
objectMetadataId: action.objectMetadataId,
});
}
case 'create_index': {
// TODO prastoin handle indexes
return flatObjectMetadataMaps;
}
case 'delete_index': {
// TODO prastoin handle indexes
return flatObjectMetadataMaps;
}
default: {
assertUnreachable(
action,
'Should never occur, encountered an unsupported workspace migration action type',
);
}
}
};
@@ -1,8 +1,10 @@
import { QueryRunner } from 'typeorm';
import { WorkspaceMigrationV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-v2';
import { FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
import { WorkspaceMigrationActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-action-common-v2';
export type WorkspaceMigrationRunnerArgs = {
workspaceMigration: WorkspaceMigrationV2;
action: WorkspaceMigrationActionV2;
queryRunner: QueryRunner;
flatObjectMetadataMaps: FlatObjectMetadataMaps;
};
@@ -0,0 +1,15 @@
import { UpdateFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2';
import { UpdateObjectAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2';
export const fromWorkspaceMigrationUpdateActionToPartialEntity = <
T extends UpdateFieldAction | UpdateObjectAction,
>(
action: T,
) => {
return action.updates.reduce((acc, { to, property }) => {
return {
...acc,
[property]: to,
};
}, {});
};
@@ -1,8 +1,6 @@
import { In } from 'typeorm';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { FlatFieldMetadataPropertiesToCompare } from 'src/engine/metadata-modules/flat-field-metadata/utils/compare-two-flat-field-metadata.util';
import {
CreateFieldAction,
DeleteFieldAction,
@@ -11,6 +9,7 @@ import {
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2';
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 { fromWorkspaceMigrationUpdateActionToPartialEntity } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/utils/from-workspace-migration-update-action-to-partial-field-or-object-entity.util';
export class WorkspaceMetadataFieldActionRunnerService
implements
@@ -25,10 +24,10 @@ export class WorkspaceMetadataFieldActionRunnerService
FieldMetadataEntity,
);
const { flatFieldMetadata } = action;
const { fieldMetadataId } = action;
await fieldMetadataRepository.delete({
id: In([flatFieldMetadata.id]),
id: In([fieldMetadataId]),
});
};
@@ -43,7 +42,6 @@ export class WorkspaceMetadataFieldActionRunnerService
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 ({
@@ -55,16 +53,11 @@ export class WorkspaceMetadataFieldActionRunnerService
FieldMetadataEntity,
);
const { flatFieldMetadata, updates } = action;
const update = updates.reduce<
Partial<Pick<FlatFieldMetadata, FlatFieldMetadataPropertiesToCompare>>
>((acc, { property, to }) => {
return {
...acc,
[property]: to,
};
}, {});
const { fieldMetadataId } = action;
await fieldMetadataRepository.update(flatFieldMetadata.id, update);
await fieldMetadataRepository.update(
fieldMetadataId,
fromWorkspaceMigrationUpdateActionToPartialEntity(action),
);
};
}
@@ -16,65 +16,63 @@ export class WorkspaceMetadataMigrationRunnerService {
) {}
runWorkspaceMetadataMigration = async ({
workspaceMigration,
action,
queryRunner,
}: WorkspaceMigrationRunnerArgs) => {
for (const action of workspaceMigration.actions) {
switch (action.type) {
case 'delete_object': {
await this.workspaceMetadataObjectMigrationRunnerService.runDeleteObjectMetadataMigration(
{ action, queryRunner },
);
break;
}
case 'create_object': {
await this.workspaceMetadataObjectMigrationRunnerService.runCreateObjectMetadataMigration(
{ action, queryRunner },
);
break;
}
case 'update_object': {
await this.workspaceMetadataObjectMigrationRunnerService.runUpdateObjectMetadataMigration(
{ action, queryRunner },
);
break;
}
case 'create_field': {
await this.workspaceMetadataFieldMigrationRunnerService.runCreateFieldMetadataMigration(
{ action, queryRunner },
);
break;
}
case 'update_field': {
await this.workspaceMetadataFieldMigrationRunnerService.runUpdateFieldMetadataMigration(
{ action, queryRunner },
);
break;
}
case 'delete_field': {
await this.workspaceMetadataFieldMigrationRunnerService.runDeleteFieldMetadataMigration(
{ action, queryRunner },
);
break;
}
case 'create_index': {
await this.workspaceMetadataIndexMigrationRunnerService.runCreateIndexMetadataMigration(
{ action, queryRunner },
);
break;
}
case 'delete_index': {
await this.workspaceMetadataIndexMigrationRunnerService.runDeleteIndexMetadataMigration(
{ action, queryRunner },
);
break;
}
default: {
assertUnreachable(
action,
'Should never occur, encountered an unsupported workspace migration action type',
);
}
switch (action.type) {
case 'delete_object': {
await this.workspaceMetadataObjectMigrationRunnerService.runDeleteObjectMetadataMigration(
{ action, queryRunner },
);
break;
}
case 'create_object': {
await this.workspaceMetadataObjectMigrationRunnerService.runCreateObjectMetadataMigration(
{ action, queryRunner },
);
break;
}
case 'update_object': {
await this.workspaceMetadataObjectMigrationRunnerService.runUpdateObjectMetadataMigration(
{ action, queryRunner },
);
break;
}
case 'create_field': {
await this.workspaceMetadataFieldMigrationRunnerService.runCreateFieldMetadataMigration(
{ action, queryRunner },
);
break;
}
case 'update_field': {
await this.workspaceMetadataFieldMigrationRunnerService.runUpdateFieldMetadataMigration(
{ action, queryRunner },
);
break;
}
case 'delete_field': {
await this.workspaceMetadataFieldMigrationRunnerService.runDeleteFieldMetadataMigration(
{ action, queryRunner },
);
break;
}
case 'create_index': {
await this.workspaceMetadataIndexMigrationRunnerService.runCreateIndexMetadataMigration(
{ action, queryRunner },
);
break;
}
case 'delete_index': {
await this.workspaceMetadataIndexMigrationRunnerService.runDeleteIndexMetadataMigration(
{ action, queryRunner },
);
break;
}
default: {
assertUnreachable(
action,
'Should never occur, encountered an unsupported workspace migration action type',
);
}
}
};
@@ -1,8 +1,6 @@
import { Injectable } from '@nestjs/common';
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { FlatObjectMetadataPropertiesToCompare } from 'src/engine/metadata-modules/flat-object-metadata/utils/compare-two-flat-object-metadata.util';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import {
CreateObjectAction,
@@ -12,16 +10,21 @@ import {
} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2';
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 { 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';
import { WorkspaceMetadataFieldActionRunnerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/workspace-metadata-migration-runner/workspace-metadata-field-action-runner.service';
@Injectable()
export class WorkspaceMetadataObjectActionRunnerService
implements
RunnerMethodForActionType<WorkspaceMigrationObjectActionTypeV2, 'metadata'>
{
constructor(private readonly dataSourceService: DataSourceService) {}
constructor(
private readonly dataSourceService: DataSourceService,
private readonly workspaceMetadataFieldActionRunnerService: WorkspaceMetadataFieldActionRunnerService,
) {}
runDeleteObjectMetadataMigration = async ({
action: { flatObjectMetadataWithoutFields },
action: { objectMetadataId },
queryRunner,
}: WorkspaceMigrationActionRunnerArgs<DeleteObjectAction>) => {
const objectMetadataRepository =
@@ -29,11 +32,11 @@ export class WorkspaceMetadataObjectActionRunnerService
ObjectMetadataEntity,
);
await objectMetadataRepository.delete(flatObjectMetadataWithoutFields.id);
await objectMetadataRepository.delete(objectMetadataId);
};
runCreateObjectMetadataMigration = async ({
action: { flatObjectMetadataWithoutFields },
action: { flatObjectMetadataWithoutFields, createFieldActions },
queryRunner,
}: WorkspaceMigrationActionRunnerArgs<CreateObjectAction>) => {
const objectMetadataRepository =
@@ -49,12 +52,20 @@ export class WorkspaceMetadataObjectActionRunnerService
...flatObjectMetadataWithoutFields,
dataSourceId: lastDataSourceMetadata.id,
targetTableName: 'DEPRECATED',
// TODO call for each provided field too or pass fields here
});
for (const createFieldAction of createFieldActions) {
await this.workspaceMetadataFieldActionRunnerService.runCreateFieldMetadataMigration(
{
action: createFieldAction,
queryRunner,
},
);
}
};
runUpdateObjectMetadataMigration = async ({
action: { flatObjectMetadataWithoutFields, updates },
action,
queryRunner,
}: WorkspaceMigrationActionRunnerArgs<UpdateObjectAction>) => {
const objectMetadataRepository =
@@ -62,18 +73,9 @@ export class WorkspaceMetadataObjectActionRunnerService
ObjectMetadataEntity,
);
const update = updates.reduce<
Partial<Pick<FlatObjectMetadata, FlatObjectMetadataPropertiesToCompare>>
>((acc, { property, to }) => {
return {
...acc,
[property]: to,
};
}, {});
await objectMetadataRepository.save({
...flatObjectMetadataWithoutFields, // could be stricter
...update,
});
await objectMetadataRepository.update(
action.objectMetadataId,
fromWorkspaceMigrationUpdateActionToPartialEntity(action),
);
};
}
@@ -3,6 +3,7 @@ import { Module } from '@nestjs/common';
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
import { WorkspaceMetadataCacheModule } from 'src/engine/metadata-modules/workspace-metadata-cache/workspace-metadata-cache.module';
import { WorkspaceMetadataVersionModule } from 'src/engine/metadata-modules/workspace-metadata-version/workspace-metadata-version.module';
import { WorkspacePermissionsCacheModule } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.module';
import { WorkspaceMetadataFieldActionRunnerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/workspace-metadata-migration-runner/workspace-metadata-field-action-runner.service';
@@ -22,6 +23,7 @@ import { WorkspaceSchemaObjectActionRunnerService } from 'src/engine/workspace-m
DataSourceModule,
WorkspaceMetadataVersionModule,
WorkspacePermissionsCacheModule,
WorkspaceMetadataCacheModule,
],
providers: [
WorkspaceMetadataObjectActionRunnerService,
@@ -3,9 +3,11 @@ import { InjectDataSource } from '@nestjs/typeorm';
import { DataSource } from 'typeorm';
import { WorkspaceMetadataCacheService } from 'src/engine/metadata-modules/workspace-metadata-cache/services/workspace-metadata-cache.service';
import { WorkspaceMetadataVersionService } from 'src/engine/metadata-modules/workspace-metadata-version/services/workspace-metadata-version.service';
import { WorkspacePermissionsCacheService } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service';
import { WorkspaceMigrationV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-v2';
import { applyWorkspaceMigrationActionOnFlatObjectMetadataMaps } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/apply-workspace-migration-action-on-flat-object-metadata-maps';
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';
@@ -16,6 +18,7 @@ export class WorkspaceMigrationRunnerV2Service {
private readonly workspaceSchemaMigrationRunner: WorkspaceSchemaMigrationRunnerService,
private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService,
private readonly workspacePermissionsCacheService: WorkspacePermissionsCacheService,
private readonly workspaceMetadataCacheService: WorkspaceMetadataCacheService,
@InjectDataSource('core')
private readonly coreDataSource: DataSource,
) {}
@@ -23,19 +26,40 @@ export class WorkspaceMigrationRunnerV2Service {
run = async (workspaceMigration: WorkspaceMigrationV2) => {
const queryRunner = this.coreDataSource.createQueryRunner();
const { flatObjectMetadataMaps } =
await this.workspaceMetadataCacheService.getExistingOrRecomputeFlatObjectMetadataMaps(
{
workspaceId: workspaceMigration.workspaceId,
},
);
await queryRunner.connect();
await queryRunner.startTransaction();
let optimisticFlatObjectMetadataMaps = structuredClone(
flatObjectMetadataMaps,
);
try {
await Promise.all([
this.workspaceMetadataMigrationRunner.runWorkspaceMetadataMigration({
queryRunner,
workspaceMigration,
}),
this.workspaceSchemaMigrationRunner.runWorkspaceSchemaMigration({
queryRunner,
workspaceMigration,
}),
]);
for (const action of workspaceMigration.actions) {
await Promise.all([
this.workspaceMetadataMigrationRunner.runWorkspaceMetadataMigration({
flatObjectMetadataMaps: optimisticFlatObjectMetadataMaps,
queryRunner,
action,
}),
this.workspaceSchemaMigrationRunner.runWorkspaceSchemaMigration({
queryRunner,
flatObjectMetadataMaps: optimisticFlatObjectMetadataMaps,
action,
}),
]);
optimisticFlatObjectMetadataMaps =
applyWorkspaceMigrationActionOnFlatObjectMetadataMaps({
action,
flatObjectMetadataMaps: optimisticFlatObjectMetadataMaps,
});
}
await queryRunner.commitTransaction();
const { workspaceId } = workspaceMigration;
@@ -0,0 +1,13 @@
import {
appendCommonExceptionCode,
CustomException,
} from 'src/utils/custom-exception';
export class WorkspaceMigrationRunnerException extends CustomException<
keyof typeof WorkspaceMigrationRunnerExceptionCode
> {}
export const WorkspaceMigrationRunnerExceptionCode = appendCommonExceptionCode({
FIELD_METADATA_NOT_FOUND: 'FIELD_METADATA_NOT_FOUND',
OBJECT_METADATA_NOT_FOUND: 'OBJECT_METADATA_NOT_FOUND',
} as const);
@@ -16,65 +16,63 @@ export class WorkspaceSchemaMigrationRunnerService {
) {}
runWorkspaceSchemaMigration = async ({
workspaceMigration,
action,
queryRunner,
}: WorkspaceMigrationRunnerArgs) => {
for (const action of workspaceMigration.actions) {
switch (action.type) {
case 'delete_object': {
await this.workspaceSchemaObjectMigrationRunnerService.runDeleteObjectSchemaMigration(
{ action, queryRunner },
);
break;
}
case 'create_object': {
await this.workspaceSchemaObjectMigrationRunnerService.runCreateObjectSchemaMigration(
{ action, queryRunner },
);
break;
}
case 'update_object': {
await this.workspaceSchemaObjectMigrationRunnerService.runUpdateObjectSchemaMigration(
{ action, queryRunner },
);
break;
}
case 'create_field': {
await this.workspaceSchemaFieldMigrationRunnerService.runCreateFieldSchemaMigration(
{ action, queryRunner },
);
break;
}
case 'update_field': {
await this.workspaceSchemaFieldMigrationRunnerService.runUpdateFieldSchemaMigration(
{ action, queryRunner },
);
break;
}
case 'delete_field': {
await this.workspaceSchemaFieldMigrationRunnerService.runDeleteFieldSchemaMigration(
{ action, queryRunner },
);
break;
}
case 'create_index': {
await this.workspaceSchemaIndexMigrationRunnerService.runCreateIndexSchemaMigration(
{ action, queryRunner },
);
break;
}
case 'delete_index': {
await this.workspaceSchemaIndexMigrationRunnerService.runDeleteIndexSchemaMigration(
{ action, queryRunner },
);
break;
}
default: {
assertUnreachable(
action,
'Should never occur, encountered an unsupported workspace migration action type',
);
}
switch (action.type) {
case 'delete_object': {
await this.workspaceSchemaObjectMigrationRunnerService.runDeleteObjectSchemaMigration(
{ action, queryRunner },
);
break;
}
case 'create_object': {
await this.workspaceSchemaObjectMigrationRunnerService.runCreateObjectSchemaMigration(
{ action, queryRunner },
);
break;
}
case 'update_object': {
await this.workspaceSchemaObjectMigrationRunnerService.runUpdateObjectSchemaMigration(
{ action, queryRunner },
);
break;
}
case 'create_field': {
await this.workspaceSchemaFieldMigrationRunnerService.runCreateFieldSchemaMigration(
{ action, queryRunner },
);
break;
}
case 'update_field': {
await this.workspaceSchemaFieldMigrationRunnerService.runUpdateFieldSchemaMigration(
{ action, queryRunner },
);
break;
}
case 'delete_field': {
await this.workspaceSchemaFieldMigrationRunnerService.runDeleteFieldSchemaMigration(
{ action, queryRunner },
);
break;
}
case 'create_index': {
await this.workspaceSchemaIndexMigrationRunnerService.runCreateIndexSchemaMigration(
{ action, queryRunner },
);
break;
}
case 'delete_index': {
await this.workspaceSchemaIndexMigrationRunnerService.runDeleteIndexSchemaMigration(
{ action, queryRunner },
);
break;
}
default: {
assertUnreachable(
action,
'Should never occur, encountered an unsupported workspace migration action type',
);
}
}
};