diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-field-metadata.mock.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-field-metadata.mock.ts new file mode 100644 index 000000000..781fea151 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-field-metadata.mock.ts @@ -0,0 +1,54 @@ +import { faker } from '@faker-js/faker'; +import { FieldMetadataType } from 'twenty-shared/types'; + +import { FlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-field-metadata'; + +type FlatFieldMetadataOverrides< + T extends FieldMetadataType = FieldMetadataType, +> = Required< + Pick, 'uniqueIdentifier' | 'objectMetadataId'> +> & + Partial>; + +export const getFlatFieldMetadataMock = < + T extends FieldMetadataType = FieldMetadataType, +>( + overrides: FlatFieldMetadataOverrides, +): FlatFieldMetadata => { + const createdAt = faker.date.anytime(); + + return { + createdAt, + description: 'default flat field metadata description', + icon: 'icon', + id: faker.string.uuid(), + isActive: true, + isCustom: true, + name: 'flatFieldMetadataName', + label: 'flat field metadata label', + isNullable: true, + isUnique: false, + relationTargetFieldMetadataId: undefined, + relationTargetObjectMetadataId: undefined, + type: FieldMetadataType.TEXT as T, + isLabelSyncedWithName: false, + isSystem: false, + standardId: undefined, + standardOverrides: undefined, + updatedAt: createdAt, + workspaceId: faker.string.uuid(), + ...overrides, + }; +}; + +export const getStandardFlatFieldMetadataMock = ( + overrides: Omit, +) => { + return getFlatFieldMetadataMock({ + standardId: faker.string.uuid(), + standardOverrides: {}, + isCustom: false, + isSystem: true, + ...overrides, + }); +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-index-field-metadata.mock.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-index-field-metadata.mock.ts new file mode 100644 index 000000000..31f388ec1 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-index-field-metadata.mock.ts @@ -0,0 +1,24 @@ +import { faker } from '@faker-js/faker'; + +import { FlatIndexFieldMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-index-field-metadata'; + +type FlatIndexFieldMetadataOverrides = Required< + Pick< + FlatIndexFieldMetadata, + 'fieldMetadataId' | 'indexMetadataId' | 'uniqueIdentifier' + > +> & + Partial; +export const getFlatIndexFieldMetadataMock = ( + overrides: FlatIndexFieldMetadataOverrides, +): FlatIndexFieldMetadata => { + const createdAt = faker.date.anytime(); + + return { + createdAt, + id: faker.string.uuid(), + order: faker.number.int(), + updatedAt: createdAt, + ...overrides, + }; +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-index-metadata.mock.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-index-metadata.mock.ts new file mode 100644 index 000000000..13ae038a1 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-index-metadata.mock.ts @@ -0,0 +1,37 @@ +import { faker } from '@faker-js/faker'; + +import { IndexType } from 'src/engine/metadata-modules/index-metadata/types/indexType.types'; +import { FlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-index-metadata'; + +type FlatIndexMetadataOverrides = Required< + Pick +> & + Partial; +export const getFlatIndexMetadataMock = ( + overrides: FlatIndexMetadataOverrides, +): FlatIndexMetadata => { + const createdAt = faker.date.anytime(); + + return { + flatIndexFieldMetadatas: [], + createdAt, + id: faker.string.uuid(), + indexType: IndexType.BTREE, + indexWhereClause: undefined, + isCustom: false, + isUnique: false, + name: 'defaultFlatIndexMetadataName', + updatedAt: createdAt, + workspaceId: faker.string.uuid(), + ...overrides, + }; +}; + +export const getStandardFlatIndexMetadataMock = ( + overrides: Omit, +) => { + return getFlatIndexMetadataMock({ + isCustom: false, + ...overrides, + }); +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-object-metadata.mock.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-object-metadata.mock.ts new file mode 100644 index 000000000..064236202 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-object-metadata.mock.ts @@ -0,0 +1,56 @@ +import { faker } from '@faker-js/faker'; + +import { FlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-object-metadata'; + +type FlatObjectMetadataOverrides = Required< + Pick +> & + Partial; +export const getFlatObjectMetadataMock = ( + overrides: FlatObjectMetadataOverrides, +): FlatObjectMetadata => { + const createdAt = faker.date.anytime(); + + return { + flatFieldMetadatas: [], + flatIndexMetadatas: [], + createdAt, + dataSourceId: faker.string.uuid(), + description: 'default flat object metadata description', + duplicateCriteria: [], + icon: 'icon', + id: faker.string.uuid(), + imageIdentifierFieldMetadataId: faker.string.uuid(), + isActive: true, + isAuditLogged: true, + isCustom: true, + isLabelSyncedWithName: false, + isRemote: false, + isSearchable: true, + isSystem: false, + labelIdentifierFieldMetadataId: faker.string.uuid(), + labelPlural: 'default flat object metadata label plural', + labelSingular: 'default flat object metadata label singular', + namePlural: 'defaultflatObjectMetadataNamePlural', + nameSingular: 'defaultflatObjectMetadataNameSingular', + shortcut: 'shortcut', + standardId: undefined, + standardOverrides: undefined, + targetTableName: '', + updatedAt: createdAt, + workspaceId: faker.string.uuid(), + ...overrides, + }; +}; + +export const getStandardFlatObjectMetadataMock = ( + overrides: Omit, +) => { + return getFlatObjectMetadataMock({ + standardId: faker.string.uuid(), + standardOverrides: {}, + isCustom: false, + isSystem: true, + ...overrides, + }); +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type.ts new file mode 100644 index 000000000..85bae9824 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type.ts @@ -0,0 +1,12 @@ +import { Relation } from 'typeorm'; + +export type ExtractRecordTypeOrmRelationProperties = + NonNullable< + { + [P in keyof T]: T[P] extends Relation< + TRelationTargets | TRelationTargets[] + > + ? P + : never; + }[keyof T] + >; 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 index 14b5240fc..55919e45d 100644 --- 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 @@ -1,7 +1,18 @@ -import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { FieldMetadataType } from 'twenty-shared/types'; -export type FlatFieldMetadata = Partial< - Omit -> & { - uniqueIdentifier: string; -}; +import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { ExtractRecordTypeOrmRelationProperties } from 'src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type'; +import { MetadataEntitiesRelationTarget } from 'src/engine/workspace-manager/workspace-migration-v2/types/metadata-entities-relation-targets.type'; + +type FieldMetadataEntityRelationProperties = + ExtractRecordTypeOrmRelationProperties< + FieldMetadataEntity, + MetadataEntitiesRelationTarget + >; + +export type FlatFieldMetadata = + Partial< + Omit, FieldMetadataEntityRelationProperties> + > & { + 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 index c25f813a6..5e42b9375 100644 --- 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 @@ -1,15 +1,15 @@ import { IndexFieldMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-field-metadata.entity'; +import { ExtractRecordTypeOrmRelationProperties } from 'src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type'; +import { MetadataEntitiesRelationTarget } from 'src/engine/workspace-manager/workspace-migration-v2/types/metadata-entities-relation-targets.type'; -const indexFieldMetadataEntityRelationProperties = [ - 'indexMetadata', - 'fieldMetadata', -] as const satisfies (keyof IndexFieldMetadataEntity)[]; - -type IndexFieldMetadataRelationProperties = - (typeof indexFieldMetadataEntityRelationProperties)[number]; +type IndexFieldMetadataEntityRelationProperties = + ExtractRecordTypeOrmRelationProperties< + IndexFieldMetadataEntity, + MetadataEntitiesRelationTarget + >; export type FlatIndexFieldMetadata = Partial< - Omit + 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 index b1ceb87b9..7ca51797c 100644 --- 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 @@ -1,8 +1,15 @@ import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; +import { ExtractRecordTypeOrmRelationProperties } from 'src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type'; import { FlatIndexFieldMetadata } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-index-field-metadata'; +import { MetadataEntitiesRelationTarget } from 'src/engine/workspace-manager/workspace-migration-v2/types/metadata-entities-relation-targets.type'; + +type IndexMetadataRelationProperties = ExtractRecordTypeOrmRelationProperties< + IndexMetadataEntity, + MetadataEntitiesRelationTarget +>; export type FlatIndexMetadata = Partial< - Omit // Might have an issue as ObjectMetadataId != uniqueIdentifier + Omit > & { 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 index 9d29ef339..f1bf9d213 100644 --- 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 @@ -1,9 +1,16 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { ExtractRecordTypeOrmRelationProperties } from 'src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type'; 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 { MetadataEntitiesRelationTarget } from 'src/engine/workspace-manager/workspace-migration-v2/types/metadata-entities-relation-targets.type'; + +type ObjectMetadataRelationProperties = ExtractRecordTypeOrmRelationProperties< + ObjectMetadataEntity, + MetadataEntitiesRelationTarget +>; export type FlatObjectMetadata = Partial< - Omit + Omit > & { uniqueIdentifier: string; flatIndexMetadatas: FlatIndexMetadata[]; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/metadata-entities-relation-targets.type.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/metadata-entities-relation-targets.type.ts new file mode 100644 index 000000000..e6b983437 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/metadata-entities-relation-targets.type.ts @@ -0,0 +1,10 @@ +import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { IndexFieldMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-field-metadata.entity'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { FieldPermissionEntity } from 'src/engine/metadata-modules/object-permission/field-permission/field-permission.entity'; + +export type MetadataEntitiesRelationTarget = + | ObjectMetadataEntity + | FieldMetadataEntity + | IndexFieldMetadataEntity + | FieldPermissionEntity; 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 index 2687d691e..3078c5bb1 100644 --- 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 @@ -2,6 +2,7 @@ import diff from 'microdiff'; import { FieldMetadataType } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; +import { isRelationFieldMetadataType } from 'src/engine/utils/is-relation-field-metadata-type.util'; 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'; @@ -18,6 +19,11 @@ const flatFieldMetadataPropertiesToCompare = [ 'name', 'options', 'standardOverrides', + 'settings', + // To reactivate once we authorize relation edition, see https://github.com/twentyhq/twenty/commit/39f6f3c4bb101272a9014e142a842d0801a3c33b + // 'relationTargetFieldMetadataId', + // 'relationTargetObjectMetadataId', + /// ] as const satisfies (keyof FlatFieldMetadata)[]; export type FlatFieldMetadataPropertiesToCompare = @@ -26,6 +32,7 @@ export type FlatFieldMetadataPropertiesToCompare = const fieldMetadataPropertiesToStringify = [ 'defaultValue', 'standardOverrides', + 'settings', ] as const satisfies FlatFieldMetadataPropertiesToCompare[]; const shouldNotOverrideDefaultValue = (type: FieldMetadataType) => { @@ -65,6 +72,15 @@ export const compareTwoFlatFieldMetadata = ({ return true; } + // Remove below assertion when we authorize relation edition, see https://github.com/twentyhq/twenty/commit/39f6f3c4bb101272a9014e142a842d0801a3c33b + if ( + isDefined(fieldMetadata.type) && + isRelationFieldMetadataType(fieldMetadata.type) && + !['label', 'description', 'isActive'].includes(property) + ) { + return true; + } + return false; }, propertiesToStringify: fieldMetadataPropertiesToStringify, diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/__snapshots__/workspace-migration-builder.spec.ts.snap b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/__snapshots__/workspace-migration-builder.spec.ts.snap new file mode 100644 index 000000000..4b1bbe25c --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/__snapshots__/workspace-migration-builder.spec.ts.snap @@ -0,0 +1,2023 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Workspace migration builder field actions test suite It should NOT build an update_field action for a field RELATION uncovered fields mutation 1`] = `[]`; + +exports[`Workspace migration builder field actions test suite It should build a delete_field action 1`] = ` +[ + { + "flatFieldMetadata": { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field-metadata-unique-identifier-1", + "updatedAt": Any, + "workspaceId": Any, + }, + "flatObjectMetadata": { + "createdAt": Any, + "dataSourceId": Any, + "description": "default flat object metadata description", + "duplicateCriteria": [], + "flatFieldMetadatas": [ + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_0", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_1", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_2", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_3", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_4", + "updatedAt": Any, + "workspaceId": Any, + }, + ], + "flatIndexMetadatas": [], + "icon": "icon", + "id": Any, + "imageIdentifierFieldMetadataId": Any, + "isActive": true, + "isAuditLogged": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isRemote": false, + "isSearchable": true, + "isSystem": false, + "labelIdentifierFieldMetadataId": Any, + "labelPlural": "default flat object metadata label plural", + "labelSingular": "default flat object metadata label singular", + "namePlural": "defaultflatObjectMetadataNamePlural", + "nameSingular": "defaultflatObjectMetadataNameSingular", + "shortcut": "shortcut", + "standardId": undefined, + "standardOverrides": undefined, + "targetTableName": "", + "uniqueIdentifier": "object-metadata-unique-identifier-1", + "updatedAt": Any, + "workspaceId": Any, + }, + "type": "delete_field", + }, +] +`; + +exports[`Workspace migration builder field actions test suite It should build an create_field action 1`] = ` +[ + { + "flatFieldMetadata": { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field-metadata-unique-identifier-1", + "updatedAt": Any, + "workspaceId": Any, + }, + "flatObjectMetadata": { + "createdAt": Any, + "dataSourceId": Any, + "description": "default flat object metadata description", + "duplicateCriteria": [], + "flatFieldMetadatas": [ + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field-metadata-unique-identifier-1", + "updatedAt": Any, + "workspaceId": Any, + }, + ], + "flatIndexMetadatas": [], + "icon": "icon", + "id": Any, + "imageIdentifierFieldMetadataId": Any, + "isActive": true, + "isAuditLogged": true, + "isCustom": true, + "isLabelSyncedWithName": true, + "isRemote": false, + "isSearchable": true, + "isSystem": false, + "labelIdentifierFieldMetadataId": Any, + "labelPlural": "default flat object metadata label plural", + "labelSingular": "default flat object metadata label singular", + "namePlural": "defaultflatObjectMetadataNamePlural", + "nameSingular": "defaultflatObjectMetadataNameSingular", + "shortcut": "shortcut", + "standardId": undefined, + "standardOverrides": undefined, + "targetTableName": "", + "uniqueIdentifier": "object-metadata-unique-identifier-1", + "updatedAt": Any, + "workspaceId": Any, + }, + "type": "create_field", + }, +] +`; + +exports[`Workspace migration builder field actions test suite It should build an create_field action for a RELATION field 1`] = ` +[ + { + "flatFieldMetadata": { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": Any, + "relationTargetObjectMetadataId": Any, + "standardId": undefined, + "standardOverrides": undefined, + "type": "RELATION", + "uniqueIdentifier": "field-metadata-unique-identifier-1", + "updatedAt": Any, + "workspaceId": Any, + }, + "flatObjectMetadata": { + "createdAt": Any, + "dataSourceId": Any, + "description": "default flat object metadata description", + "duplicateCriteria": [], + "flatFieldMetadatas": [ + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": Any, + "relationTargetObjectMetadataId": Any, + "standardId": undefined, + "standardOverrides": undefined, + "type": "RELATION", + "uniqueIdentifier": "field-metadata-unique-identifier-1", + "updatedAt": Any, + "workspaceId": Any, + }, + ], + "flatIndexMetadatas": [], + "icon": "icon", + "id": Any, + "imageIdentifierFieldMetadataId": Any, + "isActive": true, + "isAuditLogged": true, + "isCustom": true, + "isLabelSyncedWithName": true, + "isRemote": false, + "isSearchable": true, + "isSystem": false, + "labelIdentifierFieldMetadataId": Any, + "labelPlural": "default flat object metadata label plural", + "labelSingular": "default flat object metadata label singular", + "namePlural": "defaultflatObjectMetadataNamePlural", + "nameSingular": "defaultflatObjectMetadataNameSingular", + "shortcut": "shortcut", + "standardId": undefined, + "standardOverrides": undefined, + "targetTableName": "", + "uniqueIdentifier": "object-metadata-unique-identifier-1", + "updatedAt": Any, + "workspaceId": Any, + }, + "type": "create_field", + }, +] +`; + +exports[`Workspace migration builder field actions test suite It should build an update_field action 1`] = ` +[ + { + "flatFieldMetadata": { + "createdAt": Any, + "description": "new description", + "icon": "new icon", + "id": Any, + "isActive": false, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "new name", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field-metadata-unique-identifier-1", + "updatedAt": Any, + "workspaceId": Any, + }, + "flatObjectMetadata": { + "createdAt": Any, + "dataSourceId": Any, + "description": "default flat object metadata description", + "duplicateCriteria": [], + "flatFieldMetadatas": [ + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_0", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_1", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_2", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_3", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_4", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "new description", + "icon": "new icon", + "id": Any, + "isActive": false, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "new name", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field-metadata-unique-identifier-1", + "updatedAt": Any, + "workspaceId": Any, + }, + ], + "flatIndexMetadatas": [], + "icon": "icon", + "id": Any, + "imageIdentifierFieldMetadataId": Any, + "isActive": true, + "isAuditLogged": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isRemote": false, + "isSearchable": true, + "isSystem": false, + "labelIdentifierFieldMetadataId": Any, + "labelPlural": "default flat object metadata label plural", + "labelSingular": "default flat object metadata label singular", + "namePlural": "defaultflatObjectMetadataNamePlural", + "nameSingular": "defaultflatObjectMetadataNameSingular", + "shortcut": "shortcut", + "standardId": undefined, + "standardOverrides": undefined, + "targetTableName": "", + "uniqueIdentifier": "object-metadata-unique-identifier-1", + "updatedAt": Any, + "workspaceId": Any, + }, + "type": "update_field", + "updates": [ + { + "from": "default flat field metadata description", + "property": "description", + "to": "new description", + }, + { + "from": "icon", + "property": "icon", + "to": "new icon", + }, + { + "from": true, + "property": "isActive", + "to": false, + }, + { + "from": "flatFieldMetadataName", + "property": "name", + "to": "new name", + }, + ], + }, +] +`; + +exports[`Workspace migration builder field actions test suite It should build an update_field action for a RELATION field 1`] = ` +[ + { + "flatFieldMetadata": { + "createdAt": Any, + "description": "new description", + "icon": "icon", + "id": Any, + "isActive": false, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "new label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": Any, + "relationTargetObjectMetadataId": Any, + "standardId": undefined, + "standardOverrides": undefined, + "type": "RELATION", + "uniqueIdentifier": "field-metadata-unique-identifier-1", + "updatedAt": Any, + "workspaceId": Any, + }, + "flatObjectMetadata": { + "createdAt": Any, + "dataSourceId": Any, + "description": "default flat object metadata description", + "duplicateCriteria": [], + "flatFieldMetadatas": [ + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_0", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_1", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_2", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_3", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_4", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "new description", + "icon": "icon", + "id": Any, + "isActive": false, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "new label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": Any, + "relationTargetObjectMetadataId": Any, + "standardId": undefined, + "standardOverrides": undefined, + "type": "RELATION", + "uniqueIdentifier": "field-metadata-unique-identifier-1", + "updatedAt": Any, + "workspaceId": Any, + }, + ], + "flatIndexMetadatas": [], + "icon": "icon", + "id": Any, + "imageIdentifierFieldMetadataId": Any, + "isActive": true, + "isAuditLogged": true, + "isCustom": true, + "isLabelSyncedWithName": true, + "isRemote": false, + "isSearchable": true, + "isSystem": false, + "labelIdentifierFieldMetadataId": Any, + "labelPlural": "default flat object metadata label plural", + "labelSingular": "default flat object metadata label singular", + "namePlural": "defaultflatObjectMetadataNamePlural", + "nameSingular": "defaultflatObjectMetadataNameSingular", + "shortcut": "shortcut", + "standardId": undefined, + "standardOverrides": undefined, + "targetTableName": "", + "uniqueIdentifier": "object-metadata-unique-identifier-1", + "updatedAt": Any, + "workspaceId": Any, + }, + "type": "update_field", + "updates": [ + { + "from": "default flat field metadata description", + "property": "description", + "to": "new description", + }, + { + "from": true, + "property": "isActive", + "to": false, + }, + { + "from": "flat field metadata label", + "property": "label", + "to": "new label", + }, + ], + }, +] +`; + +exports[`Workspace migration builder field actions test suite It should not infer any actions as from and to fields are identical 1`] = `[]`; + +exports[`Workspace migration builder index actions test suite It should build a delete_index action 1`] = ` +[ + { + "flatIndexMetadata": { + "createdAt": Any, + "flatIndexFieldMetadatas": [], + "id": Any, + "indexType": "BTREE", + "indexWhereClause": undefined, + "isCustom": false, + "isUnique": false, + "name": "defaultFlatIndexMetadataName", + "objectMetadataId": Any, + "uniqueIdentifier": "field-metadata-unique-identifier-1", + "updatedAt": Any, + "workspaceId": Any, + }, + "type": "delete_index", + }, +] +`; + +exports[`Workspace migration builder index actions test suite It should build an create_index action 1`] = ` +[ + { + "flatIndexMetadata": { + "createdAt": Any, + "flatIndexFieldMetadatas": [], + "id": Any, + "indexType": "BTREE", + "indexWhereClause": undefined, + "isCustom": false, + "isUnique": false, + "name": "defaultFlatIndexMetadataName", + "objectMetadataId": Any, + "uniqueIdentifier": "field-metadata-unique-identifier-1", + "updatedAt": Any, + "workspaceId": Any, + }, + "type": "create_index", + }, +] +`; + +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, + "flatIndexFieldMetadatas": [], + "id": Any, + "indexType": "BTREE", + "indexWhereClause": undefined, + "isCustom": false, + "isUnique": false, + "name": "defaultFlatIndexMetadataName", + "objectMetadataId": Any, + "uniqueIdentifier": "field-metadata-unique-identifier-1", + "updatedAt": Any, + "workspaceId": Any, + }, + "type": "delete_index", + }, + { + "flatIndexMetadata": { + "createdAt": Any, + "flatIndexFieldMetadatas": [], + "id": Any, + "indexType": "BTREE", + "indexWhereClause": "new index where clause", + "isCustom": false, + "isUnique": false, + "name": "new index name", + "objectMetadataId": Any, + "uniqueIdentifier": "field-metadata-unique-identifier-1", + "updatedAt": Any, + "workspaceId": Any, + }, + "type": "create_index", + }, +] +`; + +exports[`Workspace migration builder index actions test suite It should not infer any actions as from and to indexes are identical 1`] = `[]`; + +exports[`Workspace migration builder object actions test suite It should build a create_object action 1`] = ` +[ + { + "flatObjectMetadata": { + "createdAt": Any, + "dataSourceId": Any, + "description": "default flat object metadata description", + "duplicateCriteria": [], + "flatFieldMetadatas": [], + "flatIndexMetadatas": [], + "icon": "icon", + "id": Any, + "imageIdentifierFieldMetadataId": Any, + "isActive": true, + "isAuditLogged": true, + "isCustom": true, + "isLabelSyncedWithName": true, + "isRemote": false, + "isSearchable": true, + "isSystem": false, + "labelIdentifierFieldMetadataId": Any, + "labelPlural": "default flat object metadata label plural", + "labelSingular": "default flat object metadata label singular", + "namePlural": "totos", + "nameSingular": "toto", + "shortcut": "shortcut", + "standardId": undefined, + "standardOverrides": undefined, + "targetTableName": "", + "uniqueIdentifier": "pomme", + "updatedAt": Any, + "workspaceId": Any, + }, + "type": "create_object", + }, +] +`; + +exports[`Workspace migration builder object actions test suite It should build a create_object and create_field actions for each of this fieldMetadata 1`] = ` +[ + { + "flatObjectMetadata": { + "createdAt": Any, + "dataSourceId": Any, + "description": "default flat object metadata description", + "duplicateCriteria": [], + "flatFieldMetadatas": [ + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_0", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_1", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_2", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_3", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_4", + "updatedAt": Any, + "workspaceId": Any, + }, + ], + "flatIndexMetadatas": [], + "icon": "icon", + "id": Any, + "imageIdentifierFieldMetadataId": Any, + "isActive": true, + "isAuditLogged": true, + "isCustom": true, + "isLabelSyncedWithName": true, + "isRemote": false, + "isSearchable": true, + "isSystem": false, + "labelIdentifierFieldMetadataId": Any, + "labelPlural": "default flat object metadata label plural", + "labelSingular": "default flat object metadata label singular", + "namePlural": "totos", + "nameSingular": "toto", + "shortcut": "shortcut", + "standardId": undefined, + "standardOverrides": undefined, + "targetTableName": "", + "uniqueIdentifier": "pomme", + "updatedAt": Any, + "workspaceId": Any, + }, + "type": "create_object", + }, + { + "flatFieldMetadata": { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_0", + "updatedAt": Any, + "workspaceId": Any, + }, + "flatObjectMetadata": { + "createdAt": Any, + "dataSourceId": Any, + "description": "default flat object metadata description", + "duplicateCriteria": [], + "flatFieldMetadatas": [ + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_0", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_1", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_2", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_3", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_4", + "updatedAt": Any, + "workspaceId": Any, + }, + ], + "flatIndexMetadatas": [], + "icon": "icon", + "id": Any, + "imageIdentifierFieldMetadataId": Any, + "isActive": true, + "isAuditLogged": true, + "isCustom": true, + "isLabelSyncedWithName": true, + "isRemote": false, + "isSearchable": true, + "isSystem": false, + "labelIdentifierFieldMetadataId": Any, + "labelPlural": "default flat object metadata label plural", + "labelSingular": "default flat object metadata label singular", + "namePlural": "totos", + "nameSingular": "toto", + "shortcut": "shortcut", + "standardId": undefined, + "standardOverrides": undefined, + "targetTableName": "", + "uniqueIdentifier": "pomme", + "updatedAt": Any, + "workspaceId": Any, + }, + "type": "create_field", + }, + { + "flatFieldMetadata": { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_1", + "updatedAt": Any, + "workspaceId": Any, + }, + "flatObjectMetadata": { + "createdAt": Any, + "dataSourceId": Any, + "description": "default flat object metadata description", + "duplicateCriteria": [], + "flatFieldMetadatas": [ + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_0", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_1", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_2", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_3", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_4", + "updatedAt": Any, + "workspaceId": Any, + }, + ], + "flatIndexMetadatas": [], + "icon": "icon", + "id": Any, + "imageIdentifierFieldMetadataId": Any, + "isActive": true, + "isAuditLogged": true, + "isCustom": true, + "isLabelSyncedWithName": true, + "isRemote": false, + "isSearchable": true, + "isSystem": false, + "labelIdentifierFieldMetadataId": Any, + "labelPlural": "default flat object metadata label plural", + "labelSingular": "default flat object metadata label singular", + "namePlural": "totos", + "nameSingular": "toto", + "shortcut": "shortcut", + "standardId": undefined, + "standardOverrides": undefined, + "targetTableName": "", + "uniqueIdentifier": "pomme", + "updatedAt": Any, + "workspaceId": Any, + }, + "type": "create_field", + }, + { + "flatFieldMetadata": { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_2", + "updatedAt": Any, + "workspaceId": Any, + }, + "flatObjectMetadata": { + "createdAt": Any, + "dataSourceId": Any, + "description": "default flat object metadata description", + "duplicateCriteria": [], + "flatFieldMetadatas": [ + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_0", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_1", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_2", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_3", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_4", + "updatedAt": Any, + "workspaceId": Any, + }, + ], + "flatIndexMetadatas": [], + "icon": "icon", + "id": Any, + "imageIdentifierFieldMetadataId": Any, + "isActive": true, + "isAuditLogged": true, + "isCustom": true, + "isLabelSyncedWithName": true, + "isRemote": false, + "isSearchable": true, + "isSystem": false, + "labelIdentifierFieldMetadataId": Any, + "labelPlural": "default flat object metadata label plural", + "labelSingular": "default flat object metadata label singular", + "namePlural": "totos", + "nameSingular": "toto", + "shortcut": "shortcut", + "standardId": undefined, + "standardOverrides": undefined, + "targetTableName": "", + "uniqueIdentifier": "pomme", + "updatedAt": Any, + "workspaceId": Any, + }, + "type": "create_field", + }, + { + "flatFieldMetadata": { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_3", + "updatedAt": Any, + "workspaceId": Any, + }, + "flatObjectMetadata": { + "createdAt": Any, + "dataSourceId": Any, + "description": "default flat object metadata description", + "duplicateCriteria": [], + "flatFieldMetadatas": [ + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_0", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_1", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_2", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_3", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_4", + "updatedAt": Any, + "workspaceId": Any, + }, + ], + "flatIndexMetadatas": [], + "icon": "icon", + "id": Any, + "imageIdentifierFieldMetadataId": Any, + "isActive": true, + "isAuditLogged": true, + "isCustom": true, + "isLabelSyncedWithName": true, + "isRemote": false, + "isSearchable": true, + "isSystem": false, + "labelIdentifierFieldMetadataId": Any, + "labelPlural": "default flat object metadata label plural", + "labelSingular": "default flat object metadata label singular", + "namePlural": "totos", + "nameSingular": "toto", + "shortcut": "shortcut", + "standardId": undefined, + "standardOverrides": undefined, + "targetTableName": "", + "uniqueIdentifier": "pomme", + "updatedAt": Any, + "workspaceId": Any, + }, + "type": "create_field", + }, + { + "flatFieldMetadata": { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_4", + "updatedAt": Any, + "workspaceId": Any, + }, + "flatObjectMetadata": { + "createdAt": Any, + "dataSourceId": Any, + "description": "default flat object metadata description", + "duplicateCriteria": [], + "flatFieldMetadatas": [ + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_0", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_1", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_2", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_3", + "updatedAt": Any, + "workspaceId": Any, + }, + { + "createdAt": Any, + "description": "default flat field metadata description", + "icon": "icon", + "id": Any, + "isActive": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isNullable": true, + "isSystem": false, + "isUnique": false, + "label": "flat field metadata label", + "name": "flatFieldMetadataName", + "objectMetadataId": Any, + "relationTargetFieldMetadataId": undefined, + "relationTargetObjectMetadataId": undefined, + "standardId": undefined, + "standardOverrides": undefined, + "type": "TEXT", + "uniqueIdentifier": "field_4", + "updatedAt": Any, + "workspaceId": Any, + }, + ], + "flatIndexMetadatas": [], + "icon": "icon", + "id": Any, + "imageIdentifierFieldMetadataId": Any, + "isActive": true, + "isAuditLogged": true, + "isCustom": true, + "isLabelSyncedWithName": true, + "isRemote": false, + "isSearchable": true, + "isSystem": false, + "labelIdentifierFieldMetadataId": Any, + "labelPlural": "default flat object metadata label plural", + "labelSingular": "default flat object metadata label singular", + "namePlural": "totos", + "nameSingular": "toto", + "shortcut": "shortcut", + "standardId": undefined, + "standardOverrides": undefined, + "targetTableName": "", + "uniqueIdentifier": "pomme", + "updatedAt": Any, + "workspaceId": Any, + }, + "type": "create_field", + }, +] +`; + +exports[`Workspace migration builder object actions test suite It should build a delete_object action 1`] = ` +[ + { + "flatObjectMetadata": { + "createdAt": Any, + "dataSourceId": Any, + "description": "default flat object metadata description", + "duplicateCriteria": [], + "flatFieldMetadatas": [], + "flatIndexMetadatas": [], + "icon": "icon", + "id": Any, + "imageIdentifierFieldMetadataId": Any, + "isActive": true, + "isAuditLogged": true, + "isCustom": true, + "isLabelSyncedWithName": true, + "isRemote": false, + "isSearchable": true, + "isSystem": false, + "labelIdentifierFieldMetadataId": Any, + "labelPlural": "default flat object metadata label plural", + "labelSingular": "default flat object metadata label singular", + "namePlural": "totos", + "nameSingular": "toto", + "shortcut": "shortcut", + "standardId": undefined, + "standardOverrides": undefined, + "targetTableName": "", + "uniqueIdentifier": "pomme", + "updatedAt": Any, + "workspaceId": Any, + }, + "type": "delete_object", + }, +] +`; + +exports[`Workspace migration builder object actions test suite It should build an update_object action with all object updated fields 1`] = ` +[ + { + "flatObjectMetadata": { + "createdAt": Any, + "dataSourceId": Any, + "description": "default flat object metadata description", + "duplicateCriteria": [], + "flatFieldMetadatas": [], + "flatIndexMetadatas": [], + "icon": "icon", + "id": Any, + "imageIdentifierFieldMetadataId": Any, + "isActive": true, + "isAuditLogged": true, + "isCustom": true, + "isLabelSyncedWithName": false, + "isRemote": false, + "isSearchable": true, + "isSystem": false, + "labelIdentifierFieldMetadataId": Any, + "labelPlural": "default flat object metadata label plural", + "labelSingular": "default flat object metadata label singular", + "namePlural": "prastoins", + "nameSingular": "prastouin", + "shortcut": "shortcut", + "standardId": undefined, + "standardOverrides": undefined, + "targetTableName": "", + "uniqueIdentifier": "pomme", + "updatedAt": Any, + "workspaceId": Any, + }, + "type": "update_object", + "updates": [ + { + "from": true, + "property": "isLabelSyncedWithName", + "to": false, + }, + { + "from": "totos", + "property": "namePlural", + "to": "prastoins", + }, + { + "from": "toto", + "property": "nameSingular", + "to": "prastouin", + }, + ], + }, +] +`; + +exports[`Workspace migration builder object actions test suite It should not infer any actions as from and to are identical 1`] = `[]`; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/common/workspace-migration-builder-field-test-case.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/common/workspace-migration-builder-field-test-case.ts new file mode 100644 index 000000000..4161a5dd8 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/common/workspace-migration-builder-field-test-case.ts @@ -0,0 +1,284 @@ +import { faker } from '@faker-js/faker'; +import { FieldMetadataType } from 'twenty-shared/types'; + +import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface'; + +import { getFlatFieldMetadataMock } from 'src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-field-metadata.mock'; +import { getFlatObjectMetadataMock } from 'src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-object-metadata.mock'; +import { WorkspaceMigrationBuilderTestCase } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/types/workspace-migration-builder-test-case.type'; + +const basicObjectMetadataId = faker.string.uuid(); +const basicFlatFieldMetadatas = Array.from({ length: 5 }, (_value, index) => + getFlatFieldMetadataMock({ + objectMetadataId: basicObjectMetadataId, + uniqueIdentifier: `field_${index}`, + }), +); + +// TODO prastoin test defaultValue and settings updates +// TODO prastoin test standard abstraction in TDD style + +const relationTestCases: WorkspaceMigrationBuilderTestCase[] = [ + { + title: 'It should build an create_field action for a RELATION field', + context: { + input: () => { + const objectMetadataId = faker.string.uuid(); + + const createdFlatRelationFieldMetadata = getFlatFieldMetadataMock({ + uniqueIdentifier: 'field-metadata-unique-identifier-1', + objectMetadataId, + type: FieldMetadataType.RELATION, + relationTargetFieldMetadataId: faker.string.uuid(), + relationTargetObjectMetadataId: faker.string.uuid(), + }); + const flatObjectMetadata = getFlatObjectMetadataMock({ + uniqueIdentifier: 'object-metadata-unique-identifier-1', + isLabelSyncedWithName: true, + flatFieldMetadatas: [], + }); + + return { + from: [flatObjectMetadata], + to: [ + { + ...flatObjectMetadata, + flatFieldMetadatas: [createdFlatRelationFieldMetadata], + }, + ], + }; + }, + expectedActionsTypeCounter: { + createField: 1, + }, + }, + }, + { + title: 'It should build an update_field action for a RELATION field', + context: { + input: () => { + const objectMetadataId = faker.string.uuid(); + + const updatedFieldMetadata = getFlatFieldMetadataMock({ + uniqueIdentifier: 'field-metadata-unique-identifier-1', + objectMetadataId, + type: FieldMetadataType.RELATION, + relationTargetFieldMetadataId: faker.string.uuid(), + relationTargetObjectMetadataId: faker.string.uuid(), + }); + const flatObjectMetadata = getFlatObjectMetadataMock({ + uniqueIdentifier: 'object-metadata-unique-identifier-1', + isLabelSyncedWithName: true, + flatFieldMetadatas: [ + ...basicFlatFieldMetadatas, + updatedFieldMetadata, + ], + }); + + return { + from: [flatObjectMetadata], + to: [ + { + ...flatObjectMetadata, + flatFieldMetadatas: [ + ...basicFlatFieldMetadatas, + { + ...updatedFieldMetadata, + isActive: false, + description: 'new description', + label: 'new label', + }, + ], + }, + ], + }; + }, + expectedActionsTypeCounter: { + updateField: 1, + }, + }, + }, + { + title: + 'It should NOT build an update_field action for a field RELATION uncovered fields mutation', + context: { + input: () => { + const objectMetadataId = faker.string.uuid(); + const updatedFieldMetadata = + getFlatFieldMetadataMock({ + uniqueIdentifier: 'field-metadata-unique-identifier-1', + objectMetadataId, + type: FieldMetadataType.RELATION, + settings: { + relationType: RelationType.MANY_TO_ONE, + isForeignKey: true, + joinColumnName: 'column-name', + onDelete: undefined, + }, + relationTargetFieldMetadataId: faker.string.uuid(), + relationTargetObjectMetadataId: faker.string.uuid(), + }); + const flatObjectMetadata = getFlatObjectMetadataMock({ + uniqueIdentifier: 'object-metadata-unique-identifier-1', + isLabelSyncedWithName: true, + flatFieldMetadatas: [updatedFieldMetadata], + }); + + return { + from: [flatObjectMetadata], + to: [ + { + ...flatObjectMetadata, + flatFieldMetadatas: [ + { + ...updatedFieldMetadata, + settings: { + relationType: RelationType.ONE_TO_MANY, + isForeignKey: false, + joinColumnName: 'new-column-name', + onDelete: undefined, + }, + relationTargetFieldMetadataId: faker.string.uuid(), + relationTargetObjectMetadataId: faker.string.uuid(), + }, + ], + }, + ], + }; + }, + }, + }, +]; + +const basicCrudTestCases: WorkspaceMigrationBuilderTestCase[] = [ + { + title: 'It should build an create_field action', + context: { + input: () => { + const objectMetadataId = faker.string.uuid(); + + const flatFieldMetadata = getFlatFieldMetadataMock({ + uniqueIdentifier: 'field-metadata-unique-identifier-1', + objectMetadataId, + }); + const flatObjectMetadata = getFlatObjectMetadataMock({ + uniqueIdentifier: 'object-metadata-unique-identifier-1', + isLabelSyncedWithName: true, + flatFieldMetadatas: [], + }); + + return { + from: [flatObjectMetadata], + to: [ + { + ...flatObjectMetadata, + flatFieldMetadatas: [flatFieldMetadata], + }, + ], + }; + }, + expectedActionsTypeCounter: { + createField: 1, + }, + }, + }, + { + title: 'It should build an update_field action', + context: { + input: () => { + const objectMetadataId = faker.string.uuid(); + + const flatFieldMetadata = getFlatFieldMetadataMock({ + uniqueIdentifier: 'field-metadata-unique-identifier-1', + objectMetadataId, + }); + const flatObjectMetadata = getFlatObjectMetadataMock({ + uniqueIdentifier: 'object-metadata-unique-identifier-1', + flatFieldMetadatas: [...basicFlatFieldMetadatas, flatFieldMetadata], + }); + + return { + from: [flatObjectMetadata], + to: [ + { + ...flatObjectMetadata, + flatFieldMetadatas: [ + ...basicFlatFieldMetadatas, + { + ...flatFieldMetadata, + description: 'new description', + name: 'new name', + isActive: false, + icon: 'new icon', + }, + ], + }, + ], + }; + }, + expectedActionsTypeCounter: { + updateField: 1, + }, + }, + }, + { + title: 'It should build a delete_field action', + context: { + input: () => { + const objectMetadataId = faker.string.uuid(); + + const flatFieldMetadata = getFlatFieldMetadataMock({ + uniqueIdentifier: 'field-metadata-unique-identifier-1', + objectMetadataId, + }); + const flatObjectMetadata = getFlatObjectMetadataMock({ + uniqueIdentifier: 'object-metadata-unique-identifier-1', + flatFieldMetadatas: [...basicFlatFieldMetadatas, flatFieldMetadata], + }); + + return { + from: [flatObjectMetadata], + to: [ + { + ...flatObjectMetadata, + flatFieldMetadatas: basicFlatFieldMetadatas, + }, + ], + }; + }, + expectedActionsTypeCounter: { + deleteField: 1, + }, + }, + }, +]; + +export const WORKSPACE_MIGRATION_FIELD_BUILDER_TEST_CASES: WorkspaceMigrationBuilderTestCase[] = + [ + ...relationTestCases, + ...basicCrudTestCases, + { + title: + 'It should not infer any actions as from and to fields are identical', + context: { + input: () => { + const objectMetadataId = faker.string.uuid(); + const flatFieldMetadata = getFlatFieldMetadataMock({ + uniqueIdentifier: 'field-metadata-unique-identifier-1', + objectMetadataId, + }); + const from = [ + getFlatObjectMetadataMock({ + uniqueIdentifier: 'object-metadata-unique-identifier-1', + flatFieldMetadatas: [flatFieldMetadata], + }), + ]; + + return { + from, + to: from, + }; + }, + }, + }, + ]; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/common/workspace-migration-builder-index-test-case.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/common/workspace-migration-builder-index-test-case.ts new file mode 100644 index 000000000..9e39a565b --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/common/workspace-migration-builder-index-test-case.ts @@ -0,0 +1,130 @@ +import { faker } from '@faker-js/faker'; + +import { getFlatIndexMetadataMock } from 'src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-index-metadata.mock'; +import { getFlatObjectMetadataMock } from 'src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-object-metadata.mock'; +import { WorkspaceMigrationBuilderTestCase } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/types/workspace-migration-builder-test-case.type'; + +// Should test more things such as flatFieldIndex diffing +const objectMetadataId = faker.string.uuid(); + +export const WORKSPACE_MIGRATION_INDEX_BUILDER_TEST_CASES: WorkspaceMigrationBuilderTestCase[] = + [ + { + title: 'It should build an create_index action', + context: { + input: () => { + const flatIndexMetadata = getFlatIndexMetadataMock({ + uniqueIdentifier: 'field-metadata-unique-identifier-1', + objectMetadataId, + }); + const flatObjectMetadata = getFlatObjectMetadataMock({ + uniqueIdentifier: 'object-metadata-unique-identifier-1', + isLabelSyncedWithName: true, + flatIndexMetadatas: [], + }); + + return { + from: [flatObjectMetadata], + to: [ + { + ...flatObjectMetadata, + flatIndexMetadatas: [flatIndexMetadata], + }, + ], + }; + }, + expectedActionsTypeCounter: { + createIndex: 1, + }, + }, + }, + { + title: + 'It should build an delete_index and a create_index action ( the way we handle update )', + context: { + input: () => { + const flatIndexMetadata = getFlatIndexMetadataMock({ + uniqueIdentifier: 'field-metadata-unique-identifier-1', + objectMetadataId, + }); + const flatObjectMetadata = getFlatObjectMetadataMock({ + uniqueIdentifier: 'object-metadata-unique-identifier-1', + isLabelSyncedWithName: true, + flatIndexMetadatas: [flatIndexMetadata], + }); + + return { + from: [flatObjectMetadata], + to: [ + { + ...flatObjectMetadata, + flatIndexMetadatas: [ + { + ...flatIndexMetadata, + name: 'new index name', + isUnique: false, + indexWhereClause: 'new index where clause', + }, + ], + }, + ], + }; + }, + expectedActionsTypeCounter: { + createIndex: 1, + deleteIndex: 1, + }, + }, + }, + { + title: 'It should build a delete_index action', + context: { + input: () => { + const flatIndexMetadata = getFlatIndexMetadataMock({ + uniqueIdentifier: 'field-metadata-unique-identifier-1', + objectMetadataId, + }); + const flatObjectMetadata = getFlatObjectMetadataMock({ + uniqueIdentifier: 'object-metadata-unique-identifier-1', + isLabelSyncedWithName: true, + flatIndexMetadatas: [flatIndexMetadata], + }); + + return { + from: [flatObjectMetadata], + to: [ + { + ...flatObjectMetadata, + flatIndexMetadatas: [], + }, + ], + }; + }, + expectedActionsTypeCounter: { + deleteIndex: 1, + }, + }, + }, + { + title: + 'It should not infer any actions as from and to indexes are identical', + context: { + input: () => { + const flatIndexMetadata = getFlatIndexMetadataMock({ + uniqueIdentifier: 'field-metadata-unique-identifier-1', + objectMetadataId, + }); + const flatObjectMetadata = getFlatObjectMetadataMock({ + uniqueIdentifier: 'object-metadata-unique-identifier-1', + isLabelSyncedWithName: true, + flatIndexMetadatas: [flatIndexMetadata], + }); + + return { + from: [flatObjectMetadata], + to: [flatObjectMetadata], + }; + }, + }, + }, + ]; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/common/workspace-migration-builder-object-test-case.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/common/workspace-migration-builder-object-test-case.ts new file mode 100644 index 000000000..4e3bdfbdc --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/common/workspace-migration-builder-object-test-case.ts @@ -0,0 +1,130 @@ +import { faker } from '@faker-js/faker'; + +import { getFlatFieldMetadataMock } from 'src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-field-metadata.mock'; +import { getFlatObjectMetadataMock } from 'src/engine/workspace-manager/workspace-migration-v2/__tests__/get-flat-object-metadata.mock'; +import { WorkspaceMigrationBuilderTestCase } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/types/workspace-migration-builder-test-case.type'; + +export const WORKSPACE_MIGRATION_OBJECT_BUILDER_TEST_CASES: WorkspaceMigrationBuilderTestCase[] = + [ + { + title: + 'It should build an update_object action with all object updated fields', + context: { + input: () => { + const flatObjectMetadata = getFlatObjectMetadataMock({ + uniqueIdentifier: 'pomme', + nameSingular: 'toto', + namePlural: 'totos', + isLabelSyncedWithName: true, + }); + + return { + from: [flatObjectMetadata], + to: [ + { + ...flatObjectMetadata, + nameSingular: 'prastouin', + namePlural: 'prastoins', + isLabelSyncedWithName: false, + }, + ], + }; + }, + expectedActionsTypeCounter: { + updateObject: 1, + }, + }, + }, + { + title: 'It should build a create_object action', + context: { + input: () => { + const flatObjectMetadata = getFlatObjectMetadataMock({ + uniqueIdentifier: 'pomme', + nameSingular: 'toto', + namePlural: 'totos', + isLabelSyncedWithName: true, + }); + + return { + from: [], + to: [flatObjectMetadata], + }; + }, + expectedActionsTypeCounter: { + createObject: 1, + }, + }, + }, + { + title: + 'It should build a create_object and create_field actions for each of this fieldMetadata', + context: { + input: () => { + const objectMetadataId = faker.string.uuid(); + const flatFieldMetadatas = Array.from( + { length: 5 }, + (_value, index) => + getFlatFieldMetadataMock({ + objectMetadataId, + uniqueIdentifier: `field_${index}`, + }), + ); + const flatObjectMetadata = getFlatObjectMetadataMock({ + uniqueIdentifier: 'pomme', + nameSingular: 'toto', + namePlural: 'totos', + isLabelSyncedWithName: true, + id: objectMetadataId, + flatFieldMetadatas, + }); + + return { + from: [], + to: [flatObjectMetadata], + }; + }, + + expectedActionsTypeCounter: { + createObject: 1, + createField: 5, + }, + }, + }, + { + title: 'It should build a delete_object action', + context: { + input: () => { + const flatObjectMetadata = getFlatObjectMetadataMock({ + uniqueIdentifier: 'pomme', + nameSingular: 'toto', + namePlural: 'totos', + isLabelSyncedWithName: true, + }); + + return { + from: [flatObjectMetadata], + to: [], + }; + }, + expectedActionsTypeCounter: { + deleteObject: 1, + }, + }, + }, + { + title: 'It should not infer any actions as from and to are identical', + context: { + input: () => { + const from = [ + getFlatObjectMetadataMock({ uniqueIdentifier: 'pomme' }), + ]; + + return { + from, + to: from, + }; + }, + }, + }, + ]; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/types/workspace-migration-builder-test-case.type.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/types/workspace-migration-builder-test-case.type.ts new file mode 100644 index 000000000..ef1e2ae03 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/types/workspace-migration-builder-test-case.type.ts @@ -0,0 +1,25 @@ +import { EachTestingContext } from 'twenty-shared/testing'; + +import { WorkspaceMigrationActionTypeV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-action-common-v2'; +import { WorkspaceMigrationBuilderV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-builder-v2.service'; + +type WorkspaceBuilderArgs = Parameters< + typeof WorkspaceMigrationBuilderV2Service.prototype.build +>[0]; + +type ConvertActionTypeToCamelCase = + T extends `${infer Before}_${infer After}` + ? `${Before}${Capitalize}` + : T; + +export type CamelCasedWorkspaceMigrationActionsType = + ConvertActionTypeToCamelCase; + +export type ExpectedActionCounters = Partial< + Record +>; + +export type WorkspaceMigrationBuilderTestCase = EachTestingContext<{ + input: WorkspaceBuilderArgs | (() => WorkspaceBuilderArgs); + expectedActionsTypeCounter?: ExpectedActionCounters; +}>; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-builder.spec.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-builder.spec.ts new file mode 100644 index 000000000..ea51e6186 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-builder.spec.ts @@ -0,0 +1,102 @@ +import { extractRecordIdsAndDatesAsExpectAny } from 'test/utils/extract-record-ids-and-dates-as-expect-any'; +import { eachTestingContextFilter } from 'twenty-shared/testing'; +import { capitalize } from 'twenty-shared/utils'; + +import { WORKSPACE_MIGRATION_FIELD_BUILDER_TEST_CASES } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/common/workspace-migration-builder-field-test-case'; +import { WORKSPACE_MIGRATION_INDEX_BUILDER_TEST_CASES } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/common/workspace-migration-builder-index-test-case'; +import { WORKSPACE_MIGRATION_OBJECT_BUILDER_TEST_CASES } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/common/workspace-migration-builder-object-test-case'; +import { + CamelCasedWorkspaceMigrationActionsType, + ExpectedActionCounters, + WorkspaceMigrationBuilderTestCase, +} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/types/workspace-migration-builder-test-case.type'; +import { WorkspaceMigrationV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-v2'; +import { WorkspaceMigrationBuilderV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-builder-v2.service'; + +const allWorkspaceBuilderTestCases: { + label: string; + testCases: WorkspaceMigrationBuilderTestCase[]; +}[] = [ + { + label: 'object', + testCases: WORKSPACE_MIGRATION_OBJECT_BUILDER_TEST_CASES, + }, + { + label: 'field', + testCases: WORKSPACE_MIGRATION_FIELD_BUILDER_TEST_CASES, + }, + { + label: 'index', + testCases: WORKSPACE_MIGRATION_INDEX_BUILDER_TEST_CASES, + }, +]; + +const expectedActionsTypeCounterChecker = ({ + expectedActionsTypeCounter, + workspaceMigration, +}: { + workspaceMigration: WorkspaceMigrationV2; + expectedActionsTypeCounter?: ExpectedActionCounters; +}) => { + const initialAcc: ExpectedActionCounters = { + createField: 0, + createIndex: 0, + createObject: 0, + deleteField: 0, + deleteIndex: 0, + deleteObject: 0, + updateField: 0, + updateObject: 0, + }; + const actualActionsTypeCounter = workspaceMigration.actions.reduce( + (acc, action) => { + const { type } = action; + const [operation, target] = type.split('_'); + const formattedActionKey = + `${operation}${capitalize(target)}` as CamelCasedWorkspaceMigrationActionsType; + + return { + ...acc, + [formattedActionKey]: (acc[formattedActionKey] ?? 0) + 1, + }; + }, + initialAcc, + ); + + expect(actualActionsTypeCounter).toEqual({ + ...initialAcc, + ...expectedActionsTypeCounter, + }); +}; + +describe.each(allWorkspaceBuilderTestCases)( + 'Workspace migration builder $label actions test suite', + ({ testCases }) => { + let service: WorkspaceMigrationBuilderV2Service; + + beforeEach(() => { + service = new WorkspaceMigrationBuilderV2Service(); + }); + + it.each(eachTestingContextFilter(testCases))( + '$title', + ({ context: { input, expectedActionsTypeCounter } }) => { + const { from, to } = typeof input === 'function' ? input() : input; + const workspaceMigration = service.build({ + from, + to, + }); + + expectedActionsTypeCounterChecker({ + expectedActionsTypeCounter, + workspaceMigration, + }); + const { actions } = workspaceMigration; + + expect(actions).toMatchSnapshot( + actions.map(extractRecordIdsAndDatesAsExpectAny), + ); + }, + ); + }, +); 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 deleted file mode 100644 index da2056e0b..000000000 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-v2-builder.spec.ts +++ /dev/null @@ -1,605 +0,0 @@ -import { FieldMetadataType } from 'twenty-shared/types'; - -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: FlatObjectMetadata = { - uniqueIdentifier: '20202020-e89b-12d3-a456-426614175000', - nameSingular: 'Contact', - namePlural: 'Contacts', - labelSingular: 'Contact', - flatIndexMetadatas: [], - labelPlural: 'Contacts', - description: 'A contact', - flatFieldMetadatas: [ - { - uniqueIdentifier: '20202020-e89b-12d3-a456-426614174000', - name: 'firstName', - label: 'First Name', - type: FieldMetadataType.FULL_NAME, - defaultValue: '', - description: '', - }, - ], - }; - - beforeEach(() => { - service = new WorkspaceMigrationBuilderV2Service(); - }); - - it('should return a migration when nameSingular changes', () => { - const from: FlatObjectMetadata = baseObject; - const to: FlatObjectMetadata = { - ...from, - nameSingular: 'Person', - }; - const result = service.build({ from: [from], to: [to] }); - - expect(result).toMatchInlineSnapshot(` -{ - "actions": [ - { - "flatObjectMetadata": { - "description": "A contact", - "flatFieldMetadatas": [ - { - "defaultValue": "", - "description": "", - "label": "First Name", - "name": "firstName", - "type": "FULL_NAME", - "uniqueIdentifier": "20202020-e89b-12d3-a456-426614174000", - }, - ], - "flatIndexMetadatas": [], - "labelPlural": "Contacts", - "labelSingular": "Contact", - "namePlural": "Contacts", - "nameSingular": "Person", - "uniqueIdentifier": "20202020-e89b-12d3-a456-426614175000", - }, - "type": "update_object", - "updates": [ - { - "from": "Contact", - "property": "nameSingular", - "to": "Person", - }, - ], - }, - ], -} -`); - }); - - it('should return a migration when creating a new object', () => { - const newObject: FlatObjectMetadata = { - uniqueIdentifier: '20202020-e89b-12d3-a456-426614175001', - nameSingular: 'Company', - namePlural: 'Companies', - flatIndexMetadatas: [], - labelSingular: 'Company', - labelPlural: 'Companies', - description: 'A company', - flatFieldMetadatas: [ - { - uniqueIdentifier: '20202020-e89b-12d3-a456-426614174001', - name: 'name', - label: 'Name', - type: FieldMetadataType.ADDRESS, - defaultValue: '', - description: '', - }, - ], - }; - - const result = service.build({ from: [], to: [newObject] }); - - expect(result).toMatchInlineSnapshot(` -{ - "actions": [ - { - "flatObjectMetadata": { - "description": "A company", - "flatFieldMetadatas": [ - { - "defaultValue": "", - "description": "", - "label": "Name", - "name": "name", - "type": "ADDRESS", - "uniqueIdentifier": "20202020-e89b-12d3-a456-426614174001", - }, - ], - "flatIndexMetadatas": [], - "labelPlural": "Companies", - "labelSingular": "Company", - "namePlural": "Companies", - "nameSingular": "Company", - "uniqueIdentifier": "20202020-e89b-12d3-a456-426614175001", - }, - "type": "create_object", - }, - { - "flatFieldMetadata": { - "defaultValue": "", - "description": "", - "label": "Name", - "name": "name", - "type": "ADDRESS", - "uniqueIdentifier": "20202020-e89b-12d3-a456-426614174001", - }, - "flatObjectMetadata": { - "description": "A company", - "flatFieldMetadatas": [ - { - "defaultValue": "", - "description": "", - "label": "Name", - "name": "name", - "type": "ADDRESS", - "uniqueIdentifier": "20202020-e89b-12d3-a456-426614174001", - }, - ], - "flatIndexMetadatas": [], - "labelPlural": "Companies", - "labelSingular": "Company", - "namePlural": "Companies", - "nameSingular": "Company", - "uniqueIdentifier": "20202020-e89b-12d3-a456-426614175001", - }, - "type": "create_field", - }, - ], -} -`); - }); - - it('should return a migration when deleting an object', () => { - const result = service.build({ from: [baseObject], to: [] }); - - expect(result).toMatchInlineSnapshot(` -{ - "actions": [ - { - "flatObjectMetadata": { - "description": "A contact", - "flatFieldMetadatas": [ - { - "defaultValue": "", - "description": "", - "label": "First Name", - "name": "firstName", - "type": "FULL_NAME", - "uniqueIdentifier": "20202020-e89b-12d3-a456-426614174000", - }, - ], - "flatIndexMetadatas": [], - "labelPlural": "Contacts", - "labelSingular": "Contact", - "namePlural": "Contacts", - "nameSingular": "Contact", - "uniqueIdentifier": "20202020-e89b-12d3-a456-426614175000", - }, - "type": "delete_object", - }, - ], -} -`); - }); - - it('should handle multiple operations in a single migration', () => { - const objectToUpdate: FlatObjectMetadata = { - ...baseObject, - nameSingular: 'Person', - flatFieldMetadatas: [ - ...baseObject.flatFieldMetadatas, - { - defaultValue: '', - label: 'New field', - type: FieldMetadataType.NUMBER, - name: 'newField', - uniqueIdentifier: '20202020-3ad3-4fec-9c46-8dc9158980e3', - description: 'new field description', - }, - ], - }; - const objectToDelete = { - ...baseObject, - uniqueIdentifier: '20202020-59ef-4a14-a509-0a02acb248d5', - }; - const objectToCreate: FlatObjectMetadata = { - uniqueIdentifier: '20202020-1218-4fc0-b32d-fc4f005c4bab', - nameSingular: 'Company', - namePlural: 'Companies', - flatIndexMetadatas: [], - labelSingular: 'Company', - labelPlural: 'Companies', - description: 'A company', - flatFieldMetadatas: [ - { - uniqueIdentifier: '20202020-1016-4f09-bad6-e75681f385f4', - name: 'name', - label: 'Name', - type: FieldMetadataType.ADDRESS, - defaultValue: '', - description: '', - }, - ], - }; - - const result = service.build({ - from: [baseObject, objectToDelete], - to: [objectToUpdate, objectToCreate], - }); - - expect(result).toMatchInlineSnapshot(` -{ - "actions": [ - { - "flatObjectMetadata": { - "description": "A company", - "flatFieldMetadatas": [ - { - "defaultValue": "", - "description": "", - "label": "Name", - "name": "name", - "type": "ADDRESS", - "uniqueIdentifier": "20202020-1016-4f09-bad6-e75681f385f4", - }, - ], - "flatIndexMetadatas": [], - "labelPlural": "Companies", - "labelSingular": "Company", - "namePlural": "Companies", - "nameSingular": "Company", - "uniqueIdentifier": "20202020-1218-4fc0-b32d-fc4f005c4bab", - }, - "type": "create_object", - }, - { - "flatObjectMetadata": { - "description": "A contact", - "flatFieldMetadatas": [ - { - "defaultValue": "", - "description": "", - "label": "First Name", - "name": "firstName", - "type": "FULL_NAME", - "uniqueIdentifier": "20202020-e89b-12d3-a456-426614174000", - }, - ], - "flatIndexMetadatas": [], - "labelPlural": "Contacts", - "labelSingular": "Contact", - "namePlural": "Contacts", - "nameSingular": "Contact", - "uniqueIdentifier": "20202020-59ef-4a14-a509-0a02acb248d5", - }, - "type": "delete_object", - }, - { - "flatObjectMetadata": { - "description": "A contact", - "flatFieldMetadatas": [ - { - "defaultValue": "", - "description": "", - "label": "First Name", - "name": "firstName", - "type": "FULL_NAME", - "uniqueIdentifier": "20202020-e89b-12d3-a456-426614174000", - }, - { - "defaultValue": "", - "description": "new field description", - "label": "New field", - "name": "newField", - "type": "NUMBER", - "uniqueIdentifier": "20202020-3ad3-4fec-9c46-8dc9158980e3", - }, - ], - "flatIndexMetadatas": [], - "labelPlural": "Contacts", - "labelSingular": "Contact", - "namePlural": "Contacts", - "nameSingular": "Person", - "uniqueIdentifier": "20202020-e89b-12d3-a456-426614175000", - }, - "type": "update_object", - "updates": [ - { - "from": "Contact", - "property": "nameSingular", - "to": "Person", - }, - ], - }, - { - "flatFieldMetadata": { - "defaultValue": "", - "description": "", - "label": "Name", - "name": "name", - "type": "ADDRESS", - "uniqueIdentifier": "20202020-1016-4f09-bad6-e75681f385f4", - }, - "flatObjectMetadata": { - "description": "A company", - "flatFieldMetadatas": [ - { - "defaultValue": "", - "description": "", - "label": "Name", - "name": "name", - "type": "ADDRESS", - "uniqueIdentifier": "20202020-1016-4f09-bad6-e75681f385f4", - }, - ], - "flatIndexMetadatas": [], - "labelPlural": "Companies", - "labelSingular": "Company", - "namePlural": "Companies", - "nameSingular": "Company", - "uniqueIdentifier": "20202020-1218-4fc0-b32d-fc4f005c4bab", - }, - "type": "create_field", - }, - { - "flatFieldMetadata": { - "defaultValue": "", - "description": "new field description", - "label": "New field", - "name": "newField", - "type": "NUMBER", - "uniqueIdentifier": "20202020-3ad3-4fec-9c46-8dc9158980e3", - }, - "flatObjectMetadata": { - "description": "A contact", - "flatFieldMetadatas": [ - { - "defaultValue": "", - "description": "", - "label": "First Name", - "name": "firstName", - "type": "FULL_NAME", - "uniqueIdentifier": "20202020-e89b-12d3-a456-426614174000", - }, - { - "defaultValue": "", - "description": "new field description", - "label": "New field", - "name": "newField", - "type": "NUMBER", - "uniqueIdentifier": "20202020-3ad3-4fec-9c46-8dc9158980e3", - }, - ], - "flatIndexMetadatas": [], - "labelPlural": "Contacts", - "labelSingular": "Contact", - "namePlural": "Contacts", - "nameSingular": "Person", - "uniqueIdentifier": "20202020-e89b-12d3-a456-426614175000", - }, - "type": "create_field", - }, - ], -} -`); - }); - - it('should treat objects with the same name but different IDs as distinct', () => { - const objectA: FlatObjectMetadata = { - uniqueIdentifier: 'id-1', - flatIndexMetadatas: [], - nameSingular: 'Duplicate', - namePlural: 'Duplicates', - labelSingular: 'Duplicate', - labelPlural: 'Duplicates', - description: 'First object', - flatFieldMetadatas: [ - { - uniqueIdentifier: 'field-1', - name: 'fieldA', - label: 'Field A', - type: FieldMetadataType.FULL_NAME, - defaultValue: '', - description: '', - }, - ], - }; - const objectB: FlatObjectMetadata = { - uniqueIdentifier: 'id-2', - nameSingular: 'Duplicate', - namePlural: 'Duplicates', - labelSingular: 'Duplicate', - labelPlural: 'Duplicates', - flatIndexMetadatas: [], - description: 'Second object', - flatFieldMetadatas: [ - { - uniqueIdentifier: 'field-2', - name: 'fieldB', - label: 'Field B', - type: FieldMetadataType.ADDRESS, - defaultValue: '', - description: '', - }, - ], - }; - - const result = service.build({ from: [], to: [objectA, objectB] }); - - expect(result.actions).toMatchInlineSnapshot(` -[ - { - "flatObjectMetadata": { - "description": "First object", - "flatFieldMetadatas": [ - { - "defaultValue": "", - "description": "", - "label": "Field A", - "name": "fieldA", - "type": "FULL_NAME", - "uniqueIdentifier": "field-1", - }, - ], - "flatIndexMetadatas": [], - "labelPlural": "Duplicates", - "labelSingular": "Duplicate", - "namePlural": "Duplicates", - "nameSingular": "Duplicate", - "uniqueIdentifier": "id-1", - }, - "type": "create_object", - }, - { - "flatObjectMetadata": { - "description": "Second object", - "flatFieldMetadatas": [ - { - "defaultValue": "", - "description": "", - "label": "Field B", - "name": "fieldB", - "type": "ADDRESS", - "uniqueIdentifier": "field-2", - }, - ], - "flatIndexMetadatas": [], - "labelPlural": "Duplicates", - "labelSingular": "Duplicate", - "namePlural": "Duplicates", - "nameSingular": "Duplicate", - "uniqueIdentifier": "id-2", - }, - "type": "create_object", - }, - { - "flatFieldMetadata": { - "defaultValue": "", - "description": "", - "label": "Field A", - "name": "fieldA", - "type": "FULL_NAME", - "uniqueIdentifier": "field-1", - }, - "flatObjectMetadata": { - "description": "First object", - "flatFieldMetadatas": [ - { - "defaultValue": "", - "description": "", - "label": "Field A", - "name": "fieldA", - "type": "FULL_NAME", - "uniqueIdentifier": "field-1", - }, - ], - "flatIndexMetadatas": [], - "labelPlural": "Duplicates", - "labelSingular": "Duplicate", - "namePlural": "Duplicates", - "nameSingular": "Duplicate", - "uniqueIdentifier": "id-1", - }, - "type": "create_field", - }, - { - "flatFieldMetadata": { - "defaultValue": "", - "description": "", - "label": "Field B", - "name": "fieldB", - "type": "ADDRESS", - "uniqueIdentifier": "field-2", - }, - "flatObjectMetadata": { - "description": "Second object", - "flatFieldMetadatas": [ - { - "defaultValue": "", - "description": "", - "label": "Field B", - "name": "fieldB", - "type": "ADDRESS", - "uniqueIdentifier": "field-2", - }, - ], - "flatIndexMetadatas": [], - "labelPlural": "Duplicates", - "labelSingular": "Duplicate", - "namePlural": "Duplicates", - "nameSingular": "Duplicate", - "uniqueIdentifier": "id-2", - }, - "type": "create_field", - }, -] -`); - - const deleteResult = service.build({ from: [objectA, objectB], to: [] }); - - expect(deleteResult.actions).toMatchInlineSnapshot(` -[ - { - "flatObjectMetadata": { - "description": "First object", - "flatFieldMetadatas": [ - { - "defaultValue": "", - "description": "", - "label": "Field A", - "name": "fieldA", - "type": "FULL_NAME", - "uniqueIdentifier": "field-1", - }, - ], - "flatIndexMetadatas": [], - "labelPlural": "Duplicates", - "labelSingular": "Duplicate", - "namePlural": "Duplicates", - "nameSingular": "Duplicate", - "uniqueIdentifier": "id-1", - }, - "type": "delete_object", - }, - { - "flatObjectMetadata": { - "description": "Second object", - "flatFieldMetadatas": [ - { - "defaultValue": "", - "description": "", - "label": "Field B", - "name": "fieldB", - "type": "ADDRESS", - "uniqueIdentifier": "field-2", - }, - ], - "flatIndexMetadatas": [], - "labelPlural": "Duplicates", - "labelSingular": "Duplicate", - "namePlural": "Duplicates", - "nameSingular": "Duplicate", - "uniqueIdentifier": "id-2", - }, - "type": "delete_object", - }, -] -`); - }); - - it('should emit no actions when from and to are deeply equal', () => { - 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 deleted file mode 100644 index 6e931bf0f..000000000 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-v2-indexes-builder.spec.ts +++ /dev/null @@ -1,522 +0,0 @@ -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 deleted file mode 100644 index 19e14c6b6..000000000 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-v2-relations-builder.spec.ts +++ /dev/null @@ -1,431 +0,0 @@ -import { FieldMetadataType } from 'twenty-shared/types'; - -import { FieldMetadataSettings } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface'; -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 { 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', () => { - let service: WorkspaceMigrationBuilderV2Service; - - beforeEach(() => { - service = new WorkspaceMigrationBuilderV2Service(); - }); - - const createMockObject = ( - identifier: string, - fields: Partial[] = [], - ): FlatObjectMetadata => ({ - uniqueIdentifier: identifier, - flatIndexMetadatas: [], - flatFieldMetadatas: fields.map((field) => ({ - type: FieldMetadataType.TEXT, - name: 'defaultName', - label: 'Default Label', - isCustom: true, - isActive: true, - isNullable: true, - uniqueIdentifier: 'default-id', - ...field, - })), - }); - - describe('buildWorkspaceMigrationV2RelationActions', () => { - it('should create relation actions for created fields', () => { - const fromObjects: FlatObjectMetadata[] = []; - const toObjects: FlatObjectMetadata[] = [ - createMockObject('company', [ - { - type: FieldMetadataType.RELATION, - name: 'employees', - label: 'Employees', - uniqueIdentifier: 'employees', - relationTargetFieldMetadataId: 'field-2', - relationTargetObjectMetadataId: 'obj-2', - }, - ]), - ]; - - const result = service.build({ from: fromObjects, to: toObjects }); - - expect(result).toMatchInlineSnapshot(` -{ - "actions": [ - { - "flatObjectMetadata": { - "flatFieldMetadatas": [ - { - "isActive": true, - "isCustom": true, - "isNullable": true, - "label": "Employees", - "name": "employees", - "relationTargetFieldMetadataId": "field-2", - "relationTargetObjectMetadataId": "obj-2", - "type": "RELATION", - "uniqueIdentifier": "employees", - }, - ], - "flatIndexMetadatas": [], - "uniqueIdentifier": "company", - }, - "type": "create_object", - }, - { - "flatFieldMetadata": { - "isActive": true, - "isCustom": true, - "isNullable": true, - "label": "Employees", - "name": "employees", - "relationTargetFieldMetadataId": "field-2", - "relationTargetObjectMetadataId": "obj-2", - "type": "RELATION", - "uniqueIdentifier": "employees", - }, - "flatObjectMetadata": { - "flatFieldMetadatas": [ - { - "isActive": true, - "isCustom": true, - "isNullable": true, - "label": "Employees", - "name": "employees", - "relationTargetFieldMetadataId": "field-2", - "relationTargetObjectMetadataId": "obj-2", - "type": "RELATION", - "uniqueIdentifier": "employees", - }, - ], - "flatIndexMetadatas": [], - "uniqueIdentifier": "company", - }, - "type": "create_field", - }, - ], -} -`); - }); - - it('should create delete actions for deleted fields', () => { - const fromObjects: FlatObjectMetadata[] = [ - createMockObject('company', [ - { - type: FieldMetadataType.RELATION, - name: 'employees', - label: 'Employees', - uniqueIdentifier: 'employees', - relationTargetFieldMetadataId: 'field-2', - relationTargetObjectMetadataId: 'obj-2', - }, - ]), - ]; - const toObjects: FlatObjectMetadata[] = [createMockObject('company')]; - - const result = service.build({ from: fromObjects, to: toObjects }); - - expect(result).toMatchInlineSnapshot(` -{ - "actions": [ - { - "flatFieldMetadata": { - "isActive": true, - "isCustom": true, - "isNullable": true, - "label": "Employees", - "name": "employees", - "relationTargetFieldMetadataId": "field-2", - "relationTargetObjectMetadataId": "obj-2", - "type": "RELATION", - "uniqueIdentifier": "employees", - }, - "flatObjectMetadata": { - "flatFieldMetadatas": [], - "flatIndexMetadatas": [], - "uniqueIdentifier": "company", - }, - "type": "delete_field", - }, - ], -} -`); - }); - - it('should handle multiple relation changes across different objects', () => { - const fromObjects: FlatObjectMetadata[] = [ - createMockObject('company', [ - { - type: FieldMetadataType.RELATION, - name: 'oldRelation', - label: 'Old Relation', - uniqueIdentifier: 'old-relation', - relationTargetFieldMetadataId: 'field-1', - relationTargetObjectMetadataId: 'obj-1', - }, - ]), - ]; - const toObjects: FlatObjectMetadata[] = [ - createMockObject('company', [ - { - type: FieldMetadataType.RELATION, - name: 'newRelation', - label: 'New Relation', - uniqueIdentifier: 'new-relation', - relationTargetFieldMetadataId: 'field-2', - relationTargetObjectMetadataId: 'obj-2', - }, - ]), - createMockObject('person', [ - { - type: FieldMetadataType.RELATION, - name: 'manager', - label: 'Manager', - uniqueIdentifier: 'manager', - relationTargetFieldMetadataId: 'field-3', - relationTargetObjectMetadataId: 'obj-3', - }, - ]), - ]; - - const result = service.build({ from: fromObjects, to: toObjects }); - - expect(result).toMatchInlineSnapshot(` -{ - "actions": [ - { - "flatObjectMetadata": { - "flatFieldMetadatas": [ - { - "isActive": true, - "isCustom": true, - "isNullable": true, - "label": "Manager", - "name": "manager", - "relationTargetFieldMetadataId": "field-3", - "relationTargetObjectMetadataId": "obj-3", - "type": "RELATION", - "uniqueIdentifier": "manager", - }, - ], - "flatIndexMetadatas": [], - "uniqueIdentifier": "person", - }, - "type": "create_object", - }, - { - "flatFieldMetadata": { - "isActive": true, - "isCustom": true, - "isNullable": true, - "label": "Manager", - "name": "manager", - "relationTargetFieldMetadataId": "field-3", - "relationTargetObjectMetadataId": "obj-3", - "type": "RELATION", - "uniqueIdentifier": "manager", - }, - "flatObjectMetadata": { - "flatFieldMetadatas": [ - { - "isActive": true, - "isCustom": true, - "isNullable": true, - "label": "Manager", - "name": "manager", - "relationTargetFieldMetadataId": "field-3", - "relationTargetObjectMetadataId": "obj-3", - "type": "RELATION", - "uniqueIdentifier": "manager", - }, - ], - "flatIndexMetadatas": [], - "uniqueIdentifier": "person", - }, - "type": "create_field", - }, - { - "flatFieldMetadata": { - "isActive": true, - "isCustom": true, - "isNullable": true, - "label": "New Relation", - "name": "newRelation", - "relationTargetFieldMetadataId": "field-2", - "relationTargetObjectMetadataId": "obj-2", - "type": "RELATION", - "uniqueIdentifier": "new-relation", - }, - "flatObjectMetadata": { - "flatFieldMetadatas": [ - { - "isActive": true, - "isCustom": true, - "isNullable": true, - "label": "New Relation", - "name": "newRelation", - "relationTargetFieldMetadataId": "field-2", - "relationTargetObjectMetadataId": "obj-2", - "type": "RELATION", - "uniqueIdentifier": "new-relation", - }, - ], - "flatIndexMetadatas": [], - "uniqueIdentifier": "company", - }, - "type": "create_field", - }, - { - "flatFieldMetadata": { - "isActive": true, - "isCustom": true, - "isNullable": true, - "label": "Old Relation", - "name": "oldRelation", - "relationTargetFieldMetadataId": "field-1", - "relationTargetObjectMetadataId": "obj-1", - "type": "RELATION", - "uniqueIdentifier": "old-relation", - }, - "flatObjectMetadata": { - "flatFieldMetadatas": [ - { - "isActive": true, - "isCustom": true, - "isNullable": true, - "label": "New Relation", - "name": "newRelation", - "relationTargetFieldMetadataId": "field-2", - "relationTargetObjectMetadataId": "obj-2", - "type": "RELATION", - "uniqueIdentifier": "new-relation", - }, - ], - "flatIndexMetadatas": [], - "uniqueIdentifier": "company", - }, - "type": "delete_field", - }, - ], -} -`); - }); - - it('should handle empty objects', () => { - const result = service.build({ from: [], to: [] }); - - expect(result).toMatchInlineSnapshot(` -{ - "actions": [], -} -`); - }); - - it('should handle objects with no relation 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 relation field updates', () => { - const baseField = { - type: FieldMetadataType.RELATION, - name: 'employees', - label: 'Employees', - uniqueIdentifier: 'employees', - isCustom: true, - isActive: true, - isNullable: true, - description: 'Company employees', - }; - - const fromObjects: FlatObjectMetadata[] = [ - createMockObject('company', [ - { - ...baseField, - relationTargetFieldMetadataId: 'field-1', - relationTargetObjectMetadataId: 'obj-1', - settings: { - relationType: RelationType.ONE_TO_MANY, - onDelete: RelationOnDeleteAction.CASCADE, - } as FieldMetadataSettings, - }, - ]), - ]; - - const toObjects: FlatObjectMetadata[] = [ - { - ...fromObjects[0], - flatFieldMetadatas: [ - { - ...baseField, - name: 'updatedName', - }, - ], - }, - ]; - - const result = service.build({ from: fromObjects, to: toObjects }); - - expect(result).toMatchInlineSnapshot(` -{ - "actions": [ - { - "flatFieldMetadata": { - "description": "Company employees", - "isActive": true, - "isCustom": true, - "isNullable": true, - "label": "Employees", - "name": "updatedName", - "type": "RELATION", - "uniqueIdentifier": "employees", - }, - "flatObjectMetadata": { - "flatFieldMetadatas": [ - { - "description": "Company employees", - "isActive": true, - "isCustom": true, - "isNullable": true, - "label": "Employees", - "name": "updatedName", - "type": "RELATION", - "uniqueIdentifier": "employees", - }, - ], - "flatIndexMetadatas": [], - "uniqueIdentifier": "company", - }, - "type": "update_field", - "updates": [ - { - "from": "employees", - "property": "name", - "to": "updatedName", - }, - ], - }, - ], -} -`); - }); - }); -}); diff --git a/packages/twenty-server/test/integration/metadata/suites/field-metadata/relation/failing-field-metadata-relation-creation.integration-spec.ts b/packages/twenty-server/test/integration/metadata/suites/field-metadata/relation/failing-field-metadata-relation-creation.integration-spec.ts index ad89a48b1..8562cc718 100644 --- a/packages/twenty-server/test/integration/metadata/suites/field-metadata/relation/failing-field-metadata-relation-creation.integration-spec.ts +++ b/packages/twenty-server/test/integration/metadata/suites/field-metadata/relation/failing-field-metadata-relation-creation.integration-spec.ts @@ -1,4 +1,4 @@ -import { faker } from '@faker-js/faker/.'; +import { faker } from '@faker-js/faker'; import { createOneFieldMetadata } from 'test/integration/metadata/suites/field-metadata/utils/create-one-field-metadata.util'; import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util'; import { deleteOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata.util'; diff --git a/packages/twenty-server/test/utils/extract-record-ids-and-dates-as-expect-any.ts b/packages/twenty-server/test/utils/extract-record-ids-and-dates-as-expect-any.ts new file mode 100644 index 000000000..b82ae77ca --- /dev/null +++ b/packages/twenty-server/test/utils/extract-record-ids-and-dates-as-expect-any.ts @@ -0,0 +1,46 @@ +import { isDefined } from 'twenty-shared/utils'; + +export const extractRecordIdsAndDatesAsExpectAny = ( + record: Record | Array>, +): any => { + if (Array.isArray(record)) { + return record.map(extractRecordIdsAndDatesAsExpectAny); + } + + if (typeof record !== 'object') { + throw new Error( + 'extractRecordIdsAndDatesAsExpectAny should be called with an array or a record only', + ); + } + + return Object.entries(record).reduce((acc, [key, value]) => { + if (!isDefined(value)) { + return acc; + } + + if (key.endsWith('Id') || key === 'id') { + return { + ...acc, + [key]: expect.any(String), + }; + } + + if (value instanceof Date) { + return { + ...acc, + [key]: expect.any(Date), + }; + } + + if (typeof value === 'object' || Array.isArray(value)) { + return { + ...acc, + [key]: extractRecordIdsAndDatesAsExpectAny( + value as Record, + ), + }; + } + + return acc; + }, {}); +}; diff --git a/packages/twenty-shared/src/testing/EachTestingContextFilter.ts b/packages/twenty-shared/src/testing/EachTestingContextFilter.ts new file mode 100644 index 000000000..5edf01bdd --- /dev/null +++ b/packages/twenty-shared/src/testing/EachTestingContextFilter.ts @@ -0,0 +1,20 @@ +import { EachTestingContext } from '@/testing/types/EachTestingContext.type'; + +export const eachTestingContextFilter = ( + testCases: EachTestingContext[], +) => { + const onlyTestsCases = testCases.filter((testCase) => testCase.only === true); + + if (process.env.CI && onlyTestsCases.length > 0) { + console.warn( + 'Should never push tests cases with an only to true, only to use in dev env\n returning the whole test suite anyway', + ); + return testCases; + } + + if (onlyTestsCases.length > 0) { + return onlyTestsCases; + } + + return testCases; +}; diff --git a/packages/twenty-shared/src/testing/index.ts b/packages/twenty-shared/src/testing/index.ts index 5ca352654..512d92d86 100644 --- a/packages/twenty-shared/src/testing/index.ts +++ b/packages/twenty-shared/src/testing/index.ts @@ -7,5 +7,6 @@ * |___/ */ +export { eachTestingContextFilter } from './EachTestingContextFilter'; export type { EachTestingContext } from './types/EachTestingContext.type'; export type { SuccessfulAndFailingTestCases } from './types/SuccessfulAndFailingTestCases'; diff --git a/packages/twenty-shared/src/testing/types/EachTestingContext.type.ts b/packages/twenty-shared/src/testing/types/EachTestingContext.type.ts index 8b35cd7f0..c6ea69d9c 100644 --- a/packages/twenty-shared/src/testing/types/EachTestingContext.type.ts +++ b/packages/twenty-shared/src/testing/types/EachTestingContext.type.ts @@ -1,4 +1,5 @@ export type EachTestingContext = { title: string; context: T; + only?: true; };