Files
twenty_crm/packages/twenty-server/src/engine/twenty-orm/utils/determine-relation-details.util.ts
Marie 8c6569be3b Add relation exceptions (#12185)
Introducing a class of RelationException extending CustomException to
help grouping those exception in sentries by ExceptionCode.
I did not introduce a filter as these are thrown in utils that can be
used in multiple places now or in the future, and filters are to be
added at resolver-level.
2025-05-21 15:53:25 +02:00

73 lines
2.6 KiB
TypeScript

import { RelationType } from 'typeorm/metadata/types/RelationTypes';
import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
import {
RelationException,
RelationExceptionCode,
} from 'src/engine/twenty-orm/exceptions/relation.exception';
import { computeRelationType } from 'src/engine/twenty-orm/utils/compute-relation-type.util';
interface RelationDetails {
relationType: RelationType;
target: string;
inverseSide: string;
joinColumn: { name: string } | undefined;
}
export async function determineRelationDetails(
fieldMetadata: FieldMetadataInterface,
relationMetadata: RelationMetadataEntity,
objectMetadataMaps: ObjectMetadataMaps,
): Promise<RelationDetails> {
const relationType = computeRelationType(fieldMetadata, relationMetadata);
const fromObjectMetadata =
objectMetadataMaps.byId[fieldMetadata.objectMetadataId];
let toObjectMetadata =
objectMetadataMaps.byId[relationMetadata.toObjectMetadataId];
// RelationMetadata always store the relation from the perspective of the `from` object, MANY_TO_ONE relations are not stored yet
if (relationType === 'many-to-one') {
toObjectMetadata =
objectMetadataMaps.byId[relationMetadata.fromObjectMetadataId];
}
if (!fromObjectMetadata || !toObjectMetadata) {
throw new RelationException(
'Object metadata not found',
RelationExceptionCode.RELATION_OBJECT_METADATA_NOT_FOUND,
);
}
const toFieldMetadata = Object.values(toObjectMetadata.fieldsById).find(
(field) =>
relationType === 'many-to-one'
? field.id === relationMetadata.fromFieldMetadataId
: field.id === relationMetadata.toFieldMetadataId,
);
if (!toFieldMetadata) {
throw new Error('To field metadata not found');
}
// TODO: Support many to many relations
if (relationType === 'many-to-many') {
throw new Error('Many to many relations are not supported yet');
}
return {
relationType,
target: toObjectMetadata.nameSingular,
inverseSide: toFieldMetadata.name,
joinColumn:
// TODO: This will work for now but we need to handle this better in the future for custom names on the join column
relationType === 'many-to-one' ||
(relationType === 'one-to-one' &&
relationMetadata.toObjectMetadataId === fieldMetadata.objectMetadataId)
? { name: `${fieldMetadata.name}` + 'Id' }
: undefined,
};
}