diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-field-metadata.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-field-metadata.ts new file mode 100644 index 000000000..14b5240fc --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-field-metadata.ts @@ -0,0 +1,7 @@ +import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; + +export type FlatFieldMetadata = Partial< + Omit +> & { + uniqueIdentifier: string; +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-index-field-metadata.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-index-field-metadata.ts new file mode 100644 index 000000000..c25f813a6 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-index-field-metadata.ts @@ -0,0 +1,15 @@ +import { IndexFieldMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-field-metadata.entity'; + +const indexFieldMetadataEntityRelationProperties = [ + 'indexMetadata', + 'fieldMetadata', +] as const satisfies (keyof IndexFieldMetadataEntity)[]; + +type IndexFieldMetadataRelationProperties = + (typeof indexFieldMetadataEntityRelationProperties)[number]; + +export type FlatIndexFieldMetadata = Partial< + Omit +> & { + uniqueIdentifier: string; +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-index-metadata.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-index-metadata.ts new file mode 100644 index 000000000..b1ceb87b9 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-index-metadata.ts @@ -0,0 +1,9 @@ +import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; +import { FlatIndexFieldMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-index-field-metadata'; + +export type FlatIndexMetadata = Partial< + Omit // Might have an issue as ObjectMetadataId != uniqueIdentifier +> & { + flatIndexFieldMetadatas: FlatIndexFieldMetadata[]; + uniqueIdentifier: string; +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-object-metadata.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-object-metadata.ts new file mode 100644 index 000000000..9d29ef339 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-object-metadata.ts @@ -0,0 +1,17 @@ +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { FlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-field-metadata'; +import { FlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-index-metadata'; + +export type FlatObjectMetadata = Partial< + Omit +> & { + uniqueIdentifier: string; + flatIndexMetadatas: FlatIndexMetadata[]; + flatFieldMetadatas: FlatFieldMetadata[]; +}; + +// Could be renamed +export type FlatObjectMetadataWithoutFields = Omit< + FlatObjectMetadata, + 'flatFieldMetadatas' | 'flatIndexMetadatas' +>; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-action-common-v2.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-action-common-v2.ts deleted file mode 100644 index ef5ed4e82..000000000 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-action-common-v2.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { WorkspaceMigrationFieldActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-field-action-v2'; -import { WorkspaceMigrationIndexActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-index-action-v2'; -import { WorkspaceMigrationV2ObjectAction } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-action-v2'; -import { WorkspaceMigrationUniquenessActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-uniqueness-action-v2'; - -export type WorkspaceMigrationActionV2 = - | WorkspaceMigrationV2ObjectAction - | WorkspaceMigrationFieldActionV2 - | WorkspaceMigrationUniquenessActionV2 - | WorkspaceMigrationIndexActionV2; - -export type WorkspaceMigrationActionTypeV2 = WorkspaceMigrationActionV2['type']; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-field-input.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-field-input.ts deleted file mode 100644 index 6759512da..000000000 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-field-input.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; - -export const fieldMetadataEntityEditableProperties = [ - 'defaultValue', - 'description', - 'icon', - 'isActive', - 'isLabelSyncedWithName', - 'isUnique', // unsure - 'label', - 'name', - 'options', - // TODO update once we reactivate the relation edition - // 'relationTargetFieldMetadata', - // 'relationTargetFieldMetadataId', - // 'relationTargetObjectMetadata', - // 'relationTargetObjectMetadataId', - // 'settings', - /// - 'standardOverrides', -] as const satisfies (keyof FieldMetadataEntity)[]; -export type FieldMetadataEntityEditableProperties = - (typeof fieldMetadataEntityEditableProperties)[number]; - -// TODO could describe required minimum keys -export type WorkspaceMigrationFieldInput = Partial< - Omit -> & { - uniqueIdentifier: string; -}; - -export const fieldMetadataPropertiesToStringify = [ - 'defaultValue', - 'standardOverrides', -] as const satisfies FieldMetadataEntityEditableProperties[]; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-input.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-input.ts deleted file mode 100644 index ff408c156..000000000 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-input.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; -import { WorkspaceMigrationFieldInput } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-field-input'; - -export const objectMetadataEntityEditableProperties = [ - 'description', - 'icon', - 'isActive', - 'isLabelSyncedWithName', - 'labelPlural', - 'labelSingular', - 'namePlural', - 'nameSingular', - 'standardOverrides', // Only if standard -] as const satisfies (keyof ObjectMetadataEntity)[]; -export type ObjectMetadataEntityEditableProperties = - (typeof objectMetadataEntityEditableProperties)[number]; - -export type WorkspaceMigrationObjectInput = Partial< - Omit -> & { - uniqueIdentifier: string; - fieldInputs: WorkspaceMigrationFieldInput[]; -}; - -export type WorkspaceMigrationObjectWithoutFields = Omit< - WorkspaceMigrationObjectInput, - 'fieldInputs' ->; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-uniqueness-action-v2.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-uniqueness-action-v2.ts deleted file mode 100644 index 2a412bc02..000000000 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-uniqueness-action-v2.ts +++ /dev/null @@ -1,11 +0,0 @@ -export type AddUniquenessConstraintAction = { - type: 'add_uniqueness_constraint'; -}; - -export type RemoveUniquenessConstraintAction = { - type: 'remove_uniqueness_constraint'; -}; - -export type WorkspaceMigrationUniquenessActionV2 = - | RemoveUniquenessConstraintAction - | AddUniquenessConstraintAction; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/deleted-created-updated-matrix-dispatcher.util.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/deleted-created-updated-matrix-dispatcher.util.ts similarity index 100% rename from packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/deleted-created-updated-matrix-dispatcher.util.ts rename to packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/deleted-created-updated-matrix-dispatcher.util.ts diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/flat-field-metadata-comparator.util.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/flat-field-metadata-comparator.util.ts new file mode 100644 index 000000000..2687d691e --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/flat-field-metadata-comparator.util.ts @@ -0,0 +1,104 @@ +import diff from 'microdiff'; +import { FieldMetadataType } from 'twenty-shared/types'; +import { isDefined } from 'twenty-shared/utils'; + +import { FlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-field-metadata'; +import { FromTo } from 'src/engine/workspace-manager/workspace-migration-v2/types/from-to.type'; +import { UpdateFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2'; +import { transformMetadataForComparison } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util'; + +const flatFieldMetadataPropertiesToCompare = [ + 'defaultValue', + 'description', + 'icon', + 'isActive', + 'isLabelSyncedWithName', + 'isUnique', + 'label', + 'name', + 'options', + 'standardOverrides', +] as const satisfies (keyof FlatFieldMetadata)[]; + +export type FlatFieldMetadataPropertiesToCompare = + (typeof flatFieldMetadataPropertiesToCompare)[number]; + +const fieldMetadataPropertiesToStringify = [ + 'defaultValue', + 'standardOverrides', +] as const satisfies FlatFieldMetadataPropertiesToCompare[]; + +const shouldNotOverrideDefaultValue = (type: FieldMetadataType) => { + return [ + FieldMetadataType.BOOLEAN, + FieldMetadataType.SELECT, + FieldMetadataType.MULTI_SELECT, + FieldMetadataType.CURRENCY, + FieldMetadataType.PHONES, + FieldMetadataType.ADDRESS, + ].includes(type); +}; + +type GetWorkspaceMigrationUpdateFieldActionArgs = FromTo; +export const compareTwoFlatFieldMetadata = ({ + from, + to, +}: GetWorkspaceMigrationUpdateFieldActionArgs) => { + const compareFieldMetadataOptions = { + shouldIgnoreProperty: ( + property: string, + fieldMetadata: FlatFieldMetadata, + ) => { + if ( + !flatFieldMetadataPropertiesToCompare.includes( + property as FlatFieldMetadataPropertiesToCompare, + ) + ) { + return true; + } + + if ( + property === 'defaultValue' && + isDefined(fieldMetadata.type) && + shouldNotOverrideDefaultValue(fieldMetadata.type) + ) { + return true; + } + + return false; + }, + propertiesToStringify: fieldMetadataPropertiesToStringify, + }; + const fromCompare = transformMetadataForComparison( + from, + compareFieldMetadataOptions, + ); + const toCompare = transformMetadataForComparison( + to, + compareFieldMetadataOptions, + ); + + const flatFieldMetadataDifferences = diff(fromCompare, toCompare); + + return flatFieldMetadataDifferences.flatMap< + UpdateFieldAction['updates'][number] + >((difference) => { + switch (difference.type) { + case 'CHANGE': { + const { oldValue, path, value } = difference; + + return { + from: oldValue, + to: value, + property: path[0] as FlatFieldMetadataPropertiesToCompare, + }; + } + case 'CREATE': + case 'REMOVE': + default: { + // Should never occurs, we should only provide null never undefined and so on + return []; + } + } + }); +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/flat-index-metadata-comparator.util.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/flat-index-metadata-comparator.util.ts new file mode 100644 index 000000000..3c26b5007 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/flat-index-metadata-comparator.util.ts @@ -0,0 +1,60 @@ +import diff from 'microdiff'; + +import { FlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-index-metadata'; +import { FromTo } from 'src/engine/workspace-manager/workspace-migration-v2/types/from-to.type'; +import { transformMetadataForComparison } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util'; + +const flatIndexMetadataPropertiesToCompare = [ + 'flatIndexFieldMetadatas', // Comparing this as whole ? should iterate on each keys ? => TBD should only map over cols as before ? + 'indexType', + 'indexWhereClause', + 'isUnique', + 'name', +] as const satisfies (keyof FlatIndexMetadata)[]; + +type FlatIndexMetadataPropertiesToCompare = + (typeof flatIndexMetadataPropertiesToCompare)[number]; + +// Should also handle indexFieldMetadata comparison ? +export const compareTwoFlatIndexMetadata = ({ + from, + to, +}: FromTo) => { + const transformOptions = { + shouldIgnoreProperty: (property: string) => + !flatIndexMetadataPropertiesToCompare.includes( + property as FlatIndexMetadataPropertiesToCompare, + ), + }; + + const fromCompare = transformMetadataForComparison(from, transformOptions); + const toCompare = transformMetadataForComparison(to, transformOptions); + + const flatIndexeDifferences = diff(fromCompare, toCompare); + + return flatIndexeDifferences.flatMap<{ property: string } & FromTo>( + (difference) => { + switch (difference.type) { + case 'CHANGE': { + const { oldValue, path, value } = difference; + + const property = path[0]; + + if (typeof property === 'number') { + return []; + } + + return { + from: oldValue, + property, + to: value, + }; + } + case 'CREATE': + case 'REMOVE': + default: + return []; + } + }, + ); +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/workspace-migration-object-metadata-input-comparator.util.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/flat-object-metadata-comparator.util.ts similarity index 66% rename from packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/workspace-migration-object-metadata-input-comparator.util.ts rename to packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/flat-object-metadata-comparator.util.ts index 7383768ef..3b3e29299 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/workspace-migration-object-metadata-input-comparator.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/flat-object-metadata-comparator.util.ts @@ -2,21 +2,30 @@ import omit from 'lodash.omit'; import diff from 'microdiff'; import { assertUnreachable } from 'twenty-shared/utils'; +import { FlatObjectMetadata } 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 { UpdateObjectAction } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-action-v2'; -import { - ObjectMetadataEntityEditableProperties, - WorkspaceMigrationObjectInput, - objectMetadataEntityEditableProperties, -} from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-input'; +import { UpdateObjectAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2'; import { transformMetadataForComparison } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util'; -type ObjectWorkspaceMigrationUpdate = FromTo; +const flatObjectMetadataPropertiesToCompare = [ + 'description', + 'icon', + 'isActive', + 'isLabelSyncedWithName', + 'labelPlural', + 'labelSingular', + 'namePlural', + 'nameSingular', + 'standardOverrides', // Only if standard +] as const satisfies (keyof FlatObjectMetadata)[]; -export const compareTwoWorkspaceMigrationObjectInput = ({ +export type FlatObjectMetadataPropertiesToCompare = + (typeof flatObjectMetadataPropertiesToCompare)[number]; + +export const compareTwoFlatObjectMetadata = ({ from, to, -}: ObjectWorkspaceMigrationUpdate) => { +}: FromTo) => { const fromCompare = transformMetadataForComparison(from, {}); const toCompare = transformMetadataForComparison(to, {}); const objectMetadataDifference = diff(fromCompare, omit(toCompare, 'fields')); @@ -41,15 +50,15 @@ export const compareTwoWorkspaceMigrationObjectInput = ({ // Could be handled directly from the diff we do above if ( - !objectMetadataEntityEditableProperties.includes( - property as ObjectMetadataEntityEditableProperties, + !flatObjectMetadataPropertiesToCompare.includes( + property as FlatObjectMetadataPropertiesToCompare, ) ) { return []; } return { - property: property as ObjectMetadataEntityEditableProperties, + property: property as FlatObjectMetadataPropertiesToCompare, from: difference.oldValue, to: difference.value, }; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-v2-builder.spec.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-v2-builder.spec.ts index b61b433cf..da2056e0b 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-v2-builder.spec.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-v2-builder.spec.ts @@ -1,19 +1,20 @@ import { FieldMetadataType } from 'twenty-shared/types'; -import { WorkspaceMigrationObjectInput } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-input'; +import { FlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-object-metadata'; import { WorkspaceMigrationBuilderV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-builder-v2.service'; describe('WorkspaceMigrationBuilderV2Service', () => { let service: WorkspaceMigrationBuilderV2Service; - const baseObject: WorkspaceMigrationObjectInput = { + const baseObject: FlatObjectMetadata = { uniqueIdentifier: '20202020-e89b-12d3-a456-426614175000', nameSingular: 'Contact', namePlural: 'Contacts', labelSingular: 'Contact', + flatIndexMetadatas: [], labelPlural: 'Contacts', description: 'A contact', - fieldInputs: [ + flatFieldMetadatas: [ { uniqueIdentifier: '20202020-e89b-12d3-a456-426614174000', name: 'firstName', @@ -30,8 +31,8 @@ describe('WorkspaceMigrationBuilderV2Service', () => { }); it('should return a migration when nameSingular changes', () => { - const from: WorkspaceMigrationObjectInput = baseObject; - const to: WorkspaceMigrationObjectInput = { + const from: FlatObjectMetadata = baseObject; + const to: FlatObjectMetadata = { ...from, nameSingular: 'Person', }; @@ -41,9 +42,9 @@ describe('WorkspaceMigrationBuilderV2Service', () => { { "actions": [ { - "objectMetadataInput": { + "flatObjectMetadata": { "description": "A contact", - "fieldInputs": [ + "flatFieldMetadatas": [ { "defaultValue": "", "description": "", @@ -53,6 +54,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "uniqueIdentifier": "20202020-e89b-12d3-a456-426614174000", }, ], + "flatIndexMetadatas": [], "labelPlural": "Contacts", "labelSingular": "Contact", "namePlural": "Contacts", @@ -74,14 +76,15 @@ describe('WorkspaceMigrationBuilderV2Service', () => { }); it('should return a migration when creating a new object', () => { - const newObject: WorkspaceMigrationObjectInput = { + const newObject: FlatObjectMetadata = { uniqueIdentifier: '20202020-e89b-12d3-a456-426614175001', nameSingular: 'Company', namePlural: 'Companies', + flatIndexMetadatas: [], labelSingular: 'Company', labelPlural: 'Companies', description: 'A company', - fieldInputs: [ + flatFieldMetadatas: [ { uniqueIdentifier: '20202020-e89b-12d3-a456-426614174001', name: 'name', @@ -99,9 +102,9 @@ describe('WorkspaceMigrationBuilderV2Service', () => { { "actions": [ { - "objectMetadataInput": { + "flatObjectMetadata": { "description": "A company", - "fieldInputs": [ + "flatFieldMetadatas": [ { "defaultValue": "", "description": "", @@ -111,6 +114,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "uniqueIdentifier": "20202020-e89b-12d3-a456-426614174001", }, ], + "flatIndexMetadatas": [], "labelPlural": "Companies", "labelSingular": "Company", "namePlural": "Companies", @@ -120,7 +124,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "type": "create_object", }, { - "fieldMetadataInput": { + "flatFieldMetadata": { "defaultValue": "", "description": "", "label": "Name", @@ -128,9 +132,9 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "type": "ADDRESS", "uniqueIdentifier": "20202020-e89b-12d3-a456-426614174001", }, - "objectMetadataInput": { + "flatObjectMetadata": { "description": "A company", - "fieldInputs": [ + "flatFieldMetadatas": [ { "defaultValue": "", "description": "", @@ -140,6 +144,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "uniqueIdentifier": "20202020-e89b-12d3-a456-426614174001", }, ], + "flatIndexMetadatas": [], "labelPlural": "Companies", "labelSingular": "Company", "namePlural": "Companies", @@ -160,9 +165,9 @@ describe('WorkspaceMigrationBuilderV2Service', () => { { "actions": [ { - "objectMetadataInput": { + "flatObjectMetadata": { "description": "A contact", - "fieldInputs": [ + "flatFieldMetadatas": [ { "defaultValue": "", "description": "", @@ -172,6 +177,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "uniqueIdentifier": "20202020-e89b-12d3-a456-426614174000", }, ], + "flatIndexMetadatas": [], "labelPlural": "Contacts", "labelSingular": "Contact", "namePlural": "Contacts", @@ -186,11 +192,11 @@ describe('WorkspaceMigrationBuilderV2Service', () => { }); it('should handle multiple operations in a single migration', () => { - const objectToUpdate: WorkspaceMigrationObjectInput = { + const objectToUpdate: FlatObjectMetadata = { ...baseObject, nameSingular: 'Person', - fieldInputs: [ - ...baseObject.fieldInputs, + flatFieldMetadatas: [ + ...baseObject.flatFieldMetadatas, { defaultValue: '', label: 'New field', @@ -205,14 +211,15 @@ describe('WorkspaceMigrationBuilderV2Service', () => { ...baseObject, uniqueIdentifier: '20202020-59ef-4a14-a509-0a02acb248d5', }; - const objectToCreate: WorkspaceMigrationObjectInput = { + const objectToCreate: FlatObjectMetadata = { uniqueIdentifier: '20202020-1218-4fc0-b32d-fc4f005c4bab', nameSingular: 'Company', namePlural: 'Companies', + flatIndexMetadatas: [], labelSingular: 'Company', labelPlural: 'Companies', description: 'A company', - fieldInputs: [ + flatFieldMetadatas: [ { uniqueIdentifier: '20202020-1016-4f09-bad6-e75681f385f4', name: 'name', @@ -233,9 +240,9 @@ describe('WorkspaceMigrationBuilderV2Service', () => { { "actions": [ { - "objectMetadataInput": { + "flatObjectMetadata": { "description": "A company", - "fieldInputs": [ + "flatFieldMetadatas": [ { "defaultValue": "", "description": "", @@ -245,6 +252,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "uniqueIdentifier": "20202020-1016-4f09-bad6-e75681f385f4", }, ], + "flatIndexMetadatas": [], "labelPlural": "Companies", "labelSingular": "Company", "namePlural": "Companies", @@ -254,9 +262,9 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "type": "create_object", }, { - "objectMetadataInput": { + "flatObjectMetadata": { "description": "A contact", - "fieldInputs": [ + "flatFieldMetadatas": [ { "defaultValue": "", "description": "", @@ -266,6 +274,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "uniqueIdentifier": "20202020-e89b-12d3-a456-426614174000", }, ], + "flatIndexMetadatas": [], "labelPlural": "Contacts", "labelSingular": "Contact", "namePlural": "Contacts", @@ -275,9 +284,9 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "type": "delete_object", }, { - "objectMetadataInput": { + "flatObjectMetadata": { "description": "A contact", - "fieldInputs": [ + "flatFieldMetadatas": [ { "defaultValue": "", "description": "", @@ -295,6 +304,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "uniqueIdentifier": "20202020-3ad3-4fec-9c46-8dc9158980e3", }, ], + "flatIndexMetadatas": [], "labelPlural": "Contacts", "labelSingular": "Contact", "namePlural": "Contacts", @@ -311,7 +321,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { ], }, { - "fieldMetadataInput": { + "flatFieldMetadata": { "defaultValue": "", "description": "", "label": "Name", @@ -319,9 +329,9 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "type": "ADDRESS", "uniqueIdentifier": "20202020-1016-4f09-bad6-e75681f385f4", }, - "objectMetadataInput": { + "flatObjectMetadata": { "description": "A company", - "fieldInputs": [ + "flatFieldMetadatas": [ { "defaultValue": "", "description": "", @@ -331,6 +341,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "uniqueIdentifier": "20202020-1016-4f09-bad6-e75681f385f4", }, ], + "flatIndexMetadatas": [], "labelPlural": "Companies", "labelSingular": "Company", "namePlural": "Companies", @@ -340,7 +351,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "type": "create_field", }, { - "fieldMetadataInput": { + "flatFieldMetadata": { "defaultValue": "", "description": "new field description", "label": "New field", @@ -348,9 +359,9 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "type": "NUMBER", "uniqueIdentifier": "20202020-3ad3-4fec-9c46-8dc9158980e3", }, - "objectMetadataInput": { + "flatObjectMetadata": { "description": "A contact", - "fieldInputs": [ + "flatFieldMetadatas": [ { "defaultValue": "", "description": "", @@ -368,6 +379,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "uniqueIdentifier": "20202020-3ad3-4fec-9c46-8dc9158980e3", }, ], + "flatIndexMetadatas": [], "labelPlural": "Contacts", "labelSingular": "Contact", "namePlural": "Contacts", @@ -382,14 +394,15 @@ describe('WorkspaceMigrationBuilderV2Service', () => { }); it('should treat objects with the same name but different IDs as distinct', () => { - const objectA: WorkspaceMigrationObjectInput = { + const objectA: FlatObjectMetadata = { uniqueIdentifier: 'id-1', + flatIndexMetadatas: [], nameSingular: 'Duplicate', namePlural: 'Duplicates', labelSingular: 'Duplicate', labelPlural: 'Duplicates', description: 'First object', - fieldInputs: [ + flatFieldMetadatas: [ { uniqueIdentifier: 'field-1', name: 'fieldA', @@ -400,14 +413,15 @@ describe('WorkspaceMigrationBuilderV2Service', () => { }, ], }; - const objectB: WorkspaceMigrationObjectInput = { + const objectB: FlatObjectMetadata = { uniqueIdentifier: 'id-2', nameSingular: 'Duplicate', namePlural: 'Duplicates', labelSingular: 'Duplicate', labelPlural: 'Duplicates', + flatIndexMetadatas: [], description: 'Second object', - fieldInputs: [ + flatFieldMetadatas: [ { uniqueIdentifier: 'field-2', name: 'fieldB', @@ -424,9 +438,9 @@ describe('WorkspaceMigrationBuilderV2Service', () => { expect(result.actions).toMatchInlineSnapshot(` [ { - "objectMetadataInput": { + "flatObjectMetadata": { "description": "First object", - "fieldInputs": [ + "flatFieldMetadatas": [ { "defaultValue": "", "description": "", @@ -436,6 +450,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "uniqueIdentifier": "field-1", }, ], + "flatIndexMetadatas": [], "labelPlural": "Duplicates", "labelSingular": "Duplicate", "namePlural": "Duplicates", @@ -445,9 +460,9 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "type": "create_object", }, { - "objectMetadataInput": { + "flatObjectMetadata": { "description": "Second object", - "fieldInputs": [ + "flatFieldMetadatas": [ { "defaultValue": "", "description": "", @@ -457,6 +472,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "uniqueIdentifier": "field-2", }, ], + "flatIndexMetadatas": [], "labelPlural": "Duplicates", "labelSingular": "Duplicate", "namePlural": "Duplicates", @@ -466,7 +482,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "type": "create_object", }, { - "fieldMetadataInput": { + "flatFieldMetadata": { "defaultValue": "", "description": "", "label": "Field A", @@ -474,9 +490,9 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "type": "FULL_NAME", "uniqueIdentifier": "field-1", }, - "objectMetadataInput": { + "flatObjectMetadata": { "description": "First object", - "fieldInputs": [ + "flatFieldMetadatas": [ { "defaultValue": "", "description": "", @@ -486,6 +502,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "uniqueIdentifier": "field-1", }, ], + "flatIndexMetadatas": [], "labelPlural": "Duplicates", "labelSingular": "Duplicate", "namePlural": "Duplicates", @@ -495,7 +512,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "type": "create_field", }, { - "fieldMetadataInput": { + "flatFieldMetadata": { "defaultValue": "", "description": "", "label": "Field B", @@ -503,9 +520,9 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "type": "ADDRESS", "uniqueIdentifier": "field-2", }, - "objectMetadataInput": { + "flatObjectMetadata": { "description": "Second object", - "fieldInputs": [ + "flatFieldMetadatas": [ { "defaultValue": "", "description": "", @@ -515,6 +532,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "uniqueIdentifier": "field-2", }, ], + "flatIndexMetadatas": [], "labelPlural": "Duplicates", "labelSingular": "Duplicate", "namePlural": "Duplicates", @@ -531,9 +549,9 @@ describe('WorkspaceMigrationBuilderV2Service', () => { expect(deleteResult.actions).toMatchInlineSnapshot(` [ { - "objectMetadataInput": { + "flatObjectMetadata": { "description": "First object", - "fieldInputs": [ + "flatFieldMetadatas": [ { "defaultValue": "", "description": "", @@ -543,6 +561,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "uniqueIdentifier": "field-1", }, ], + "flatIndexMetadatas": [], "labelPlural": "Duplicates", "labelSingular": "Duplicate", "namePlural": "Duplicates", @@ -552,9 +571,9 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "type": "delete_object", }, { - "objectMetadataInput": { + "flatObjectMetadata": { "description": "Second object", - "fieldInputs": [ + "flatFieldMetadatas": [ { "defaultValue": "", "description": "", @@ -564,6 +583,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { "uniqueIdentifier": "field-2", }, ], + "flatIndexMetadatas": [], "labelPlural": "Duplicates", "labelSingular": "Duplicate", "namePlural": "Duplicates", @@ -577,7 +597,7 @@ describe('WorkspaceMigrationBuilderV2Service', () => { }); it('should emit no actions when from and to are deeply equal', () => { - const obj: WorkspaceMigrationObjectInput = { ...baseObject }; + const obj: FlatObjectMetadata = { ...baseObject }; const result = service.build({ from: [obj], to: [obj] }); expect(result.actions).toEqual([]); diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-v2-indexes-builder.spec.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-v2-indexes-builder.spec.ts new file mode 100644 index 000000000..6e931bf0f --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-v2-indexes-builder.spec.ts @@ -0,0 +1,522 @@ +import { FieldMetadataType } from 'twenty-shared/types'; + +import { IndexType } from 'src/engine/metadata-modules/index-metadata/types/indexType.types'; +import { FlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-field-metadata'; +import { FlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-index-metadata'; +import { FlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-object-metadata'; +import { WorkspaceMigrationBuilderV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-builder-v2.service'; + +describe('Workspace migration builder indexes tests suite', () => { + let service: WorkspaceMigrationBuilderV2Service; + + beforeEach(() => { + service = new WorkspaceMigrationBuilderV2Service(); + }); + + const createMockObject = ( + identifier: string, + fields: Partial[] = [], + indexes: FlatIndexMetadata[] = [], + ): FlatObjectMetadata => ({ + uniqueIdentifier: identifier, + flatIndexMetadatas: indexes, + flatFieldMetadatas: fields.map((field) => ({ + type: FieldMetadataType.TEXT, + name: 'defaultName', + label: 'Default Label', + isCustom: true, + isActive: true, + isNullable: true, + uniqueIdentifier: 'default-id', + ...field, + })), + }); + + const createMockIndex = ( + name: string, + fields: string[], + isUnique = false, + ): FlatIndexMetadata => ({ + name, + isUnique, + indexType: IndexType.BTREE, + indexWhereClause: null, + uniqueIdentifier: name, + flatIndexFieldMetadatas: fields.map((field, index) => ({ + uniqueIdentifier: `${name}-field-${index}`, + order: index, + })), + }); + + describe('buildWorkspaceMigrationV2IndexActions', () => { + it('should create index actions for created indexes', () => { + const fromObjects: FlatObjectMetadata[] = []; + const toObjects: FlatObjectMetadata[] = [ + createMockObject( + 'company', + [ + { + type: FieldMetadataType.TEXT, + name: 'name', + label: 'Name', + uniqueIdentifier: 'name', + }, + ], + [createMockIndex('idx_company_name', ['name'], true)], + ), + ]; + + const result = service.build({ from: fromObjects, to: toObjects }); + + expect(result).toMatchInlineSnapshot(` +{ + "actions": [ + { + "flatObjectMetadata": { + "flatFieldMetadatas": [ + { + "isActive": true, + "isCustom": true, + "isNullable": true, + "label": "Name", + "name": "name", + "type": "TEXT", + "uniqueIdentifier": "name", + }, + ], + "flatIndexMetadatas": [ + { + "flatIndexFieldMetadatas": [ + { + "order": 0, + "uniqueIdentifier": "idx_company_name-field-0", + }, + ], + "indexType": "BTREE", + "indexWhereClause": null, + "isUnique": true, + "name": "idx_company_name", + "uniqueIdentifier": "idx_company_name", + }, + ], + "uniqueIdentifier": "company", + }, + "type": "create_object", + }, + { + "flatFieldMetadata": { + "isActive": true, + "isCustom": true, + "isNullable": true, + "label": "Name", + "name": "name", + "type": "TEXT", + "uniqueIdentifier": "name", + }, + "flatObjectMetadata": { + "flatFieldMetadatas": [ + { + "isActive": true, + "isCustom": true, + "isNullable": true, + "label": "Name", + "name": "name", + "type": "TEXT", + "uniqueIdentifier": "name", + }, + ], + "flatIndexMetadatas": [ + { + "flatIndexFieldMetadatas": [ + { + "order": 0, + "uniqueIdentifier": "idx_company_name-field-0", + }, + ], + "indexType": "BTREE", + "indexWhereClause": null, + "isUnique": true, + "name": "idx_company_name", + "uniqueIdentifier": "idx_company_name", + }, + ], + "uniqueIdentifier": "company", + }, + "type": "create_field", + }, + { + "flatIndexMetadata": { + "flatIndexFieldMetadatas": [ + { + "order": 0, + "uniqueIdentifier": "idx_company_name-field-0", + }, + ], + "indexType": "BTREE", + "indexWhereClause": null, + "isUnique": true, + "name": "idx_company_name", + "uniqueIdentifier": "idx_company_name", + }, + "type": "create_index", + }, + ], +} +`); + }); + + it('should create delete actions for deleted indexes', () => { + const fromObjects: FlatObjectMetadata[] = [ + createMockObject( + 'company', + [ + { + type: FieldMetadataType.TEXT, + name: 'name', + label: 'Name', + uniqueIdentifier: 'name', + }, + ], + [createMockIndex('idx_company_name', ['name'], true)], + ), + ]; + const toObjects: FlatObjectMetadata[] = [ + createMockObject('company', [ + { + type: FieldMetadataType.TEXT, + name: 'name', + label: 'Name', + uniqueIdentifier: 'name', + }, + ]), + ]; + + const result = service.build({ from: fromObjects, to: toObjects }); + + expect(result).toMatchInlineSnapshot(` +{ + "actions": [ + { + "flatIndexMetadata": { + "flatIndexFieldMetadatas": [ + { + "order": 0, + "uniqueIdentifier": "idx_company_name-field-0", + }, + ], + "indexType": "BTREE", + "indexWhereClause": null, + "isUnique": true, + "name": "idx_company_name", + "uniqueIdentifier": "idx_company_name", + }, + "type": "delete_index", + }, + ], +} +`); + }); + + it('should handle multiple index changes across different objects', () => { + const fromObjects: FlatObjectMetadata[] = [ + createMockObject( + 'company', + [ + { + type: FieldMetadataType.TEXT, + name: 'name', + label: 'Name', + uniqueIdentifier: 'name', + }, + ], + [createMockIndex('idx_company_name_old', ['name'], true)], + ), + ]; + const toObjects: FlatObjectMetadata[] = [ + createMockObject( + 'company', + [ + { + type: FieldMetadataType.TEXT, + name: 'name', + label: 'Name', + uniqueIdentifier: 'name', + }, + ], + [createMockIndex('idx_company_name_new', ['name'], true)], + ), + createMockObject( + 'person', + [ + { + type: FieldMetadataType.TEXT, + name: 'email', + label: 'Email', + uniqueIdentifier: 'email', + }, + ], + [createMockIndex('idx_person_email', ['email'], true)], + ), + ]; + + const result = service.build({ from: fromObjects, to: toObjects }); + + expect(result).toMatchInlineSnapshot(` +{ + "actions": [ + { + "flatObjectMetadata": { + "flatFieldMetadatas": [ + { + "isActive": true, + "isCustom": true, + "isNullable": true, + "label": "Email", + "name": "email", + "type": "TEXT", + "uniqueIdentifier": "email", + }, + ], + "flatIndexMetadatas": [ + { + "flatIndexFieldMetadatas": [ + { + "order": 0, + "uniqueIdentifier": "idx_person_email-field-0", + }, + ], + "indexType": "BTREE", + "indexWhereClause": null, + "isUnique": true, + "name": "idx_person_email", + "uniqueIdentifier": "idx_person_email", + }, + ], + "uniqueIdentifier": "person", + }, + "type": "create_object", + }, + { + "flatFieldMetadata": { + "isActive": true, + "isCustom": true, + "isNullable": true, + "label": "Email", + "name": "email", + "type": "TEXT", + "uniqueIdentifier": "email", + }, + "flatObjectMetadata": { + "flatFieldMetadatas": [ + { + "isActive": true, + "isCustom": true, + "isNullable": true, + "label": "Email", + "name": "email", + "type": "TEXT", + "uniqueIdentifier": "email", + }, + ], + "flatIndexMetadatas": [ + { + "flatIndexFieldMetadatas": [ + { + "order": 0, + "uniqueIdentifier": "idx_person_email-field-0", + }, + ], + "indexType": "BTREE", + "indexWhereClause": null, + "isUnique": true, + "name": "idx_person_email", + "uniqueIdentifier": "idx_person_email", + }, + ], + "uniqueIdentifier": "person", + }, + "type": "create_field", + }, + { + "flatIndexMetadata": { + "flatIndexFieldMetadatas": [ + { + "order": 0, + "uniqueIdentifier": "idx_person_email-field-0", + }, + ], + "indexType": "BTREE", + "indexWhereClause": null, + "isUnique": true, + "name": "idx_person_email", + "uniqueIdentifier": "idx_person_email", + }, + "type": "create_index", + }, + { + "flatIndexMetadata": { + "flatIndexFieldMetadatas": [ + { + "order": 0, + "uniqueIdentifier": "idx_company_name_new-field-0", + }, + ], + "indexType": "BTREE", + "indexWhereClause": null, + "isUnique": true, + "name": "idx_company_name_new", + "uniqueIdentifier": "idx_company_name_new", + }, + "type": "create_index", + }, + { + "flatIndexMetadata": { + "flatIndexFieldMetadatas": [ + { + "order": 0, + "uniqueIdentifier": "idx_company_name_old-field-0", + }, + ], + "indexType": "BTREE", + "indexWhereClause": null, + "isUnique": true, + "name": "idx_company_name_old", + "uniqueIdentifier": "idx_company_name_old", + }, + "type": "delete_index", + }, + ], +} +`); + }); + + it('should handle empty objects', () => { + const result = service.build({ from: [], to: [] }); + + expect(result).toMatchInlineSnapshot(` +{ + "actions": [], +} +`); + }); + + it('should handle objects with no index changes', () => { + const objects = [ + createMockObject('company', [ + { + type: FieldMetadataType.TEXT, + name: 'name', + label: 'Name', + uniqueIdentifier: 'name', + }, + ]), + ]; + + const result = service.build({ from: objects, to: objects }); + + expect(result).toMatchInlineSnapshot(` +{ + "actions": [], +} +`); + }); + + it('should handle index updates', () => { + const fromObjects: FlatObjectMetadata[] = [ + createMockObject( + 'company', + [ + { + type: FieldMetadataType.TEXT, + name: 'name', + label: 'Name', + uniqueIdentifier: 'name', + }, + ], + [createMockIndex('idx_company_name', ['name'], true)], + ), + ]; + + const toObjects: FlatObjectMetadata[] = [ + createMockObject( + 'company', + [ + { + type: FieldMetadataType.TEXT, + name: 'name', + label: 'Name', + uniqueIdentifier: 'name', + }, + ], + [createMockIndex('idx_company_name', ['name'], false)], + ), + ]; + + const result = service.build({ from: fromObjects, to: toObjects }); + + expect(result).toMatchInlineSnapshot(` +{ + "actions": [ + { + "flatIndexMetadata": { + "flatIndexFieldMetadatas": [ + { + "order": 0, + "uniqueIdentifier": "idx_company_name-field-0", + }, + ], + "indexType": "BTREE", + "indexWhereClause": null, + "isUnique": true, + "name": "idx_company_name", + "uniqueIdentifier": "idx_company_name", + }, + "type": "delete_index", + }, + { + "flatIndexMetadata": { + "flatIndexFieldMetadatas": [ + { + "order": 0, + "uniqueIdentifier": "idx_company_name-field-0", + }, + ], + "indexType": "BTREE", + "indexWhereClause": null, + "isUnique": false, + "name": "idx_company_name", + "uniqueIdentifier": "idx_company_name", + }, + "type": "create_index", + }, + ], +} +`); + }); + + it('should not generate any actions when indexes are identical', () => { + const objects = [ + createMockObject( + 'company', + [ + { + type: FieldMetadataType.TEXT, + name: 'name', + label: 'Name', + uniqueIdentifier: 'name', + }, + ], + [createMockIndex('idx_company_name', ['name'], true)], + ), + ]; + + const result = service.build({ from: objects, to: objects }); + + expect(result).toMatchInlineSnapshot(` +{ + "actions": [], +} +`); + }); + }); +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-v2-relations-builder.spec.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-v2-relations-builder.spec.ts index 162768b94..19e14c6b6 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-v2-relations-builder.spec.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-v2-relations-builder.spec.ts @@ -4,8 +4,8 @@ import { FieldMetadataSettings } from 'src/engine/metadata-modules/field-metadat import { RelationOnDeleteAction } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-on-delete-action.interface'; import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface'; -import { WorkspaceMigrationFieldInput } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-field-input'; -import { WorkspaceMigrationObjectInput } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-input'; +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 { WorkspaceMigrationBuilderV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-builder-v2.service'; describe('Workspace migration builder relations tests suite', () => { @@ -17,10 +17,11 @@ describe('Workspace migration builder relations tests suite', () => { const createMockObject = ( identifier: string, - fields: Partial[] = [], - ): WorkspaceMigrationObjectInput => ({ + fields: Partial[] = [], + ): FlatObjectMetadata => ({ uniqueIdentifier: identifier, - fieldInputs: fields.map((field) => ({ + flatIndexMetadatas: [], + flatFieldMetadatas: fields.map((field) => ({ type: FieldMetadataType.TEXT, name: 'defaultName', label: 'Default Label', @@ -34,8 +35,8 @@ describe('Workspace migration builder relations tests suite', () => { describe('buildWorkspaceMigrationV2RelationActions', () => { it('should create relation actions for created fields', () => { - const fromObjects: WorkspaceMigrationObjectInput[] = []; - const toObjects: WorkspaceMigrationObjectInput[] = [ + const fromObjects: FlatObjectMetadata[] = []; + const toObjects: FlatObjectMetadata[] = [ createMockObject('company', [ { type: FieldMetadataType.RELATION, @@ -54,8 +55,8 @@ describe('Workspace migration builder relations tests suite', () => { { "actions": [ { - "objectMetadataInput": { - "fieldInputs": [ + "flatObjectMetadata": { + "flatFieldMetadatas": [ { "isActive": true, "isCustom": true, @@ -68,12 +69,13 @@ describe('Workspace migration builder relations tests suite', () => { "uniqueIdentifier": "employees", }, ], + "flatIndexMetadatas": [], "uniqueIdentifier": "company", }, "type": "create_object", }, { - "fieldMetadataInput": { + "flatFieldMetadata": { "isActive": true, "isCustom": true, "isNullable": true, @@ -84,8 +86,8 @@ describe('Workspace migration builder relations tests suite', () => { "type": "RELATION", "uniqueIdentifier": "employees", }, - "objectMetadataInput": { - "fieldInputs": [ + "flatObjectMetadata": { + "flatFieldMetadatas": [ { "isActive": true, "isCustom": true, @@ -98,6 +100,7 @@ describe('Workspace migration builder relations tests suite', () => { "uniqueIdentifier": "employees", }, ], + "flatIndexMetadatas": [], "uniqueIdentifier": "company", }, "type": "create_field", @@ -108,7 +111,7 @@ describe('Workspace migration builder relations tests suite', () => { }); it('should create delete actions for deleted fields', () => { - const fromObjects: WorkspaceMigrationObjectInput[] = [ + const fromObjects: FlatObjectMetadata[] = [ createMockObject('company', [ { type: FieldMetadataType.RELATION, @@ -120,9 +123,7 @@ describe('Workspace migration builder relations tests suite', () => { }, ]), ]; - const toObjects: WorkspaceMigrationObjectInput[] = [ - createMockObject('company'), - ]; + const toObjects: FlatObjectMetadata[] = [createMockObject('company')]; const result = service.build({ from: fromObjects, to: toObjects }); @@ -130,7 +131,7 @@ describe('Workspace migration builder relations tests suite', () => { { "actions": [ { - "fieldMetadataInput": { + "flatFieldMetadata": { "isActive": true, "isCustom": true, "isNullable": true, @@ -141,8 +142,9 @@ describe('Workspace migration builder relations tests suite', () => { "type": "RELATION", "uniqueIdentifier": "employees", }, - "objectMetadataInput": { - "fieldInputs": [], + "flatObjectMetadata": { + "flatFieldMetadatas": [], + "flatIndexMetadatas": [], "uniqueIdentifier": "company", }, "type": "delete_field", @@ -153,7 +155,7 @@ describe('Workspace migration builder relations tests suite', () => { }); it('should handle multiple relation changes across different objects', () => { - const fromObjects: WorkspaceMigrationObjectInput[] = [ + const fromObjects: FlatObjectMetadata[] = [ createMockObject('company', [ { type: FieldMetadataType.RELATION, @@ -165,7 +167,7 @@ describe('Workspace migration builder relations tests suite', () => { }, ]), ]; - const toObjects: WorkspaceMigrationObjectInput[] = [ + const toObjects: FlatObjectMetadata[] = [ createMockObject('company', [ { type: FieldMetadataType.RELATION, @@ -194,8 +196,8 @@ describe('Workspace migration builder relations tests suite', () => { { "actions": [ { - "objectMetadataInput": { - "fieldInputs": [ + "flatObjectMetadata": { + "flatFieldMetadatas": [ { "isActive": true, "isCustom": true, @@ -208,12 +210,13 @@ describe('Workspace migration builder relations tests suite', () => { "uniqueIdentifier": "manager", }, ], + "flatIndexMetadatas": [], "uniqueIdentifier": "person", }, "type": "create_object", }, { - "fieldMetadataInput": { + "flatFieldMetadata": { "isActive": true, "isCustom": true, "isNullable": true, @@ -224,8 +227,8 @@ describe('Workspace migration builder relations tests suite', () => { "type": "RELATION", "uniqueIdentifier": "manager", }, - "objectMetadataInput": { - "fieldInputs": [ + "flatObjectMetadata": { + "flatFieldMetadatas": [ { "isActive": true, "isCustom": true, @@ -238,12 +241,13 @@ describe('Workspace migration builder relations tests suite', () => { "uniqueIdentifier": "manager", }, ], + "flatIndexMetadatas": [], "uniqueIdentifier": "person", }, "type": "create_field", }, { - "fieldMetadataInput": { + "flatFieldMetadata": { "isActive": true, "isCustom": true, "isNullable": true, @@ -254,8 +258,8 @@ describe('Workspace migration builder relations tests suite', () => { "type": "RELATION", "uniqueIdentifier": "new-relation", }, - "objectMetadataInput": { - "fieldInputs": [ + "flatObjectMetadata": { + "flatFieldMetadatas": [ { "isActive": true, "isCustom": true, @@ -268,12 +272,13 @@ describe('Workspace migration builder relations tests suite', () => { "uniqueIdentifier": "new-relation", }, ], + "flatIndexMetadatas": [], "uniqueIdentifier": "company", }, "type": "create_field", }, { - "fieldMetadataInput": { + "flatFieldMetadata": { "isActive": true, "isCustom": true, "isNullable": true, @@ -284,8 +289,8 @@ describe('Workspace migration builder relations tests suite', () => { "type": "RELATION", "uniqueIdentifier": "old-relation", }, - "objectMetadataInput": { - "fieldInputs": [ + "flatObjectMetadata": { + "flatFieldMetadatas": [ { "isActive": true, "isCustom": true, @@ -298,6 +303,7 @@ describe('Workspace migration builder relations tests suite', () => { "uniqueIdentifier": "new-relation", }, ], + "flatIndexMetadatas": [], "uniqueIdentifier": "company", }, "type": "delete_field", @@ -350,7 +356,7 @@ describe('Workspace migration builder relations tests suite', () => { description: 'Company employees', }; - const fromObjects: WorkspaceMigrationObjectInput[] = [ + const fromObjects: FlatObjectMetadata[] = [ createMockObject('company', [ { ...baseField, @@ -364,10 +370,10 @@ describe('Workspace migration builder relations tests suite', () => { ]), ]; - const toObjects: WorkspaceMigrationObjectInput[] = [ + const toObjects: FlatObjectMetadata[] = [ { ...fromObjects[0], - fieldInputs: [ + flatFieldMetadatas: [ { ...baseField, name: 'updatedName', @@ -382,7 +388,7 @@ describe('Workspace migration builder relations tests suite', () => { { "actions": [ { - "fieldMetadataInput": { + "flatFieldMetadata": { "description": "Company employees", "isActive": true, "isCustom": true, @@ -392,8 +398,8 @@ describe('Workspace migration builder relations tests suite', () => { "type": "RELATION", "uniqueIdentifier": "employees", }, - "objectMetadataInput": { - "fieldInputs": [ + "flatObjectMetadata": { + "flatFieldMetadatas": [ { "description": "Company employees", "isActive": true, @@ -405,6 +411,7 @@ describe('Workspace migration builder relations tests suite', () => { "uniqueIdentifier": "employees", }, ], + "flatIndexMetadatas": [], "uniqueIdentifier": "company", }, "type": "update_field", diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-action-common-v2.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-action-common-v2.ts new file mode 100644 index 000000000..2f9ec8d93 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-action-common-v2.ts @@ -0,0 +1,10 @@ +import { WorkspaceMigrationFieldActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2'; +import { WorkspaceMigrationIndexActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-index-action-v2'; +import { WorkspaceMigrationObjectActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2'; + +export type WorkspaceMigrationActionV2 = + | WorkspaceMigrationObjectActionV2 + | WorkspaceMigrationFieldActionV2 + | WorkspaceMigrationIndexActionV2; + +export type WorkspaceMigrationActionTypeV2 = WorkspaceMigrationActionV2['type']; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-field-action-v2.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2.ts similarity index 57% rename from packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-field-action-v2.ts rename to packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2.ts index 1191b6c28..136d72974 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-field-action-v2.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2.ts @@ -1,14 +1,12 @@ 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 { 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 { - FieldMetadataEntityEditableProperties, - WorkspaceMigrationFieldInput, -} from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-field-input'; -import { WorkspaceMigrationObjectWithoutFields } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-input'; +import { FlatFieldMetadataPropertiesToCompare } from 'src/engine/workspace-manager/workspace-migration-v2/utils/flat-field-metadata-comparator.util'; export type FieldAndObjectMetadataWorkspaceMigrationInput = { - fieldMetadataInput: WorkspaceMigrationFieldInput; - objectMetadataInput: WorkspaceMigrationObjectWithoutFields; + flatFieldMetadata: FlatFieldMetadata; + flatObjectMetadata: FlatObjectMetadataWithoutFields; }; export type CreateFieldAction = { type: 'create_field'; @@ -18,10 +16,10 @@ export type UpdateFieldAction = { type: 'update_field'; updates: Partial< { - [P in FieldMetadataEntityEditableProperties]: { + [P in FlatFieldMetadataPropertiesToCompare]: { property: P; } & FromTo; - }[FieldMetadataEntityEditableProperties] + }[FlatFieldMetadataPropertiesToCompare] >[]; } & FieldAndObjectMetadataWorkspaceMigrationInput; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-index-action-v2.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-index-action-v2.ts similarity index 52% rename from packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-index-action-v2.ts rename to packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-index-action-v2.ts index 9f364e154..d6992864e 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-index-action-v2.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-index-action-v2.ts @@ -1,9 +1,13 @@ +import { FlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-index-metadata'; + export type CreateIndexAction = { type: 'create_index'; + flatIndexMetadata: FlatIndexMetadata; }; export type DeleteIndexAction = { type: 'delete_index'; + flatIndexMetadata: FlatIndexMetadata; }; export type WorkspaceMigrationIndexActionV2 = diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-action-v2.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2.ts similarity index 57% rename from packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-action-v2.ts rename to packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2.ts index 9226f6eae..b3b29d23c 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-action-v2.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2.ts @@ -1,12 +1,10 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +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 { - ObjectMetadataEntityEditableProperties, - WorkspaceMigrationObjectWithoutFields, -} from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-input'; +import { FlatObjectMetadataPropertiesToCompare } from 'src/engine/workspace-manager/workspace-migration-v2/utils/flat-object-metadata-comparator.util'; type ObjectActionCommon = { - objectMetadataInput: WorkspaceMigrationObjectWithoutFields; + flatObjectMetadata: FlatObjectMetadataWithoutFields; }; export type CreateObjectAction = { type: 'create_object'; @@ -16,10 +14,10 @@ export type UpdateObjectAction = { type: 'update_object'; updates: Partial< { - [P in ObjectMetadataEntityEditableProperties]: { + [P in FlatObjectMetadataPropertiesToCompare]: { property: P; } & FromTo; - }[ObjectMetadataEntityEditableProperties] + }[FlatObjectMetadataPropertiesToCompare] >[]; } & ObjectActionCommon; @@ -27,7 +25,7 @@ export type DeleteObjectAction = { type: 'delete_object'; } & ObjectActionCommon; -export type WorkspaceMigrationV2ObjectAction = +export type WorkspaceMigrationObjectActionV2 = | CreateObjectAction | UpdateObjectAction | DeleteObjectAction; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-v2.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-v2.ts similarity index 76% rename from packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-v2.ts rename to packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-v2.ts index 6a6d3cfd1..f69717e78 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-v2.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-v2.ts @@ -1,4 +1,4 @@ -import { WorkspaceMigrationActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-action-common-v2'; +import { WorkspaceMigrationActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-action-common-v2'; export type WorkspaceMigrationV2< TActions extends WorkspaceMigrationActionV2 = WorkspaceMigrationActionV2, diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/compute-updated-object-metadata-deleted-created-updated-field-matrix.util.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/compute-updated-object-metadata-deleted-created-updated-field-matrix.util.ts index 593472a6d..8c1efce6f 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/compute-updated-object-metadata-deleted-created-updated-field-matrix.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/compute-updated-object-metadata-deleted-created-updated-field-matrix.util.ts @@ -1,35 +1,32 @@ -import { FromTo } from 'src/engine/workspace-manager/workspace-migration-v2/types/from-to.type'; -import { WorkspaceMigrationFieldInput } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-field-input'; +import { FlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-field-metadata'; import { - WorkspaceMigrationObjectInput, - WorkspaceMigrationObjectWithoutFields, -} from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-input'; + 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 { CustomDeletedCreatedUpdatedMatrix, deletedCreatedUpdatedMatrixDispatcher, -} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-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 = { - objectMetadataInput: WorkspaceMigrationObjectWithoutFields; -} & CustomDeletedCreatedUpdatedMatrix< - 'fieldMetadata', - WorkspaceMigrationFieldInput ->; + flatObjectMetadata: FlatObjectMetadataWithoutFields; +} & CustomDeletedCreatedUpdatedMatrix<'fieldMetadata', FlatFieldMetadata>; export const computeUpdatedObjectMetadataDeletedCreatedUpdatedFieldMatrix = ( - updatedObjectMetadata: FromTo[], + updatedObjectMetadata: FromTo[], ): UpdatedObjectMetadataDeletedCreatedUpdatedFieldMatrix[] => { const matrixAccumulator: UpdatedObjectMetadataDeletedCreatedUpdatedFieldMatrix[] = []; for (const { from, to } of updatedObjectMetadata) { const fieldMetadataMatrix = deletedCreatedUpdatedMatrixDispatcher({ - from: from.fieldInputs, - to: to.fieldInputs, + from: from.flatFieldMetadatas, + to: to.flatFieldMetadatas, }); matrixAccumulator.push({ - objectMetadataInput: to, + flatObjectMetadata: to, createdFieldMetadata: fieldMetadataMatrix.created, deletedFieldMetadata: fieldMetadataMatrix.deleted, updatedFieldMetadata: fieldMetadataMatrix.updated, diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/compute-updated-object-metadata-deleted-created-updated-index-matrix.util.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/compute-updated-object-metadata-deleted-created-updated-index-matrix.util.ts new file mode 100644 index 000000000..e600975a1 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/compute-updated-object-metadata-deleted-created-updated-index-matrix.util.ts @@ -0,0 +1,37 @@ +import { FlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-index-metadata'; +import { + 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 { + CustomDeletedCreatedUpdatedMatrix, + deletedCreatedUpdatedMatrixDispatcher, +} from 'src/engine/workspace-manager/workspace-migration-v2/utils/deleted-created-updated-matrix-dispatcher.util'; + +export type UpdatedObjectMetadataDeletedCreatedUpdatedIndexMatrix = { + flatObjectMetadata: FlatObjectMetadataWithoutFields; +} & CustomDeletedCreatedUpdatedMatrix<'indexMetadata', FlatIndexMetadata>; + +export const computeUpdatedObjectMetadataDeletedCreatedUpdatedIndexMatrix = ( + updatedObjectMetadata: FromTo[], +): UpdatedObjectMetadataDeletedCreatedUpdatedIndexMatrix[] => { + const matrixAccumulator: UpdatedObjectMetadataDeletedCreatedUpdatedIndexMatrix[] = + []; + + for (const { from, to } of updatedObjectMetadata) { + const indexMetadataMatrix = deletedCreatedUpdatedMatrixDispatcher({ + from: from.flatIndexMetadatas, + to: to.flatIndexMetadatas, + }); + + matrixAccumulator.push({ + flatObjectMetadata: to, + createdIndexMetadata: indexMetadataMatrix.created, + deletedIndexMetadata: indexMetadataMatrix.deleted, + updatedIndexMetadata: indexMetadataMatrix.updated, + }); + } + + return matrixAccumulator; +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-field-actions.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-field-actions.ts index 1bc919f53..361895784 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-field-actions.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-field-actions.ts @@ -2,22 +2,22 @@ import { CreateFieldAction, DeleteFieldAction, FieldAndObjectMetadataWorkspaceMigrationInput, -} from 'src/engine/workspace-manager/workspace-migration-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'; export const getWorkspaceMigrationV2FieldCreateAction = ({ - fieldMetadataInput, - objectMetadataInput, + flatFieldMetadata, + flatObjectMetadata, }: FieldAndObjectMetadataWorkspaceMigrationInput): CreateFieldAction => ({ type: 'create_field', - fieldMetadataInput, - objectMetadataInput, + flatFieldMetadata, + flatObjectMetadata, }); export const getWorkspaceMigrationV2FieldDeleteAction = ({ - fieldMetadataInput, - objectMetadataInput, + flatFieldMetadata, + flatObjectMetadata, }: FieldAndObjectMetadataWorkspaceMigrationInput): DeleteFieldAction => ({ type: 'delete_field', - fieldMetadataInput, - objectMetadataInput, + flatFieldMetadata, + flatObjectMetadata, }); diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-index-actions.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-index-actions.ts new file mode 100644 index 000000000..849888cc5 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-index-actions.ts @@ -0,0 +1,19 @@ +import { FlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-index-metadata'; +import { + CreateIndexAction, + DeleteIndexAction, +} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-index-action-v2'; + +export const getWorkspaceMigrationV2CreateIndexAction = ( + flatIndexMetadata: FlatIndexMetadata, +): CreateIndexAction => ({ + type: 'create_index', + flatIndexMetadata, +}); + +export const getWorkspaceMigrationV2DeleteIndexAction = ( + flatIndexMetadata: FlatIndexMetadata, +): DeleteIndexAction => ({ + type: 'delete_index', + flatIndexMetadata, +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-object-actions.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-object-actions.ts index dd3668fef..c1e131a64 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-object-actions.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-object-actions.ts @@ -1,19 +1,19 @@ +import { FlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-object-metadata'; import { CreateObjectAction, DeleteObjectAction, -} from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-action-v2'; -import { WorkspaceMigrationObjectInput } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-input'; +} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2'; export const getWorkspaceMigrationV2ObjectCreateAction = ( - objectMetadataInput: WorkspaceMigrationObjectInput, + flatObjectMetadata: FlatObjectMetadata, ): CreateObjectAction => ({ type: 'create_object', - objectMetadataInput, + flatObjectMetadata, }); export const getWorkspaceMigrationV2ObjectDeleteAction = ( - objectMetadataInput: WorkspaceMigrationObjectInput, + flatObjectMetadata: FlatObjectMetadata, ): DeleteObjectAction => ({ type: 'delete_object', - objectMetadataInput, + flatObjectMetadata, }); diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/workspace-migration-field-metadata-input-comparator.util.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/workspace-migration-field-metadata-input-comparator.util.ts deleted file mode 100644 index 3988fb434..000000000 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/workspace-migration-field-metadata-input-comparator.util.ts +++ /dev/null @@ -1,101 +0,0 @@ -import diff from 'microdiff'; -import { FieldMetadataType } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; - -import { FromTo } from 'src/engine/workspace-manager/workspace-migration-v2/types/from-to.type'; -import { UpdateFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-field-action-v2'; -import { - FieldMetadataEntityEditableProperties, - WorkspaceMigrationFieldInput, - fieldMetadataEntityEditableProperties, - fieldMetadataPropertiesToStringify, -} from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-field-input'; -import { transformMetadataForComparison } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util'; - -const shouldNotOverrideDefaultValue = (type: FieldMetadataType) => { - return [ - FieldMetadataType.BOOLEAN, - FieldMetadataType.SELECT, - FieldMetadataType.MULTI_SELECT, - FieldMetadataType.CURRENCY, - FieldMetadataType.PHONES, - FieldMetadataType.ADDRESS, - ].includes(type); -}; - -const compareTwoWorkspaceMigrationFieldInput = ({ - from, - to, -}: FromTo) => { - const compareFieldMetadataOptions = { - shouldIgnoreProperty: ( - property: string, - fieldMetadata: WorkspaceMigrationFieldInput, - ) => { - if ( - !fieldMetadataEntityEditableProperties.includes( - property as FieldMetadataEntityEditableProperties, - ) - ) { - return true; - } - - if ( - property === 'defaultValue' && - isDefined(fieldMetadata.type) && - shouldNotOverrideDefaultValue(fieldMetadata.type) - ) { - return true; - } - - return false; - }, - propertiesToStringify: fieldMetadataPropertiesToStringify, - }; - const fromCompare = transformMetadataForComparison( - from, - compareFieldMetadataOptions, - ); - const toCompare = transformMetadataForComparison( - to, - compareFieldMetadataOptions, - ); - - const fieldMetadataDifference = diff(fromCompare, toCompare); - - return fieldMetadataDifference; -}; - -type GetWorkspaceMigrationUpdateFieldActionArgs = - FromTo; -export const compareFieldMetadataInputAndGetUpdateFieldActions = ({ - from, - to, -}: GetWorkspaceMigrationUpdateFieldActionArgs) => { - const fieldMetadataDifferences = compareTwoWorkspaceMigrationFieldInput({ - from, - to, - }); - - return fieldMetadataDifferences.flatMap( - (difference) => { - switch (difference.type) { - case 'CHANGE': { - const { oldValue, path, value } = difference; - - return { - from: oldValue, - to: value, - property: path[0] as FieldMetadataEntityEditableProperties, - }; - } - case 'CREATE': - case 'REMOVE': - default: { - // Should never occurs, we should only provide null never undefined and so on - return []; - } - } - }, - ); -}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-builder-v2.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-builder-v2.service.ts index b2feef6bd..f83a53a59 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-builder-v2.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-builder-v2.service.ts @@ -1,19 +1,22 @@ import { Injectable } from '@nestjs/common'; +import { FlatObjectMetadata } 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 { WorkspaceMigrationObjectInput } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-input'; -import { WorkspaceMigrationV2 } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-v2'; +import { deletedCreatedUpdatedMatrixDispatcher } from 'src/engine/workspace-manager/workspace-migration-v2/utils/deleted-created-updated-matrix-dispatcher.util'; +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 { deletedCreatedUpdatedMatrixDispatcher } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/deleted-created-updated-matrix-dispatcher.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 { 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 { buildWorkspaceMigrationIndexActions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-index-actions-builder'; import { buildWorkspaceMigrationV2ObjectActions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-object-actions-builder'; @Injectable() export class WorkspaceMigrationBuilderV2Service { constructor() {} build( - objectMetadataFromToInputs: FromTo, + objectMetadataFromToInputs: FromTo, ): WorkspaceMigrationV2 { const { created: createdObjectMetadata, @@ -29,30 +32,47 @@ export class WorkspaceMigrationBuilderV2Service { }); const createdObjectWorkspaceMigrationCreateFieldActions = - createdObjectMetadata.flatMap((objectMetadataInput) => - objectMetadataInput.fieldInputs.map((fieldMetadataInput) => + createdObjectMetadata.flatMap((flatObjectMetadata) => + flatObjectMetadata.flatFieldMetadatas.map((flatFieldMetadata) => getWorkspaceMigrationV2FieldCreateAction({ - fieldMetadataInput, - objectMetadataInput, + flatFieldMetadata, + flatObjectMetadata, }), ), ); - const updatedObjectMetadataFieldAndRelationDeletedCreatedUpdatedMatrix = + const createdObjectMetadataCreateIndexActions = + createdObjectMetadata.flatMap((objectMetadata) => + objectMetadata.flatIndexMetadatas.map( + getWorkspaceMigrationV2CreateIndexAction, + ), + ); + + const updatedObjectMetadataDeletedCreatedUpdatedFieldMatrix = computeUpdatedObjectMetadataDeletedCreatedUpdatedFieldMatrix( updatedObjectMetadata, ); const fieldWorkspaceMigrationActions = buildWorkspaceMigrationV2FieldActions( - updatedObjectMetadataFieldAndRelationDeletedCreatedUpdatedMatrix, + updatedObjectMetadataDeletedCreatedUpdatedFieldMatrix, ); + const updatedObjectMetadataIndexDeletedCreatedUpdatedMatrix = + computeUpdatedObjectMetadataDeletedCreatedUpdatedIndexMatrix( + updatedObjectMetadata, + ); + const indexWorkspaceMigrationActions = buildWorkspaceMigrationIndexActions( + updatedObjectMetadataIndexDeletedCreatedUpdatedMatrix, + ); + return { actions: [ ...objectWorkspaceMigrationActions, ...createdObjectWorkspaceMigrationCreateFieldActions, + ...createdObjectMetadataCreateIndexActions, ...fieldWorkspaceMigrationActions, + ...indexWorkspaceMigrationActions, ], }; } diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-field-actions-builder.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-field-actions-builder.ts index e6b591c8a..5053a8c90 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-field-actions-builder.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-field-actions-builder.ts @@ -1,13 +1,13 @@ +import { compareTwoFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/utils/flat-field-metadata-comparator.util'; import { UpdateFieldAction, WorkspaceMigrationFieldActionV2, -} from 'src/engine/workspace-manager/workspace-migration-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 { getWorkspaceMigrationV2FieldCreateAction, getWorkspaceMigrationV2FieldDeleteAction, } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-field-actions'; -import { compareFieldMetadataInputAndGetUpdateFieldActions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/workspace-migration-field-metadata-input-comparator.util'; export const buildWorkspaceMigrationV2FieldActions = ( objectMetadataDeletedCreatedUpdatedFields: UpdatedObjectMetadataDeletedCreatedUpdatedFieldMatrix[], @@ -19,11 +19,11 @@ export const buildWorkspaceMigrationV2FieldActions = ( createdFieldMetadata, deletedFieldMetadata, updatedFieldMetadata, - objectMetadataInput, + flatObjectMetadata, } of objectMetadataDeletedCreatedUpdatedFields) { const updateFieldActions = updatedFieldMetadata.flatMap( ({ from, to }) => { - const updates = compareFieldMetadataInputAndGetUpdateFieldActions({ + const updates = compareTwoFlatFieldMetadata({ from, to, }); @@ -34,24 +34,24 @@ export const buildWorkspaceMigrationV2FieldActions = ( return { type: 'update_field', - fieldMetadataInput: to, - objectMetadataInput, + flatFieldMetadata: to, + flatObjectMetadata, updates, }; }, ); - const createFieldAction = createdFieldMetadata.map((fieldMetadataInput) => + const createFieldAction = createdFieldMetadata.map((flatFieldMetadata) => getWorkspaceMigrationV2FieldCreateAction({ - fieldMetadataInput, - objectMetadataInput, + flatFieldMetadata, + flatObjectMetadata, }), ); - const deleteFieldAction = deletedFieldMetadata.map((fieldMetadataInput) => + const deleteFieldAction = deletedFieldMetadata.map((flatFieldMetadata) => getWorkspaceMigrationV2FieldDeleteAction({ - fieldMetadataInput, - objectMetadataInput, + flatFieldMetadata, + flatObjectMetadata, }), ); diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-index-actions-builder.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-index-actions-builder.ts new file mode 100644 index 000000000..ebc16fa99 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-index-actions-builder.ts @@ -0,0 +1,52 @@ +import { compareTwoFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/utils/flat-index-metadata-comparator.util'; +import { WorkspaceMigrationIndexActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-index-action-v2'; +import { UpdatedObjectMetadataDeletedCreatedUpdatedIndexMatrix } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/compute-updated-object-metadata-deleted-created-updated-index-matrix.util'; +import { + getWorkspaceMigrationV2CreateIndexAction, + getWorkspaceMigrationV2DeleteIndexAction, +} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-index-actions'; + +export const buildWorkspaceMigrationIndexActions = ( + objectMetadataDeletedCreatedUpdatedIndex: UpdatedObjectMetadataDeletedCreatedUpdatedIndexMatrix[], +): WorkspaceMigrationIndexActionV2[] => { + let allUpdatedObjectMetadataIndexActions: WorkspaceMigrationIndexActionV2[] = + []; + + for (const { + createdIndexMetadata, + deletedIndexMetadata, + updatedIndexMetadata, + } of objectMetadataDeletedCreatedUpdatedIndex) { + const updatedDeleteAndCreateIndexActions = + updatedIndexMetadata.flatMap( + ({ to, from }) => { + const updates = compareTwoFlatIndexMetadata({ from, to }); + + if (updates.length === 0) { + return []; + } + + return [ + getWorkspaceMigrationV2DeleteIndexAction(from), + getWorkspaceMigrationV2CreateIndexAction(to), + ]; + }, + ); + + const createIndexActions = createdIndexMetadata.map( + getWorkspaceMigrationV2CreateIndexAction, + ); + const deleteIndexActions = deletedIndexMetadata.map( + getWorkspaceMigrationV2DeleteIndexAction, + ); + + allUpdatedObjectMetadataIndexActions = + allUpdatedObjectMetadataIndexActions.concat([ + ...createIndexActions, + ...deleteIndexActions, + ...updatedDeleteAndCreateIndexActions, + ]); + } + + return allUpdatedObjectMetadataIndexActions; +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-object-actions-builder.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-object-actions-builder.ts index f83990d8a..12047262c 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-object-actions-builder.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-object-actions-builder.ts @@ -1,25 +1,22 @@ +import { FlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-object-metadata'; +import { CustomDeletedCreatedUpdatedMatrix } from 'src/engine/workspace-manager/workspace-migration-v2/utils/deleted-created-updated-matrix-dispatcher.util'; +import { compareTwoFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/utils/flat-object-metadata-comparator.util'; import { UpdateObjectAction, - WorkspaceMigrationV2ObjectAction, -} from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-action-v2'; -import { WorkspaceMigrationObjectInput } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-object-input'; -import { CustomDeletedCreatedUpdatedMatrix } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/deleted-created-updated-matrix-dispatcher.util'; + WorkspaceMigrationObjectActionV2, +} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2'; import { getWorkspaceMigrationV2ObjectCreateAction, getWorkspaceMigrationV2ObjectDeleteAction, } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-object-actions'; -import { compareTwoWorkspaceMigrationObjectInput } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/workspace-migration-object-metadata-input-comparator.util'; export type CreatedDeletedUpdatedObjectMetadataInputMatrix = - CustomDeletedCreatedUpdatedMatrix< - 'objectMetadata', - WorkspaceMigrationObjectInput - >; + CustomDeletedCreatedUpdatedMatrix<'objectMetadata', FlatObjectMetadata>; export const buildWorkspaceMigrationV2ObjectActions = ({ createdObjectMetadata, deletedObjectMetadata, updatedObjectMetadata, -}: CreatedDeletedUpdatedObjectMetadataInputMatrix): WorkspaceMigrationV2ObjectAction[] => { +}: CreatedDeletedUpdatedObjectMetadataInputMatrix): WorkspaceMigrationObjectActionV2[] => { const createdObjectActions = createdObjectMetadata.map( getWorkspaceMigrationV2ObjectCreateAction, ); @@ -30,7 +27,7 @@ export const buildWorkspaceMigrationV2ObjectActions = ({ const updatedObjectActions = updatedObjectMetadata.flatMap(({ from, to }) => { - const objectUpdatedProperties = compareTwoWorkspaceMigrationObjectInput({ + const objectUpdatedProperties = compareTwoFlatObjectMetadata({ from, to, }); @@ -41,7 +38,7 @@ export const buildWorkspaceMigrationV2ObjectActions = ({ return { type: 'update_object', - objectMetadataInput: to, + flatObjectMetadata: to, updates: objectUpdatedProperties, }; });