140 lines
4.9 KiB
TypeScript
140 lines
4.9 KiB
TypeScript
import { InjectRepository } from '@nestjs/typeorm';
|
|
|
|
import chalk from 'chalk';
|
|
import { Command } from 'nest-commander';
|
|
import { FieldMetadataType } from 'twenty-shared/types';
|
|
import { In, Repository } from 'typeorm';
|
|
|
|
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
|
|
|
|
import {
|
|
ActiveOrSuspendedWorkspacesMigrationCommandRunner,
|
|
RunOnWorkspaceArgs,
|
|
} from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner';
|
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
|
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
|
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
|
import {
|
|
RelationDirection,
|
|
deduceRelationDirection,
|
|
} from 'src/engine/utils/deduce-relation-direction.util';
|
|
import { isFieldMetadataOfType } from 'src/engine/utils/is-field-metadata-of-type.util';
|
|
|
|
@Command({
|
|
name: 'upgrade:0-51:migrate-relations-to-field-metadata',
|
|
description: 'Migrate relations to field metadata',
|
|
})
|
|
export class MigrateRelationsToFieldMetadataCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner {
|
|
constructor(
|
|
@InjectRepository(Workspace, 'core')
|
|
protected readonly workspaceRepository: Repository<Workspace>,
|
|
@InjectRepository(FieldMetadataEntity, 'metadata')
|
|
private readonly fieldMetadataRepository: Repository<FieldMetadataEntity>,
|
|
protected readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
|
) {
|
|
super(workspaceRepository, twentyORMGlobalManager);
|
|
}
|
|
|
|
override async runOnWorkspace({
|
|
index,
|
|
total,
|
|
workspaceId,
|
|
}: RunOnWorkspaceArgs): Promise<void> {
|
|
this.logger.log(
|
|
`Running command for workspace ${workspaceId} ${index + 1}/${total}`,
|
|
);
|
|
|
|
const fieldMetadataCollection = await this.fieldMetadataRepository.find({
|
|
where: {
|
|
workspaceId,
|
|
type: In([FieldMetadataType.RELATION, FieldMetadataType.UUID]),
|
|
},
|
|
relations: ['fromRelationMetadata', 'toRelationMetadata'],
|
|
});
|
|
|
|
if (!fieldMetadataCollection.length) {
|
|
this.logger.log(
|
|
chalk.yellow(
|
|
`No relation field metadata found for workspace ${workspaceId}.`,
|
|
),
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
const joinColumnFieldMetadataCollection = fieldMetadataCollection.filter(
|
|
(fieldMetadata) =>
|
|
isFieldMetadataOfType(fieldMetadata, FieldMetadataType.UUID),
|
|
// TODO: Fix this, it's working in other places but not here
|
|
) as FieldMetadataEntity<FieldMetadataType.UUID>[];
|
|
|
|
const fieldMetadataToUpdateCollection = fieldMetadataCollection
|
|
.filter((fieldMetadata) =>
|
|
isFieldMetadataOfType(fieldMetadata, FieldMetadataType.RELATION),
|
|
)
|
|
.map((fieldMetadata) =>
|
|
this.updateRelationFieldMetadata(
|
|
joinColumnFieldMetadataCollection,
|
|
// TODO: Fix this, it's working in other places but not here
|
|
fieldMetadata as FieldMetadataEntity<FieldMetadataType.RELATION>,
|
|
),
|
|
);
|
|
|
|
if (fieldMetadataToUpdateCollection.length > 0) {
|
|
await this.fieldMetadataRepository.save(fieldMetadataToUpdateCollection);
|
|
}
|
|
|
|
this.logger.log(
|
|
chalk.green(`Command completed for workspace ${workspaceId}.`),
|
|
);
|
|
}
|
|
|
|
private updateRelationFieldMetadata(
|
|
joinColumnFieldMetadataCollection: FieldMetadataEntity<FieldMetadataType.UUID>[],
|
|
fieldMetadata: FieldMetadataEntity<FieldMetadataType.RELATION>,
|
|
): FieldMetadataEntity<FieldMetadataType.RELATION> {
|
|
const relationMetadata =
|
|
fieldMetadata.fromRelationMetadata ?? fieldMetadata.toRelationMetadata;
|
|
const joinColumnFieldMetadata = joinColumnFieldMetadataCollection.find(
|
|
(joinColumnFieldMetadata) =>
|
|
// We're deducing the field based on the name of the relation field
|
|
// This is not the best way to do this but we don't have a better way
|
|
joinColumnFieldMetadata.name === `${fieldMetadata.name}Id`,
|
|
);
|
|
|
|
const relationDirection = deduceRelationDirection(
|
|
fieldMetadata,
|
|
relationMetadata,
|
|
);
|
|
let relationType = relationMetadata.relationType as unknown as RelationType;
|
|
|
|
if (
|
|
relationDirection === RelationDirection.TO &&
|
|
relationType === RelationType.ONE_TO_MANY
|
|
) {
|
|
relationType = RelationType.MANY_TO_ONE;
|
|
}
|
|
|
|
const relationTargetFieldMetadataId =
|
|
relationDirection === RelationDirection.FROM
|
|
? relationMetadata.toFieldMetadataId
|
|
: relationMetadata.fromFieldMetadataId;
|
|
|
|
const relationTargetObjectMetadataId =
|
|
relationDirection === RelationDirection.FROM
|
|
? relationMetadata.toObjectMetadataId
|
|
: relationMetadata.fromObjectMetadataId;
|
|
|
|
return {
|
|
...fieldMetadata,
|
|
settings: {
|
|
relationType,
|
|
onDelete: relationMetadata.onDeleteAction,
|
|
joinColumnName: joinColumnFieldMetadata?.name,
|
|
},
|
|
relationTargetFieldMetadataId,
|
|
relationTargetObjectMetadataId,
|
|
};
|
|
}
|
|
}
|