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:
@ -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 },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user