Remove old relations (#11993)
This is a first PR to remove old relation logic Next steps: - remove relationMetadata from cache - remove relationMetadata table content and structure - refactor relationDefinition to leverage field.settings instead
This commit is contained in:
@ -9,7 +9,6 @@ import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
|
||||
|
||||
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
|
||||
import { ActorModule } from 'src/engine/core-modules/actor/actor.module';
|
||||
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
||||
import { FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto';
|
||||
@ -49,7 +48,6 @@ import { UpdateFieldInput } from './dtos/update-field.input';
|
||||
WorkspaceMigrationRunnerModule,
|
||||
WorkspaceMetadataVersionModule,
|
||||
WorkspaceCacheStorageModule,
|
||||
FeatureFlagModule,
|
||||
ObjectMetadataModule,
|
||||
DataSourceModule,
|
||||
TypeORMModule,
|
||||
|
||||
@ -10,8 +10,6 @@ import {
|
||||
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import {
|
||||
ForbiddenError,
|
||||
ValidationError,
|
||||
@ -53,7 +51,6 @@ import { createDeterministicUuid } from 'src/engine/workspace-manager/workspace-
|
||||
export class FieldMetadataResolver {
|
||||
constructor(
|
||||
private readonly fieldMetadataService: FieldMetadataService,
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
private readonly beforeUpdateOneField: BeforeUpdateOneField<UpdateFieldInput>,
|
||||
) {}
|
||||
|
||||
@ -178,51 +175,28 @@ export class FieldMetadataResolver {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isNewRelationEnabled = await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IsNewRelationEnabled,
|
||||
workspace.id,
|
||||
const relation = await this.relation(
|
||||
workspace,
|
||||
fieldMetadata as FieldMetadataEntity<FieldMetadataType.RELATION>,
|
||||
context,
|
||||
);
|
||||
|
||||
// TODO: Remove this once we drop old relations or update the front-end to use the new relation
|
||||
if (isNewRelationEnabled) {
|
||||
const relation = await this.relation(
|
||||
workspace,
|
||||
fieldMetadata as FieldMetadataEntity<FieldMetadataType.RELATION>,
|
||||
context,
|
||||
);
|
||||
|
||||
if (!relation) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
// Temporary fix as we don't have relationId in the new relation
|
||||
relationId: createDeterministicUuid([
|
||||
relation.sourceFieldMetadata.id,
|
||||
relation.targetFieldMetadata.id,
|
||||
]),
|
||||
direction: relation.type as unknown as RelationDefinitionType,
|
||||
sourceObjectMetadata: relation.sourceObjectMetadata,
|
||||
targetObjectMetadata: relation.targetObjectMetadata,
|
||||
sourceFieldMetadata: relation.sourceFieldMetadata,
|
||||
targetFieldMetadata: relation.targetFieldMetadata,
|
||||
};
|
||||
if (!relation) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const relationMetadataItem =
|
||||
await context.loaders.relationMetadataLoader.load({
|
||||
fieldMetadata,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
|
||||
return await this.fieldMetadataService.getRelationDefinitionFromRelationMetadata(
|
||||
fieldMetadata,
|
||||
relationMetadataItem,
|
||||
);
|
||||
} catch (error) {
|
||||
fieldMetadataGraphqlApiExceptionHandler(error);
|
||||
}
|
||||
return {
|
||||
// Temporary fix as we don't have relationId in the new relation
|
||||
relationId: createDeterministicUuid([
|
||||
relation.sourceFieldMetadata.id,
|
||||
relation.targetFieldMetadata.id,
|
||||
]),
|
||||
direction: relation.type as unknown as RelationDefinitionType,
|
||||
sourceObjectMetadata: relation.sourceObjectMetadata,
|
||||
targetObjectMetadata: relation.targetObjectMetadata,
|
||||
sourceFieldMetadata: relation.sourceFieldMetadata,
|
||||
targetFieldMetadata: relation.targetFieldMetadata,
|
||||
};
|
||||
}
|
||||
|
||||
@ResolveField(() => RelationDTO, { nullable: true })
|
||||
@ -236,18 +210,6 @@ export class FieldMetadataResolver {
|
||||
}
|
||||
|
||||
try {
|
||||
const isNewRelationEnabled =
|
||||
await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IsNewRelationEnabled,
|
||||
workspace.id,
|
||||
);
|
||||
|
||||
if (!isNewRelationEnabled) {
|
||||
throw new FieldMetadataException(
|
||||
'New relation feature is not enabled for this workspace',
|
||||
FieldMetadataExceptionCode.FIELD_METADATA_RELATION_NOT_ENABLED,
|
||||
);
|
||||
}
|
||||
const {
|
||||
sourceObjectMetadata,
|
||||
targetObjectMetadata,
|
||||
|
||||
@ -10,7 +10,6 @@ import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
|
||||
|
||||
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
|
||||
import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
||||
import { SettingsPermissionsGuard } from 'src/engine/guards/settings-permissions.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
||||
@ -22,7 +21,6 @@ import { ObjectMetadataResolver } from 'src/engine/metadata-modules/object-metad
|
||||
import { ObjectMetadataFieldRelationService } from 'src/engine/metadata-modules/object-metadata/services/object-metadata-field-relation.service';
|
||||
import { ObjectMetadataMigrationService } from 'src/engine/metadata-modules/object-metadata/services/object-metadata-migration.service';
|
||||
import { ObjectMetadataRelatedRecordsService } from 'src/engine/metadata-modules/object-metadata/services/object-metadata-related-records.service';
|
||||
import { ObjectMetadataRelationService } from 'src/engine/metadata-modules/object-metadata/services/object-metadata-relation.service';
|
||||
import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/constants/setting-permission-type.constants';
|
||||
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
|
||||
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
|
||||
@ -58,14 +56,12 @@ import { UpdateObjectPayload } from './dtos/update-object.input';
|
||||
RemoteTableRelationsModule,
|
||||
SearchVectorModule,
|
||||
IndexMetadataModule,
|
||||
FeatureFlagModule,
|
||||
PermissionsModule,
|
||||
WorkspacePermissionsCacheModule,
|
||||
],
|
||||
services: [
|
||||
ObjectMetadataService,
|
||||
ObjectMetadataMigrationService,
|
||||
ObjectMetadataRelationService,
|
||||
ObjectMetadataFieldRelationService,
|
||||
ObjectMetadataRelatedRecordsService,
|
||||
],
|
||||
|
||||
@ -10,8 +10,6 @@ import { FindManyOptions, FindOneOptions, In, Not, Repository } from 'typeorm';
|
||||
|
||||
import { ObjectMetadataStandardIdToIdMap } from 'src/engine/metadata-modules/object-metadata/interfaces/object-metadata-standard-id-to-id-map';
|
||||
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { generateMessageId } from 'src/engine/core-modules/i18n/utils/generateMessageId';
|
||||
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
@ -29,7 +27,6 @@ import {
|
||||
import { ObjectMetadataFieldRelationService } from 'src/engine/metadata-modules/object-metadata/services/object-metadata-field-relation.service';
|
||||
import { ObjectMetadataMigrationService } from 'src/engine/metadata-modules/object-metadata/services/object-metadata-migration.service';
|
||||
import { ObjectMetadataRelatedRecordsService } from 'src/engine/metadata-modules/object-metadata/services/object-metadata-related-records.service';
|
||||
import { ObjectMetadataRelationService } from 'src/engine/metadata-modules/object-metadata/services/object-metadata-relation.service';
|
||||
import { buildDefaultFieldsForCustomObject } from 'src/engine/metadata-modules/object-metadata/utils/build-default-fields-for-custom-object.util';
|
||||
import {
|
||||
validateLowerCasedAndTrimmedStringsAreDifferentOrThrow,
|
||||
@ -64,13 +61,11 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
private readonly workspaceMigrationRunnerService: WorkspaceMigrationRunnerService,
|
||||
private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService,
|
||||
private readonly searchVectorService: SearchVectorService,
|
||||
private readonly objectMetadataRelationService: ObjectMetadataRelationService,
|
||||
private readonly objectMetadataFieldRelationService: ObjectMetadataFieldRelationService,
|
||||
private readonly objectMetadataMigrationService: ObjectMetadataMigrationService,
|
||||
private readonly objectMetadataRelatedRecordsService: ObjectMetadataRelatedRecordsService,
|
||||
private readonly indexMetadataService: IndexMetadataService,
|
||||
private readonly workspacePermissionsCacheService: WorkspacePermissionsCacheService,
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
) {
|
||||
super(objectMetadataRepository);
|
||||
}
|
||||
@ -188,33 +183,12 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
createdObjectMetadata.fields,
|
||||
);
|
||||
|
||||
const isNewRelationEnabled =
|
||||
await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IsNewRelationEnabled,
|
||||
const createdRelatedObjectMetadataCollection =
|
||||
await this.objectMetadataFieldRelationService.createRelationsAndForeignKeysMetadata(
|
||||
objectMetadataInput.workspaceId,
|
||||
createdObjectMetadata,
|
||||
);
|
||||
|
||||
let createdRelatedObjectMetadataCollection: ObjectMetadataEntity[];
|
||||
|
||||
if (isNewRelationEnabled) {
|
||||
createdRelatedObjectMetadataCollection =
|
||||
await this.objectMetadataFieldRelationService.createRelationsAndForeignKeysMetadata(
|
||||
objectMetadataInput.workspaceId,
|
||||
createdObjectMetadata,
|
||||
);
|
||||
} else {
|
||||
createdRelatedObjectMetadataCollection =
|
||||
await this.objectMetadataRelationService.createRelationsAndForeignKeysMetadata(
|
||||
objectMetadataInput.workspaceId,
|
||||
createdObjectMetadata,
|
||||
{
|
||||
primaryKeyFieldMetadataSettings:
|
||||
objectMetadataInput.primaryKeyFieldMetadataSettings,
|
||||
primaryKeyColumnType: objectMetadataInput.primaryKeyColumnType,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
await this.objectMetadataMigrationService.createRelationMigrations(
|
||||
createdObjectMetadata,
|
||||
createdRelatedObjectMetadataCollection,
|
||||
@ -316,27 +290,12 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
|
||||
const updatedObject = await super.updateOne(inputId, inputPayload);
|
||||
|
||||
const isNewRelationEnabled = await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IsNewRelationEnabled,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
await this.handleObjectNameAndLabelUpdates(
|
||||
existingObjectMetadata,
|
||||
existingObjectMetadataCombinedWithUpdateInput,
|
||||
inputPayload,
|
||||
);
|
||||
|
||||
if (inputPayload.isActive !== undefined) {
|
||||
// For new relation system, the active status is stitched to the field metadata
|
||||
if (!isNewRelationEnabled) {
|
||||
await this.objectMetadataRelationService.updateObjectRelationshipsActivationStatus(
|
||||
inputId,
|
||||
inputPayload.isActive,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await this.workspaceMigrationRunnerService.executeMigrationFromPendingMigrations(
|
||||
workspaceId,
|
||||
);
|
||||
@ -377,11 +336,6 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
input: DeleteOneObjectInput,
|
||||
workspaceId: string,
|
||||
): Promise<ObjectMetadataEntity> {
|
||||
const isNewRelationEnabled = await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IsNewRelationEnabled,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
const objectMetadata = await this.objectMetadataRepository.findOne({
|
||||
relations: [
|
||||
'fields',
|
||||
@ -419,7 +373,6 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
await this.objectMetadataMigrationService.deleteAllRelationsAndDropTable(
|
||||
objectMetadata,
|
||||
workspaceId,
|
||||
isNewRelationEnabled,
|
||||
);
|
||||
}
|
||||
|
||||
@ -536,11 +489,6 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
objectMetadataForUpdate: ObjectMetadataEntity,
|
||||
inputPayload: UpdateObjectPayload,
|
||||
) {
|
||||
const isNewRelationEnabled = await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IsNewRelationEnabled,
|
||||
objectMetadataForUpdate.workspaceId,
|
||||
);
|
||||
|
||||
const newTargetTableName = computeObjectTargetTable(
|
||||
objectMetadataForUpdate,
|
||||
);
|
||||
@ -555,33 +503,18 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
objectMetadataForUpdate.workspaceId,
|
||||
);
|
||||
|
||||
if (isNewRelationEnabled) {
|
||||
const relationMetadataCollection =
|
||||
await this.objectMetadataFieldRelationService.updateRelationsAndForeignKeysMetadata(
|
||||
objectMetadataForUpdate.workspaceId,
|
||||
objectMetadataForUpdate,
|
||||
);
|
||||
|
||||
await this.objectMetadataMigrationService.updateRelationMigrations(
|
||||
existingObjectMetadata,
|
||||
objectMetadataForUpdate,
|
||||
relationMetadataCollection,
|
||||
const relationMetadataCollection =
|
||||
await this.objectMetadataFieldRelationService.updateRelationsAndForeignKeysMetadata(
|
||||
objectMetadataForUpdate.workspaceId,
|
||||
);
|
||||
} else {
|
||||
const relationsAndForeignKeysMetadata =
|
||||
await this.objectMetadataRelationService.updateRelationsAndForeignKeysMetadata(
|
||||
objectMetadataForUpdate.workspaceId,
|
||||
objectMetadataForUpdate,
|
||||
);
|
||||
|
||||
await this.objectMetadataMigrationService.createUpdateForeignKeysMigrations(
|
||||
existingObjectMetadata,
|
||||
objectMetadataForUpdate,
|
||||
relationsAndForeignKeysMetadata,
|
||||
objectMetadataForUpdate.workspaceId,
|
||||
);
|
||||
}
|
||||
|
||||
await this.objectMetadataMigrationService.updateRelationMigrations(
|
||||
existingObjectMetadata,
|
||||
objectMetadataForUpdate,
|
||||
relationMetadataCollection,
|
||||
objectMetadataForUpdate.workspaceId,
|
||||
);
|
||||
|
||||
await this.objectMetadataMigrationService.recomputeEnumNames(
|
||||
objectMetadataForUpdate,
|
||||
|
||||
@ -7,7 +7,6 @@ import { In, Repository } from 'typeorm';
|
||||
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
|
||||
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { computeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { buildMigrationsForCustomObjectRelations } from 'src/engine/metadata-modules/object-metadata/utils/build-migrations-for-custom-object-relations.util';
|
||||
import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
|
||||
@ -30,8 +29,6 @@ import { RELATION_MIGRATION_PRIORITY_PREFIX } from 'src/engine/workspace-manager
|
||||
@Injectable()
|
||||
export class ObjectMetadataMigrationService {
|
||||
constructor(
|
||||
@InjectRepository(ObjectMetadataEntity, 'metadata')
|
||||
private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
|
||||
@InjectRepository(FieldMetadataEntity, 'metadata')
|
||||
private readonly fieldMetadataRepository: Repository<FieldMetadataEntity>,
|
||||
@InjectRepository(RelationMetadataEntity, 'metadata')
|
||||
@ -222,7 +219,6 @@ export class ObjectMetadataMigrationService {
|
||||
public async deleteAllRelationsAndDropTable(
|
||||
objectMetadata: ObjectMetadataEntity,
|
||||
workspaceId: string,
|
||||
isNewRelationEnabled: boolean,
|
||||
) {
|
||||
const relationsMetadataToDelete: RelationToDelete[] = [];
|
||||
|
||||
@ -275,88 +271,59 @@ export class ObjectMetadataMigrationService {
|
||||
relationToDelete.fromFieldMetadataId,
|
||||
relationToDelete.toFieldMetadataId,
|
||||
]);
|
||||
|
||||
if (relationToDelete.direction === 'from' && !isNewRelationEnabled) {
|
||||
await this.workspaceMigrationService.createCustomMigration(
|
||||
generateMigrationName(
|
||||
`delete-${RELATION_MIGRATION_PRIORITY_PREFIX}-${relationToDelete.fromObjectName}-${relationToDelete.toObjectName}`,
|
||||
),
|
||||
workspaceId,
|
||||
[
|
||||
{
|
||||
name: computeTableName(
|
||||
relationToDelete.toObjectName,
|
||||
relationToDelete.toObjectMetadataIsCustom,
|
||||
),
|
||||
action: WorkspaceMigrationTableActionType.ALTER,
|
||||
columns: [
|
||||
{
|
||||
action: WorkspaceMigrationColumnActionType.DROP,
|
||||
columnName: computeColumnName(
|
||||
relationToDelete.toFieldMetadataName,
|
||||
{ isForeignKey: true },
|
||||
),
|
||||
} satisfies WorkspaceMigrationColumnDrop,
|
||||
],
|
||||
},
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (isNewRelationEnabled) {
|
||||
const manyToOneRelationFieldsToDelete = objectMetadata.fields.filter(
|
||||
(field) =>
|
||||
isFieldMetadataInterfaceOfType(field, FieldMetadataType.RELATION) &&
|
||||
(field as FieldMetadataEntity<FieldMetadataType.RELATION>).settings
|
||||
?.relationType === RelationType.MANY_TO_ONE,
|
||||
) as FieldMetadataEntity<FieldMetadataType.RELATION>[];
|
||||
const manyToOneRelationFieldsToDelete = objectMetadata.fields.filter(
|
||||
(field) =>
|
||||
isFieldMetadataInterfaceOfType(field, FieldMetadataType.RELATION) &&
|
||||
(field as FieldMetadataEntity<FieldMetadataType.RELATION>).settings
|
||||
?.relationType === RelationType.MANY_TO_ONE,
|
||||
) as FieldMetadataEntity<FieldMetadataType.RELATION>[];
|
||||
|
||||
const oneToManyRelationFieldsToDelete = objectMetadata.fields.filter(
|
||||
(field) =>
|
||||
isFieldMetadataInterfaceOfType(field, FieldMetadataType.RELATION) &&
|
||||
(field as FieldMetadataEntity<FieldMetadataType.RELATION>).settings
|
||||
?.relationType === RelationType.ONE_TO_MANY,
|
||||
);
|
||||
const oneToManyRelationFieldsToDelete = objectMetadata.fields.filter(
|
||||
(field) =>
|
||||
isFieldMetadataInterfaceOfType(field, FieldMetadataType.RELATION) &&
|
||||
(field as FieldMetadataEntity<FieldMetadataType.RELATION>).settings
|
||||
?.relationType === RelationType.ONE_TO_MANY,
|
||||
);
|
||||
|
||||
const relationFieldsToDelete = [
|
||||
...manyToOneRelationFieldsToDelete,
|
||||
...(oneToManyRelationFieldsToDelete.map(
|
||||
(field) => field.relationTargetFieldMetadata,
|
||||
) as FieldMetadataEntity<FieldMetadataType.RELATION>[]),
|
||||
];
|
||||
const relationFieldsToDelete = [
|
||||
...manyToOneRelationFieldsToDelete,
|
||||
...(oneToManyRelationFieldsToDelete.map(
|
||||
(field) => field.relationTargetFieldMetadata,
|
||||
) as FieldMetadataEntity<FieldMetadataType.RELATION>[]),
|
||||
];
|
||||
|
||||
for (const relationFieldToDelete of relationFieldsToDelete) {
|
||||
const joinColumnName = relationFieldToDelete.settings?.joinColumnName;
|
||||
for (const relationFieldToDelete of relationFieldsToDelete) {
|
||||
const joinColumnName = relationFieldToDelete.settings?.joinColumnName;
|
||||
|
||||
if (!joinColumnName) {
|
||||
throw new Error(
|
||||
`Join column name is not set for relation field ${relationFieldToDelete.name}`,
|
||||
);
|
||||
}
|
||||
|
||||
await this.workspaceMigrationService.createCustomMigration(
|
||||
generateMigrationName(
|
||||
`delete-${RELATION_MIGRATION_PRIORITY_PREFIX}-${relationFieldToDelete.name}`,
|
||||
),
|
||||
workspaceId,
|
||||
[
|
||||
{
|
||||
name: computeTableName(
|
||||
relationFieldToDelete.object.nameSingular,
|
||||
relationFieldToDelete.object.isCustom,
|
||||
),
|
||||
action: WorkspaceMigrationTableActionType.ALTER,
|
||||
columns: [
|
||||
{
|
||||
action: WorkspaceMigrationColumnActionType.DROP,
|
||||
columnName: joinColumnName,
|
||||
} satisfies WorkspaceMigrationColumnDrop,
|
||||
],
|
||||
},
|
||||
],
|
||||
if (!joinColumnName) {
|
||||
throw new Error(
|
||||
`Join column name is not set for relation field ${relationFieldToDelete.name}`,
|
||||
);
|
||||
}
|
||||
|
||||
await this.workspaceMigrationService.createCustomMigration(
|
||||
generateMigrationName(
|
||||
`delete-${RELATION_MIGRATION_PRIORITY_PREFIX}-${relationFieldToDelete.name}`,
|
||||
),
|
||||
workspaceId,
|
||||
[
|
||||
{
|
||||
name: computeTableName(
|
||||
relationFieldToDelete.object.nameSingular,
|
||||
relationFieldToDelete.object.isCustom,
|
||||
),
|
||||
action: WorkspaceMigrationTableActionType.ALTER,
|
||||
columns: [
|
||||
{
|
||||
action: WorkspaceMigrationColumnActionType.DROP,
|
||||
columnName: joinColumnName,
|
||||
} satisfies WorkspaceMigrationColumnDrop,
|
||||
],
|
||||
},
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// DROP TABLE
|
||||
|
||||
@ -1,451 +0,0 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { In, Repository } from 'typeorm';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
import { FieldMetadataSettings } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
|
||||
|
||||
import { FieldMetadataEntity } 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,
|
||||
RelationOnDeleteAction,
|
||||
} from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
|
||||
import { mapUdtNameToFieldType } from 'src/engine/metadata-modules/remote-server/remote-table/utils/udt-name-mapper.util';
|
||||
import {
|
||||
CUSTOM_OBJECT_STANDARD_FIELD_IDS,
|
||||
STANDARD_OBJECT_FIELD_IDS,
|
||||
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
|
||||
import { STANDARD_OBJECT_ICONS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-icons';
|
||||
import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids';
|
||||
import {
|
||||
createForeignKeyDeterministicUuid,
|
||||
createRelationDeterministicUuid,
|
||||
} from 'src/engine/workspace-manager/workspace-sync-metadata/utils/create-deterministic-uuid.util';
|
||||
|
||||
const DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS = [
|
||||
STANDARD_OBJECT_IDS.timelineActivity,
|
||||
STANDARD_OBJECT_IDS.favorite,
|
||||
STANDARD_OBJECT_IDS.attachment,
|
||||
STANDARD_OBJECT_IDS.noteTarget,
|
||||
STANDARD_OBJECT_IDS.taskTarget,
|
||||
];
|
||||
|
||||
@Injectable()
|
||||
export class ObjectMetadataRelationService {
|
||||
constructor(
|
||||
@InjectRepository(ObjectMetadataEntity, 'metadata')
|
||||
private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
|
||||
@InjectRepository(FieldMetadataEntity, 'metadata')
|
||||
private readonly fieldMetadataRepository: Repository<FieldMetadataEntity>,
|
||||
@InjectRepository(RelationMetadataEntity, 'metadata')
|
||||
private readonly relationMetadataRepository: Repository<RelationMetadataEntity>,
|
||||
) {}
|
||||
|
||||
public async createRelationsAndForeignKeysMetadata(
|
||||
workspaceId: string,
|
||||
createdObjectMetadata: ObjectMetadataEntity,
|
||||
{ primaryKeyFieldMetadataSettings, primaryKeyColumnType },
|
||||
) {
|
||||
const relatedObjectMetadataCollection = await Promise.all(
|
||||
DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS.map(
|
||||
async (relationObjectMetadataStandardId) =>
|
||||
this.createRelationAndForeignKeyMetadata(
|
||||
workspaceId,
|
||||
createdObjectMetadata,
|
||||
mapUdtNameToFieldType(primaryKeyColumnType ?? 'uuid'),
|
||||
primaryKeyFieldMetadataSettings,
|
||||
relationObjectMetadataStandardId,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return relatedObjectMetadataCollection;
|
||||
}
|
||||
|
||||
private async createRelationAndForeignKeyMetadata(
|
||||
workspaceId: string,
|
||||
createdObjectMetadata: ObjectMetadataEntity,
|
||||
objectPrimaryKeyType: FieldMetadataType,
|
||||
objectPrimaryKeyFieldSettings:
|
||||
| FieldMetadataSettings<FieldMetadataType>
|
||||
| undefined,
|
||||
relationObjectMetadataStandardId: string,
|
||||
) {
|
||||
const relatedObjectMetadata =
|
||||
await this.objectMetadataRepository.findOneByOrFail({
|
||||
standardId: relationObjectMetadataStandardId,
|
||||
workspaceId: workspaceId,
|
||||
isCustom: false,
|
||||
});
|
||||
|
||||
const relationFieldMetadataCollection =
|
||||
await this.createRelationFieldMetadas(
|
||||
workspaceId,
|
||||
createdObjectMetadata,
|
||||
relatedObjectMetadata,
|
||||
objectPrimaryKeyType,
|
||||
objectPrimaryKeyFieldSettings,
|
||||
);
|
||||
|
||||
await this.createRelationMetadataFromFieldMetadatas(
|
||||
workspaceId,
|
||||
createdObjectMetadata,
|
||||
relatedObjectMetadata,
|
||||
relationFieldMetadataCollection,
|
||||
);
|
||||
|
||||
return relatedObjectMetadata;
|
||||
}
|
||||
|
||||
private async createRelationFieldMetadas(
|
||||
workspaceId: string,
|
||||
createdObjectMetadata: ObjectMetadataEntity,
|
||||
relatedObjectMetadata: ObjectMetadataEntity,
|
||||
objectPrimaryKeyType: FieldMetadataType,
|
||||
objectPrimaryKeyFieldSettings:
|
||||
| FieldMetadataSettings<FieldMetadataType>
|
||||
| undefined,
|
||||
) {
|
||||
return this.fieldMetadataRepository.save([
|
||||
this.buildFromFieldMetadata(
|
||||
workspaceId,
|
||||
createdObjectMetadata,
|
||||
relatedObjectMetadata,
|
||||
),
|
||||
this.buildToFieldMetadata(
|
||||
workspaceId,
|
||||
createdObjectMetadata,
|
||||
relatedObjectMetadata,
|
||||
),
|
||||
this.buildForeignKeyFieldMetadata(
|
||||
workspaceId,
|
||||
createdObjectMetadata,
|
||||
relatedObjectMetadata,
|
||||
objectPrimaryKeyType,
|
||||
objectPrimaryKeyFieldSettings,
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
public async updateRelationsAndForeignKeysMetadata(
|
||||
workspaceId: string,
|
||||
updatedObjectMetadata: ObjectMetadataEntity,
|
||||
): Promise<
|
||||
{
|
||||
relatedObjectMetadata: ObjectMetadataEntity;
|
||||
foreignKeyFieldMetadata: FieldMetadataEntity;
|
||||
toFieldMetadata: FieldMetadataEntity;
|
||||
fromFieldMetadata: FieldMetadataEntity;
|
||||
}[]
|
||||
> {
|
||||
return await Promise.all(
|
||||
DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS.map(
|
||||
async (relationObjectMetadataStandardId) =>
|
||||
this.updateRelationAndForeignKeyMetadata(
|
||||
workspaceId,
|
||||
updatedObjectMetadata,
|
||||
relationObjectMetadataStandardId,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
private async updateRelationAndForeignKeyMetadata(
|
||||
workspaceId: string,
|
||||
updatedObjectMetadata: ObjectMetadataEntity,
|
||||
relationObjectMetadataStandardId: string,
|
||||
) {
|
||||
const relatedObjectMetadata =
|
||||
await this.objectMetadataRepository.findOneByOrFail({
|
||||
standardId: relationObjectMetadataStandardId,
|
||||
workspaceId: workspaceId,
|
||||
isCustom: false,
|
||||
});
|
||||
|
||||
const toFieldMetadataUpdateCriteria = {
|
||||
standardId: createRelationDeterministicUuid({
|
||||
objectId: updatedObjectMetadata.id,
|
||||
standardId:
|
||||
STANDARD_OBJECT_FIELD_IDS[relatedObjectMetadata.nameSingular].custom,
|
||||
}),
|
||||
objectMetadataId: relatedObjectMetadata.id,
|
||||
workspaceId: workspaceId,
|
||||
};
|
||||
const toFieldMetadataUpdateData = this.buildToFieldMetadata(
|
||||
workspaceId,
|
||||
updatedObjectMetadata,
|
||||
relatedObjectMetadata,
|
||||
true,
|
||||
);
|
||||
const toFieldMetadataToUpdate =
|
||||
await this.fieldMetadataRepository.findOneBy(
|
||||
toFieldMetadataUpdateCriteria,
|
||||
);
|
||||
const toFieldMetadata = await this.fieldMetadataRepository.save({
|
||||
...toFieldMetadataToUpdate,
|
||||
...toFieldMetadataUpdateData,
|
||||
});
|
||||
|
||||
const fromFieldMetadataUpdateCriteria = {
|
||||
standardId:
|
||||
CUSTOM_OBJECT_STANDARD_FIELD_IDS[relatedObjectMetadata.namePlural],
|
||||
objectMetadataId: updatedObjectMetadata.id,
|
||||
workspaceId: workspaceId,
|
||||
};
|
||||
const fromFieldMetadataUpdateData = this.buildFromFieldMetadata(
|
||||
workspaceId,
|
||||
updatedObjectMetadata,
|
||||
relatedObjectMetadata,
|
||||
true,
|
||||
);
|
||||
const fromFieldMetadataToUpdate =
|
||||
await this.fieldMetadataRepository.findOneBy(
|
||||
fromFieldMetadataUpdateCriteria,
|
||||
);
|
||||
const fromFieldMetadata = await this.fieldMetadataRepository.save({
|
||||
...fromFieldMetadataToUpdate,
|
||||
...fromFieldMetadataUpdateData,
|
||||
});
|
||||
|
||||
const foreignKeyFieldMetadataUpdateCriteria = {
|
||||
standardId: createForeignKeyDeterministicUuid({
|
||||
objectId: updatedObjectMetadata.id,
|
||||
standardId:
|
||||
STANDARD_OBJECT_FIELD_IDS[relatedObjectMetadata.nameSingular].custom,
|
||||
}),
|
||||
objectMetadataId: relatedObjectMetadata.id,
|
||||
workspaceId: workspaceId,
|
||||
};
|
||||
const foreignKeyFieldMetadataUpdateData = this.buildForeignKeyFieldMetadata(
|
||||
workspaceId,
|
||||
updatedObjectMetadata,
|
||||
relatedObjectMetadata,
|
||||
FieldMetadataType.UUID,
|
||||
undefined,
|
||||
true,
|
||||
);
|
||||
const foreignKeyFieldMetadataToUpdate =
|
||||
await this.fieldMetadataRepository.findOneBy(
|
||||
foreignKeyFieldMetadataUpdateCriteria,
|
||||
);
|
||||
const foreignKeyFieldMetadata = await this.fieldMetadataRepository.save({
|
||||
...foreignKeyFieldMetadataToUpdate,
|
||||
...foreignKeyFieldMetadataUpdateData,
|
||||
});
|
||||
|
||||
return {
|
||||
relatedObjectMetadata,
|
||||
foreignKeyFieldMetadata,
|
||||
toFieldMetadata,
|
||||
fromFieldMetadata,
|
||||
};
|
||||
}
|
||||
|
||||
private buildFromFieldMetadata(
|
||||
workspaceId: string,
|
||||
objectMetadata: ObjectMetadataEntity,
|
||||
relatedObjectMetadata: ObjectMetadataEntity,
|
||||
isUpdate = false,
|
||||
) {
|
||||
const relationObjectMetadataNamePlural = relatedObjectMetadata.namePlural;
|
||||
|
||||
const { description } = buildDescriptionForRelationFieldMetadataOnFromField(
|
||||
{
|
||||
relationObjectMetadataNamePlural,
|
||||
targetObjectLabelSingular: objectMetadata.labelSingular,
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
description,
|
||||
...(!isUpdate
|
||||
? {
|
||||
standardId:
|
||||
CUSTOM_OBJECT_STANDARD_FIELD_IDS[
|
||||
relationObjectMetadataNamePlural
|
||||
],
|
||||
objectMetadataId: objectMetadata.id,
|
||||
workspaceId: workspaceId,
|
||||
isCustom: false,
|
||||
isActive: true,
|
||||
isSystem: true,
|
||||
type: FieldMetadataType.RELATION,
|
||||
name: relatedObjectMetadata.namePlural,
|
||||
label: capitalize(relationObjectMetadataNamePlural),
|
||||
description,
|
||||
icon:
|
||||
STANDARD_OBJECT_ICONS[relatedObjectMetadata.nameSingular] ||
|
||||
'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
private buildToFieldMetadata(
|
||||
workspaceId: string,
|
||||
objectMetadata: ObjectMetadataEntity,
|
||||
relatedObjectMetadata: ObjectMetadataEntity,
|
||||
isUpdate = false,
|
||||
) {
|
||||
const customStandardFieldId =
|
||||
STANDARD_OBJECT_FIELD_IDS[relatedObjectMetadata.nameSingular].custom;
|
||||
|
||||
if (!customStandardFieldId) {
|
||||
throw new Error(
|
||||
`Custom standard field ID not found for ${relatedObjectMetadata.nameSingular}`,
|
||||
);
|
||||
}
|
||||
|
||||
const { description } = buildDescriptionForRelationFieldMetadataOnToField({
|
||||
relationObjectMetadataNamePlural: relatedObjectMetadata.namePlural,
|
||||
targetObjectLabelSingular: objectMetadata.labelSingular,
|
||||
});
|
||||
|
||||
return {
|
||||
name: objectMetadata.nameSingular,
|
||||
label: objectMetadata.labelSingular,
|
||||
description,
|
||||
...(!isUpdate
|
||||
? {
|
||||
standardId: createRelationDeterministicUuid({
|
||||
objectId: objectMetadata.id,
|
||||
standardId: customStandardFieldId,
|
||||
}),
|
||||
objectMetadataId: relatedObjectMetadata.id,
|
||||
workspaceId: workspaceId,
|
||||
isCustom: false,
|
||||
isActive: true,
|
||||
isSystem: true,
|
||||
type: FieldMetadataType.RELATION,
|
||||
name: objectMetadata.nameSingular,
|
||||
label: objectMetadata.labelSingular,
|
||||
description,
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
private buildForeignKeyFieldMetadata(
|
||||
workspaceId: string,
|
||||
objectMetadata: ObjectMetadataEntity,
|
||||
relatedObjectMetadata: ObjectMetadataEntity,
|
||||
objectPrimaryKeyType: FieldMetadataType,
|
||||
objectPrimaryKeyFieldSettings:
|
||||
| FieldMetadataSettings<FieldMetadataType>
|
||||
| undefined,
|
||||
isUpdate = false,
|
||||
) {
|
||||
const customStandardFieldId =
|
||||
STANDARD_OBJECT_FIELD_IDS[relatedObjectMetadata.nameSingular].custom;
|
||||
|
||||
if (!customStandardFieldId) {
|
||||
throw new Error(
|
||||
`Custom standard field ID not found for ${relatedObjectMetadata.nameSingular}`,
|
||||
);
|
||||
}
|
||||
|
||||
const { name, label, description } =
|
||||
buildNameLabelAndDescriptionForForeignKeyFieldMetadata({
|
||||
targetObjectNameSingular: objectMetadata.nameSingular,
|
||||
targetObjectLabelSingular: objectMetadata.labelSingular,
|
||||
relatedObjectLabelSingular: relatedObjectMetadata.labelSingular,
|
||||
});
|
||||
|
||||
return {
|
||||
name,
|
||||
label,
|
||||
description,
|
||||
...(!isUpdate
|
||||
? {
|
||||
standardId: createForeignKeyDeterministicUuid({
|
||||
objectId: objectMetadata.id,
|
||||
standardId: customStandardFieldId,
|
||||
}),
|
||||
objectMetadataId: relatedObjectMetadata.id,
|
||||
workspaceId: workspaceId,
|
||||
isCustom: false,
|
||||
isActive: true,
|
||||
type: objectPrimaryKeyType,
|
||||
name,
|
||||
label,
|
||||
description,
|
||||
icon: undefined,
|
||||
isNullable: true,
|
||||
isSystem: true,
|
||||
defaultValue: undefined,
|
||||
settings: { ...objectPrimaryKeyFieldSettings, isForeignKey: true },
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
private async createRelationMetadataFromFieldMetadatas(
|
||||
workspaceId: string,
|
||||
createdObjectMetadata: ObjectMetadataEntity,
|
||||
relatedObjectMetadata: ObjectMetadataEntity,
|
||||
relationFieldMetadataCollection: FieldMetadataEntity[],
|
||||
) {
|
||||
const relationFieldMetadataMap = relationFieldMetadataCollection.reduce(
|
||||
(acc, fieldMetadata: FieldMetadataEntity) => {
|
||||
if (fieldMetadata.type === FieldMetadataType.RELATION) {
|
||||
acc[fieldMetadata.objectMetadataId] = fieldMetadata;
|
||||
}
|
||||
|
||||
return acc;
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
await this.relationMetadataRepository.save([
|
||||
{
|
||||
workspaceId: workspaceId,
|
||||
relationType: RelationMetadataType.ONE_TO_MANY,
|
||||
fromObjectMetadataId: createdObjectMetadata.id,
|
||||
toObjectMetadataId: relatedObjectMetadata.id,
|
||||
fromFieldMetadataId:
|
||||
relationFieldMetadataMap[createdObjectMetadata.id].id,
|
||||
toFieldMetadataId:
|
||||
relationFieldMetadataMap[relatedObjectMetadata.id].id,
|
||||
onDeleteAction: RelationOnDeleteAction.CASCADE,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
async updateObjectRelationshipsActivationStatus(
|
||||
objectMetadataId: string,
|
||||
isActive: boolean,
|
||||
) {
|
||||
const affectedRelations = await this.relationMetadataRepository.find({
|
||||
where: [
|
||||
{ fromObjectMetadataId: objectMetadataId },
|
||||
{ toObjectMetadataId: objectMetadataId },
|
||||
],
|
||||
});
|
||||
|
||||
const affectedFieldIds = affectedRelations.reduce(
|
||||
(acc, { fromFieldMetadataId, toFieldMetadataId }) => {
|
||||
acc.push(fromFieldMetadataId, toFieldMetadataId);
|
||||
|
||||
return acc;
|
||||
},
|
||||
[] as string[],
|
||||
);
|
||||
|
||||
if (affectedFieldIds.length > 0) {
|
||||
await this.fieldMetadataRepository.update(
|
||||
{ id: In(affectedFieldIds) },
|
||||
{ isActive: isActive },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,8 +12,6 @@ import { FieldMetadataDefaultSettings } from 'src/engine/metadata-modules/field-
|
||||
import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
|
||||
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
|
||||
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/field-metadata.service';
|
||||
import { IndexMetadataService } from 'src/engine/metadata-modules/index-metadata/index-metadata.service';
|
||||
@ -60,7 +58,6 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat
|
||||
private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService,
|
||||
private readonly indexMetadataService: IndexMetadataService,
|
||||
private readonly workspaceCacheStorageService: WorkspaceCacheStorageService,
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
) {
|
||||
super(relationMetadataRepository);
|
||||
}
|
||||
@ -72,11 +69,6 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat
|
||||
relationMetadataInput,
|
||||
);
|
||||
|
||||
const isNewRelationEnabled = await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IsNewRelationEnabled,
|
||||
relationMetadataInput.workspaceId,
|
||||
);
|
||||
|
||||
try {
|
||||
validateMetadataNameOrThrow(relationMetadataInput.fromName);
|
||||
validateMetadataNameOrThrow(relationMetadataInput.toName);
|
||||
@ -116,15 +108,6 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat
|
||||
isCustom,
|
||||
toId,
|
||||
),
|
||||
// We don't want to create the join column field metadata for new relation
|
||||
...(isNewRelationEnabled
|
||||
? []
|
||||
: [
|
||||
this.createForeignKeyFieldMetadata(
|
||||
relationMetadataInput,
|
||||
columnName,
|
||||
),
|
||||
]),
|
||||
].flat(),
|
||||
);
|
||||
|
||||
@ -190,30 +173,6 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat
|
||||
|
||||
this.throwIfDeletedAtFieldMetadataNotFound(deletedAtFieldMetadata);
|
||||
|
||||
if (!isNewRelationEnabled) {
|
||||
const foreignKeyFieldMetadata = createdRelationFieldsMetadata.find(
|
||||
(fieldMetadata) => fieldMetadata.type === FieldMetadataType.UUID,
|
||||
);
|
||||
|
||||
if (!foreignKeyFieldMetadata) {
|
||||
throw new RelationMetadataException(
|
||||
`ForeignKey field metadata not found`,
|
||||
RelationMetadataExceptionCode.RELATION_METADATA_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
await this.indexMetadataService.createIndexMetadata(
|
||||
relationMetadataInput.workspaceId,
|
||||
toObjectMetadata,
|
||||
[
|
||||
foreignKeyFieldMetadata,
|
||||
deletedAtFieldMetadata as FieldMetadataEntity<FieldMetadataType>,
|
||||
],
|
||||
false,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
await this.workspaceMigrationRunnerService.executeMigrationFromPendingMigrations(
|
||||
relationMetadataInput.workspaceId,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user