diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.service.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.service.ts index 9682e2f756..bca0132d83 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.service.ts @@ -424,14 +424,14 @@ export class ObjectMetadataService extends TypeOrmQueryService + relations.map((relation) => relation.toObjectMetadataId), + ); - const fieldsWihStandardRelation = await this.fieldMetadataRepository.find( - { + const foreignKeyFieldMetadataForStandardRelation = + await this.fieldMetadataRepository.find({ where: { isCustom: false, settings: { isForeignKey: true, }, name: `${existingObjectMetadata.nameSingular}Id`, + workspaceId: workspaceId, }, - }, - ); - - await this.fieldMetadataRepository.update(searchCriteria, { - name: `${updatedObjectMetadata.nameSingular}Id`, - }); + }); await Promise.all( - fieldsWihStandardRelation.map(async (fieldWihStandardRelation) => { - const relatedObject = await this.objectMetadataRepository.findOneBy({ - id: fieldWihStandardRelation.objectMetadataId, - workspaceId: workspaceId, - }); + foreignKeyFieldMetadataForStandardRelation.map( + async (foreignKeyFieldMetadata) => { + if ( + relatedObjectsIds.includes( + foreignKeyFieldMetadata.objectMetadataId, + ) + ) { + const relatedObject = + await this.objectMetadataRepository.findOneBy({ + id: foreignKeyFieldMetadata.objectMetadataId, + workspaceId: workspaceId, + }); - if (relatedObject) { - await this.fieldMetadataRepository.update( - { - name: existingObjectMetadata.nameSingular, - label: existingObjectMetadata.labelSingular, - }, - { - name: updatedObjectMetadata.nameSingular, - label: updatedObjectMetadata.labelSingular, - }, - ); + if (relatedObject) { + // 1. Update to and from relation fieldMetadata) + const toFieldRelationFieldMetadataId = + await this.fieldMetadataRepository + .findOneByOrFail({ + name: existingObjectMetadata.nameSingular, + label: existingObjectMetadata.labelSingular, + objectMetadataId: relatedObject.id, + workspaceId: workspaceId, + }) + .then((field) => field.id); - const relationTableName = computeObjectTargetTable(relatedObject); - const columnName = `${existingObjectMetadata.nameSingular}Id`; - const columnType = fieldMetadataTypeToColumnType( - fieldWihStandardRelation.type, - ); + const { description: descriptionForToField } = + buildDescriptionForRelationFieldMetadataOnToField({ + relationObjectMetadataNamePlural: relatedObject.namePlural, + targetObjectLabelSingular: + updatedObjectMetadata.labelSingular, + }); - await this.workspaceMigrationService.createCustomMigration( - generateMigrationName( - `rename-${existingObjectMetadata.nameSingular}-to-${updatedObjectMetadata.nameSingular}-in-${relatedObject.nameSingular}`, - ), - workspaceId, - [ - { - name: relationTableName, - action: WorkspaceMigrationTableActionType.ALTER, - columns: [ + await this.fieldMetadataRepository.update( + toFieldRelationFieldMetadataId, + { + name: updatedObjectMetadata.nameSingular, + label: updatedObjectMetadata.labelSingular, + description: descriptionForToField, + }, + ); + + const fromFieldRelationFieldMetadataId = + await this.relationMetadataRepository + .findOneByOrFail({ + fromObjectMetadataId: existingObjectMetadata.id, + toObjectMetadataId: relatedObject.id, + toFieldMetadataId: toFieldRelationFieldMetadataId, + workspaceId, + }) + .then((relation) => relation?.fromFieldMetadataId); + + await this.fieldMetadataRepository.update( + fromFieldRelationFieldMetadataId, + { + description: + buildDescriptionForRelationFieldMetadataOnFromField({ + relationObjectMetadataNamePlural: + relatedObject.namePlural, + targetObjectLabelSingular: + updatedObjectMetadata.labelSingular, + }).description, + }, + ); + + // 2. Update foreign key fieldMetadata + const { + name: updatedNameForForeignKeyFieldMetadata, + label: updatedLabelForForeignKeyFieldMetadata, + description: updatedDescriptionForForeignKeyFieldMetadata, + } = buildNameLabelAndDescriptionForForeignKeyFieldMetadata({ + targetObjectNameSingular: updatedObjectMetadata.nameSingular, + targetObjectLabelSingular: + updatedObjectMetadata.labelSingular, + relatedObjectLabelSingular: relatedObject.labelSingular, + }); + + await this.fieldMetadataRepository.update( + foreignKeyFieldMetadata.id, + { + name: updatedNameForForeignKeyFieldMetadata, + label: updatedLabelForForeignKeyFieldMetadata, + description: updatedDescriptionForForeignKeyFieldMetadata, + }, + ); + + const relatedObjectTableName = + computeObjectTargetTable(relatedObject); + const columnName = `${existingObjectMetadata.nameSingular}Id`; + const columnType = fieldMetadataTypeToColumnType( + foreignKeyFieldMetadata.type, + ); + + await this.workspaceMigrationService.createCustomMigration( + generateMigrationName( + `rename-${existingObjectMetadata.nameSingular}-to-${updatedObjectMetadata.nameSingular}-in-${relatedObject.nameSingular}`, + ), + workspaceId, + [ { - action: WorkspaceMigrationColumnActionType.ALTER, - currentColumnDefinition: { - columnName, - columnType, - isNullable: true, - defaultValue: null, - }, - alteredColumnDefinition: { - columnName: `${updatedObjectMetadata.nameSingular}Id`, - columnType, - isNullable: true, - defaultValue: null, - }, + name: relatedObjectTableName, + action: WorkspaceMigrationTableActionType.ALTER, + columns: [ + { + action: WorkspaceMigrationColumnActionType.ALTER, + currentColumnDefinition: { + columnName, + columnType, + isNullable: true, + defaultValue: null, + }, + alteredColumnDefinition: { + columnName: `${updatedObjectMetadata.nameSingular}Id`, + columnType, + isNullable: true, + defaultValue: null, + }, + }, + ], }, ], - }, - ], - ); - } - }), + ); + } + } + }, + ), ); } } diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/services/object-metadata-relation.service.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/services/object-metadata-relation.service.ts index 68f35492c3..74dac774e0 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/services/object-metadata-relation.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/services/object-metadata-relation.service.ts @@ -10,6 +10,9 @@ import { FieldMetadataType, } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { buildDescriptionForRelationFieldMetadataOnFromField } from 'src/engine/metadata-modules/object-metadata/utils/build-description-for-relation-field-on-from-field.util'; +import { buildDescriptionForRelationFieldMetadataOnToField } from 'src/engine/metadata-modules/object-metadata/utils/build-description-for-relation-field-on-to-field.util'; +import { buildNameLabelAndDescriptionForForeignKeyFieldMetadata } from 'src/engine/metadata-modules/object-metadata/utils/build-name-label-and-description-for-foreign-key-field-metadata.util'; import { RelationMetadataEntity, RelationMetadataType, @@ -94,6 +97,13 @@ export class ObjectMetadataRelationService { ); } + const { name, label, description } = + buildNameLabelAndDescriptionForForeignKeyFieldMetadata({ + targetObjectNameSingular: createdObjectMetadata.nameSingular, + targetObjectLabelSingular: createdObjectMetadata.labelSingular, + relatedObjectLabelSingular: relatedObjectMetadata.labelSingular, + }); + await this.fieldMetadataRepository.save({ standardId: createForeignKeyDeterministicUuid({ objectId: createdObjectMetadata.id, @@ -104,9 +114,9 @@ export class ObjectMetadataRelationService { isCustom: false, isActive: true, type: objectPrimaryKeyType, - name: `${createdObjectMetadata.nameSingular}Id`, - label: `${createdObjectMetadata.labelSingular} ID (foreign key)`, - description: `${relatedObjectMetadata.labelSingular} ${createdObjectMetadata.labelSingular} id foreign key`, + name, + label, + description, icon: undefined, isNullable: true, isSystem: true, @@ -141,6 +151,13 @@ export class ObjectMetadataRelationService { ) { const relationObjectMetadataNamePlural = relatedObjectMetadata.namePlural; + const { description } = buildDescriptionForRelationFieldMetadataOnFromField( + { + relationObjectMetadataNamePlural, + targetObjectLabelSingular: createdObjectMetadata.labelSingular, + }, + ); + return { standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS[relationObjectMetadataNamePlural], @@ -152,7 +169,7 @@ export class ObjectMetadataRelationService { type: FieldMetadataType.RELATION, name: relatedObjectMetadata.namePlural, label: capitalize(relationObjectMetadataNamePlural), - description: `${capitalize(relationObjectMetadataNamePlural)} tied to the ${createdObjectMetadata.labelSingular}`, + description, icon: STANDARD_OBJECT_ICONS[relatedObjectMetadata.nameSingular] || 'IconBuildingSkyscraper', @@ -174,6 +191,11 @@ export class ObjectMetadataRelationService { ); } + const { description } = buildDescriptionForRelationFieldMetadataOnToField({ + relationObjectMetadataNamePlural: relatedObjectMetadata.namePlural, + targetObjectLabelSingular: createdObjectMetadata.labelSingular, + }); + return { standardId: createRelationDeterministicUuid({ objectId: createdObjectMetadata.id, @@ -187,7 +209,7 @@ export class ObjectMetadataRelationService { type: FieldMetadataType.RELATION, name: createdObjectMetadata.nameSingular, label: createdObjectMetadata.labelSingular, - description: `${capitalize(relatedObjectMetadata.nameSingular)} ${createdObjectMetadata.labelSingular}`, + description, icon: 'IconBuildingSkyscraper', isNullable: true, }; diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-description-for-relation-field-on-from-field.util.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-description-for-relation-field-on-from-field.util.ts new file mode 100644 index 0000000000..3f7d98e131 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-description-for-relation-field-on-from-field.util.ts @@ -0,0 +1,13 @@ +import { capitalize } from 'src/utils/capitalize'; + +export const buildDescriptionForRelationFieldMetadataOnFromField = ({ + relationObjectMetadataNamePlural, + targetObjectLabelSingular, +}: { + relationObjectMetadataNamePlural: string; + targetObjectLabelSingular: string; +}) => { + const description = `${capitalize(relationObjectMetadataNamePlural)} tied to the ${targetObjectLabelSingular}`; + + return { description }; +}; diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-description-for-relation-field-on-to-field.util.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-description-for-relation-field-on-to-field.util.ts new file mode 100644 index 0000000000..fb15c56aeb --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-description-for-relation-field-on-to-field.util.ts @@ -0,0 +1,13 @@ +import { capitalize } from 'src/utils/capitalize'; + +export const buildDescriptionForRelationFieldMetadataOnToField = ({ + relationObjectMetadataNamePlural, + targetObjectLabelSingular, +}: { + relationObjectMetadataNamePlural: string; + targetObjectLabelSingular: string; +}) => { + const description = `${capitalize(relationObjectMetadataNamePlural)} ${targetObjectLabelSingular}`; + + return { description }; +}; diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-name-label-and-description-for-foreign-key-field-metadata.util.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-name-label-and-description-for-foreign-key-field-metadata.util.ts new file mode 100644 index 0000000000..d6e4134a49 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-name-label-and-description-for-foreign-key-field-metadata.util.ts @@ -0,0 +1,15 @@ +export const buildNameLabelAndDescriptionForForeignKeyFieldMetadata = ({ + targetObjectNameSingular, + targetObjectLabelSingular, + relatedObjectLabelSingular, +}: { + targetObjectNameSingular: string; + targetObjectLabelSingular: string; + relatedObjectLabelSingular: string; +}) => { + const name = `${targetObjectNameSingular}Id`; + const label = `${targetObjectLabelSingular} ID (foreign key)`; + const description = `${relatedObjectLabelSingular} ${targetObjectLabelSingular} id foreign key`; + + return { name, label, description }; +}; diff --git a/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.service.ts b/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.service.ts index a98f2f0024..2b149b73f7 100644 --- a/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/relation-metadata/relation-metadata.service.ts @@ -332,6 +332,7 @@ export class RelationMetadataService extends TypeOrmQueryService