Fix workspace relation sync (#11963)

## Context

While deploying the IS_NEW_RELATION_ENABLED (we don't compute relation
based on relationMetadata anymore) to existing workspace, I've tested to
run a sync-metadata post feature flag activation. This has raised two
issues:
- the workspaceMigration generator (which is over-complex and should be
refactored later) for fieldMetadata of type RELATION was not handling
settings update properly ;
- we need to delete existing fieldMetadata corresponding to the UUID
foreignKey as they are not needed anymore. This is handled as a 0.53
upgrade command as 0.53 will also come with the full removal of the old
relation system

---------

Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
Co-authored-by: prastoin <paul@twenty.com>
This commit is contained in:
Charles Bochet
2025-05-09 19:03:39 +02:00
committed by GitHub
parent 3308ba56b2
commit 8216800a4a
7 changed files with 166 additions and 63 deletions

View File

@ -18,7 +18,6 @@ import { WorkspaceMigrationFactory } from 'src/engine/metadata-modules/workspace
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
import { isFieldMetadataEntityOfType } from 'src/engine/utils/is-field-metadata-of-type.util';
import { FieldMetadataUpdate } from 'src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-field.factory';
import { camelCase } from 'src/utils/camel-case';
@Injectable()
export class WorkspaceMigrationFieldRelationFactory {
constructor(
@ -101,6 +100,24 @@ export class WorkspaceMigrationFieldRelationFactory {
);
}
if (!sourceFieldMetadata.settings) {
throw new Error(
`FieldMetadata for relation with id ${sourceFieldMetadata.id} has no settings`,
);
}
if (
sourceFieldMetadata.settings.relationType !== RelationType.MANY_TO_ONE
) {
continue;
}
if (!sourceFieldMetadata.settings.joinColumnName) {
throw new Error(
`FieldMetadata with id ${sourceFieldMetadata.id} has no join column name in settings`,
);
}
if (!targetObjectMetadata) {
throw new Error(
`ObjectMetadata with id ${sourceFieldMetadata.relationTargetObjectMetadataId} not found`,
@ -137,29 +154,27 @@ export class WorkspaceMigrationFieldRelationFactory {
const migrations: WorkspaceMigrationTableAction[] = [
{
name: computeObjectTargetTable(targetObjectMetadata),
name: computeObjectTargetTable(sourceObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
{
action: WorkspaceMigrationColumnActionType.DROP_FOREIGN_KEY,
columnName: `${camelCase(targetFieldMetadata.name)}Id`,
columnName: sourceFieldMetadata.settings.joinColumnName,
},
],
},
{
name: computeObjectTargetTable(targetObjectMetadata),
name: computeObjectTargetTable(sourceObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
{
action: WorkspaceMigrationColumnActionType.CREATE_FOREIGN_KEY,
columnName: `${camelCase(targetFieldMetadata.name)}Id`,
columnName: sourceFieldMetadata.settings.joinColumnName,
referencedTableName:
computeObjectTargetTable(sourceObjectMetadata),
computeObjectTargetTable(targetObjectMetadata),
referencedTableColumnName: 'id',
isUnique:
targetFieldMetadata.settings.relationType ===
RelationType.ONE_TO_ONE,
onDelete: targetFieldMetadata.settings.onDelete,
isUnique: false,
onDelete: sourceFieldMetadata.settings.onDelete,
},
],
},
@ -192,22 +207,27 @@ export class WorkspaceMigrationFieldRelationFactory {
sourceFieldMetadata.relationTargetObjectMetadataId
];
if (!sourceObjectMetadata) {
throw new Error(
`ObjectMetadata with id ${sourceFieldMetadata.objectMetadataId} not found`,
);
}
if (!sourceFieldMetadata.settings) {
throw new Error(
`FieldMetadata for relation with id ${sourceFieldMetadata.id} has no settings`,
);
}
// We're creating it from `ONE_TO_MANY` with the join column so we don't need to create a migration for `MANY_TO_ONE`
if (
sourceFieldMetadata.settings.relationType === RelationType.MANY_TO_ONE
sourceFieldMetadata.settings.relationType !== RelationType.MANY_TO_ONE
) {
continue;
}
if (!sourceObjectMetadata) {
if (!sourceFieldMetadata.settings.joinColumnName) {
throw new Error(
`ObjectMetadata with id ${sourceFieldMetadata.objectMetadataId} not found`,
`FieldMetadata with id ${sourceFieldMetadata.id} has no join column name in settings`,
);
}
@ -239,43 +259,29 @@ export class WorkspaceMigrationFieldRelationFactory {
);
}
if (!targetFieldMetadata.settings) {
throw new Error(
`FieldMetadata for relation with id ${sourceFieldMetadata.id} has no settings`,
);
}
if (!targetFieldMetadata.settings.joinColumnName) {
continue;
}
const migrations: WorkspaceMigrationTableAction[] = [
{
name: computeObjectTargetTable(targetObjectMetadata),
name: computeObjectTargetTable(sourceObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
...this.workspaceMigrationFactory.createColumnActions(
WorkspaceMigrationColumnActionType.CREATE,
targetFieldMetadata,
sourceFieldMetadata,
),
],
},
{
name: computeObjectTargetTable(targetObjectMetadata),
name: computeObjectTargetTable(sourceObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
{
action: WorkspaceMigrationColumnActionType.CREATE_FOREIGN_KEY,
columnName:
targetFieldMetadata.settings.joinColumnName ??
`${camelCase(targetFieldMetadata.name)}Id`,
columnName: sourceFieldMetadata.settings.joinColumnName,
referencedTableName:
computeObjectTargetTable(sourceObjectMetadata),
computeObjectTargetTable(targetObjectMetadata),
referencedTableColumnName: 'id',
isUnique:
targetFieldMetadata.settings.relationType ===
RelationType.ONE_TO_ONE,
onDelete: targetFieldMetadata.settings.onDelete,
isUnique: false,
onDelete: sourceFieldMetadata.settings.onDelete,
},
],
},
@ -314,6 +320,19 @@ export class WorkspaceMigrationFieldRelationFactory {
);
}
if (!sourceFieldMetadata.settings) {
throw new Error(
`FieldMetadata for relation with id ${sourceFieldMetadata.id} has no settings`,
);
}
if (
sourceFieldMetadata.settings.relationType !== RelationType.MANY_TO_ONE
) {
// Only MANY_TO_ONE relations deletion have consequences on the database schema
continue;
}
if (!targetObjectMetadata) {
throw new Error(
`ObjectMetadata with id ${sourceFieldMetadata.relationTargetObjectMetadataId} not found`,
@ -342,32 +361,30 @@ export class WorkspaceMigrationFieldRelationFactory {
);
}
if (!targetFieldMetadata.settings) {
if (!sourceFieldMetadata.settings.joinColumnName) {
throw new Error(
`FieldMetadata for relation with id ${sourceFieldMetadata.id} has no settings`,
`FieldMetadata for relation with id ${sourceFieldMetadata.id} has no join column name, it should not generate a workspace migration`,
);
}
const migrations: WorkspaceMigrationTableAction[] = [
{
name: computeObjectTargetTable(targetObjectMetadata),
name: computeObjectTargetTable(sourceObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
{
action: WorkspaceMigrationColumnActionType.DROP_FOREIGN_KEY,
columnName: `${camelCase(targetFieldMetadata.name)}Id`,
columnName: sourceFieldMetadata.settings.joinColumnName,
},
],
},
{
name: computeObjectTargetTable(targetObjectMetadata),
name: computeObjectTargetTable(sourceObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
{
action: WorkspaceMigrationColumnActionType.DROP,
columnName:
targetFieldMetadata.settings.joinColumnName ??
`${camelCase(targetFieldMetadata.name)}Id`,
columnName: sourceFieldMetadata.settings.joinColumnName,
},
],
},