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.
This commit is contained in:
Marie
2025-05-21 15:53:25 +02:00
committed by GitHub
parent c982bcdb52
commit 8c6569be3b
5 changed files with 59 additions and 9 deletions

View File

@ -0,0 +1,18 @@
import { CustomException } from 'src/utils/custom-exception';
export class RelationException extends CustomException {
declare code: RelationExceptionCode;
constructor(message: string, code: RelationExceptionCode) {
super(message, code);
}
}
export enum RelationExceptionCode {
RELATION_OBJECT_METADATA_NOT_FOUND = 'RELATION_OBJECT_METADATA_NOT_FOUND',
RELATION_TARGET_FIELD_METADATA_ID_NOT_FOUND = 'RELATION_TARGET_FIELD_METADATA_ID_NOT_FOUND',
RELATION_TARGET_FIELD_METADATA_NOT_FOUND = 'RELATION_TARGET_FIELD_METADATA_NOT_FOUND',
INVALID_RELATION_TYPE = 'INVALID_RELATION_TYPE',
RELATION_JOIN_COLUMN_ON_BOTH_SIDES = 'RELATION_JOIN_COLUMN_ON_BOTH_SIDES',
MISSING_RELATION_JOIN_COLUMN = 'MISSING_RELATION_JOIN_COLUMN',
MULTIPLE_JOIN_COLUMNS_FOUND = 'MULTIPLE_JOIN_COLUMNS_FOUND',
}

View File

@ -1,3 +1,5 @@
import { ForbiddenException } from '@nestjs/common';
import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
import {
@ -29,6 +31,8 @@ export const computeRelationType = (
case RelationMetadataType.MANY_TO_MANY:
return 'many-to-many';
default:
throw new Error('Invalid relation type');
throw new ForbiddenException(
`Invalid relation type: ${relationMetadata.relationType}`,
);
}
};

View File

@ -4,6 +4,10 @@ import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metada
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 {
@ -31,7 +35,10 @@ export async function determineRelationDetails(
}
if (!fromObjectMetadata || !toObjectMetadata) {
throw new Error('Object metadata not found');
throw new RelationException(
'Object metadata not found',
RelationExceptionCode.RELATION_OBJECT_METADATA_NOT_FOUND,
);
}
const toFieldMetadata = Object.values(toObjectMetadata.fieldsById).find(

View File

@ -4,6 +4,10 @@ import { RelationType } from 'typeorm/metadata/types/RelationTypes';
import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
import {
RelationException,
RelationExceptionCode,
} from 'src/engine/twenty-orm/exceptions/relation.exception';
import { converRelationTypeToTypeORMRelationType } from 'src/engine/twenty-orm/utils/convert-relation-type-to-typeorm-relation-type.util';
interface RelationDetails {
@ -26,7 +30,10 @@ export async function determineSchemaRelationDetails(
);
if (!fieldMetadata.relationTargetObjectMetadataId) {
throw new Error('Relation target object metadata ID is missing');
throw new RelationException(
'Relation target object metadata ID is missing',
RelationExceptionCode.RELATION_OBJECT_METADATA_NOT_FOUND,
);
}
const sourceObjectMetadata =
@ -35,11 +42,17 @@ export async function determineSchemaRelationDetails(
objectMetadataMaps.byId[fieldMetadata.relationTargetObjectMetadataId];
if (!sourceObjectMetadata || !targetObjectMetadata) {
throw new Error(`Object metadata not found for field ${fieldMetadata.id}`);
throw new RelationException(
`Object metadata not found for field ${fieldMetadata.id}`,
RelationExceptionCode.RELATION_OBJECT_METADATA_NOT_FOUND,
);
}
if (!fieldMetadata.relationTargetFieldMetadataId) {
throw new Error('Relation target field metadata ID is missing');
throw new RelationException(
'Relation target field metadata ID is missing',
RelationExceptionCode.RELATION_TARGET_FIELD_METADATA_ID_NOT_FOUND,
);
}
const targetFieldMetadata =

View File

@ -2,6 +2,10 @@ import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfa
import { WorkspaceJoinColumnsMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-join-columns-metadata-args.interface';
import { WorkspaceRelationMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface';
import {
RelationException,
RelationExceptionCode,
} from 'src/engine/twenty-orm/exceptions/relation.exception';
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
export const getJoinColumn = (
@ -31,8 +35,9 @@ export const getJoinColumn = (
filteredJoinColumnsMetadataArgsCollection.length > 0 &&
oppositeFilteredJoinColumnsMetadataArgsCollection.length > 0
) {
throw new Error(
throw new RelationException(
`Join column for ${relationMetadataArgs.name} relation is present on both sides`,
RelationExceptionCode.RELATION_JOIN_COLUMN_ON_BOTH_SIDES,
);
}
@ -52,8 +57,9 @@ export const getJoinColumn = (
);
if (!inverseSideRelationMetadataArgs) {
throw new Error(
throw new RelationException(
`Inverse side join column of relation ${relationMetadataArgs.name} is missing`,
RelationExceptionCode.MISSING_RELATION_JOIN_COLUMN,
);
}
@ -67,16 +73,18 @@ export const getJoinColumn = (
// Check if there are multiple join columns for the relation
if (filteredJoinColumnsMetadataArgsCollection.length > 1) {
throw new Error(
throw new RelationException(
`Multiple join columns found for relation ${relationMetadataArgs.name}`,
RelationExceptionCode.MULTIPLE_JOIN_COLUMNS_FOUND,
);
}
const joinColumnsMetadataArgs = filteredJoinColumnsMetadataArgsCollection[0];
if (!joinColumnsMetadataArgs) {
throw new Error(
throw new RelationException(
`Join column is missing for relation ${relationMetadataArgs.name}`,
RelationExceptionCode.MISSING_RELATION_JOIN_COLUMN,
);
}