Handle relations between same objects (#4137)

* Handle relations between same objects

* Simplify conditions

---------

Co-authored-by: Thomas Trompette <thomast@twenty.com>
This commit is contained in:
Thomas Trompette
2024-02-23 09:51:42 +01:00
committed by GitHub
parent 679456e819
commit 67e27a69ff
5 changed files with 62 additions and 20 deletions

View File

@ -1,5 +1,7 @@
import { FieldMetadataInterface } from 'src/metadata/field-metadata/interfaces/field-metadata.interface';
import { RelationMetadataInterface } from 'src/metadata/field-metadata/interfaces/relation-metadata.interface'; import { RelationMetadataInterface } from 'src/metadata/field-metadata/interfaces/relation-metadata.interface';
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
import { RelationMetadataType } from 'src/metadata/relation-metadata/relation-metadata.entity'; import { RelationMetadataType } from 'src/metadata/relation-metadata/relation-metadata.entity';
import { import {
deduceRelationDirection, deduceRelationDirection,
@ -7,39 +9,61 @@ import {
} from 'src/workspace/utils/deduce-relation-direction.util'; } from 'src/workspace/utils/deduce-relation-direction.util';
describe('deduceRelationDirection', () => { describe('deduceRelationDirection', () => {
it('should return FROM when the current object Metadata ID matches fromObjectMetadataId', () => { it('should return FROM when the current object Metadata ID matches fromObjectMetadataId and id matches fromFieldMetadataId', () => {
const currentObjectId = 'from_object_id'; const fieldMetadata: FieldMetadataInterface = {
id: 'field_id',
objectMetadataId: 'from_object_id',
type: FieldMetadataType.RELATION,
name: 'field_name',
label: 'Field Name',
description: 'Field Description',
targetColumnMap: {
default: 'default_column',
},
};
const relationMetadata = { const relationMetadata = {
id: 'relation_id', id: 'relation_id',
fromObjectMetadataId: currentObjectId, fromObjectMetadataId: fieldMetadata.objectMetadataId,
toObjectMetadataId: 'to_object_id', toObjectMetadataId: 'to_object_id',
fromFieldMetadataId: 'from_field_id', fromFieldMetadataId: fieldMetadata.id,
toFieldMetadataId: 'to_field_id', toFieldMetadataId: 'to_field_id',
relationType: RelationMetadataType.ONE_TO_ONE, relationType: RelationMetadataType.ONE_TO_ONE,
}; };
const result = deduceRelationDirection( const result = deduceRelationDirection(
currentObjectId, fieldMetadata,
relationMetadata as RelationMetadataInterface, relationMetadata as RelationMetadataInterface,
); );
expect(result).toBe(RelationDirection.FROM); expect(result).toBe(RelationDirection.FROM);
}); });
it('should return TO when the current object Metadata ID matches toObjectMetadataId', () => { it('should return TO when the current object Metadata ID matches toObjectMetadataId and id matches toFieldMetadataId', () => {
// Arrange // Arrange
const currentObjectId = 'to_object_id'; const fieldMetadata: FieldMetadataInterface = {
id: 'field_id',
objectMetadataId: 'to_object_id',
type: FieldMetadataType.RELATION,
name: 'field_name',
label: 'Field Name',
description: 'Field Description',
targetColumnMap: {
default: 'default_column',
},
};
const relationMetadata = { const relationMetadata = {
id: 'relation_id', id: 'relation_id',
fromObjectMetadataId: 'from_object_id', fromObjectMetadataId: 'from_object_id',
toObjectMetadataId: currentObjectId, toObjectMetadataId: fieldMetadata.objectMetadataId,
fromFieldMetadataId: 'from_field_id', fromFieldMetadataId: 'from_field_id',
toFieldMetadataId: 'to_field_id', toFieldMetadataId: fieldMetadata.id,
relationType: RelationMetadataType.ONE_TO_ONE, relationType: RelationMetadataType.ONE_TO_ONE,
}; };
const result = deduceRelationDirection( const result = deduceRelationDirection(
currentObjectId, fieldMetadata,
relationMetadata as RelationMetadataInterface, relationMetadata as RelationMetadataInterface,
); );
@ -47,7 +71,18 @@ describe('deduceRelationDirection', () => {
}); });
it('should throw an error when the current object Metadata ID does not match any object metadata ID', () => { it('should throw an error when the current object Metadata ID does not match any object metadata ID', () => {
const currentObjectId = 'unrelated_object_id'; const fieldMetadata: FieldMetadataInterface = {
id: 'field_id',
objectMetadataId: 'unrelated_object_id',
type: FieldMetadataType.RELATION,
name: 'field_name',
label: 'Field Name',
description: 'Field Description',
targetColumnMap: {
default: 'default_column',
},
};
const relationMetadata = { const relationMetadata = {
id: 'relation_id', id: 'relation_id',
fromObjectMetadataId: 'from_object_id', fromObjectMetadataId: 'from_object_id',
@ -59,11 +94,11 @@ describe('deduceRelationDirection', () => {
expect(() => expect(() =>
deduceRelationDirection( deduceRelationDirection(
currentObjectId, fieldMetadata,
relationMetadata as RelationMetadataInterface, relationMetadata as RelationMetadataInterface,
), ),
).toThrow( ).toThrow(
`Relation metadata ${relationMetadata.id} is not related to object ${currentObjectId}`, `Relation metadata ${relationMetadata.id} is not related to object ${fieldMetadata.objectMetadataId}`,
); );
}); });
}); });

View File

@ -1,3 +1,4 @@
import { FieldMetadataInterface } from 'src/metadata/field-metadata/interfaces/field-metadata.interface';
import { RelationMetadataInterface } from 'src/metadata/field-metadata/interfaces/relation-metadata.interface'; import { RelationMetadataInterface } from 'src/metadata/field-metadata/interfaces/relation-metadata.interface';
export enum RelationDirection { export enum RelationDirection {
@ -6,18 +7,24 @@ export enum RelationDirection {
} }
export const deduceRelationDirection = ( export const deduceRelationDirection = (
currentObjectId: string, fieldMetadata: FieldMetadataInterface,
relationMetadata: RelationMetadataInterface, relationMetadata: RelationMetadataInterface,
): RelationDirection => { ): RelationDirection => {
if (relationMetadata.fromObjectMetadataId === currentObjectId) { if (
relationMetadata.fromObjectMetadataId === fieldMetadata.objectMetadataId &&
relationMetadata.fromFieldMetadataId === fieldMetadata.id
) {
return RelationDirection.FROM; return RelationDirection.FROM;
} }
if (relationMetadata.toObjectMetadataId === currentObjectId) { if (
relationMetadata.toObjectMetadataId === fieldMetadata.objectMetadataId &&
relationMetadata.toFieldMetadataId === fieldMetadata.id
) {
return RelationDirection.TO; return RelationDirection.TO;
} }
throw new Error( throw new Error(
`Relation metadata ${relationMetadata.id} is not related to object ${currentObjectId}`, `Relation metadata ${relationMetadata.id} is not related to object ${fieldMetadata.objectMetadataId}`,
); );
}; };

View File

@ -55,7 +55,7 @@ export class RelationMetadataHealthService {
} }
const relationDirection = deduceRelationDirection( const relationDirection = deduceRelationDirection(
objectMetadata.id, fieldMetadata,
relationMetadata, relationMetadata,
); );

View File

@ -72,7 +72,7 @@ export class RelationFieldAliasFactory {
} }
const relationDirection = deduceRelationDirection( const relationDirection = deduceRelationDirection(
fieldMetadata.objectMetadataId, fieldMetadata,
relationMetadata, relationMetadata,
); );
// Retrieve the referenced object metadata based on the relation direction // Retrieve the referenced object metadata based on the relation direction

View File

@ -128,7 +128,7 @@ export class ExtendObjectTypeDefinitionFactory {
} }
const relationDirection = deduceRelationDirection( const relationDirection = deduceRelationDirection(
fieldMetadata.objectMetadataId, fieldMetadata,
relationMetadata, relationMetadata,
); );
const relationType = this.relationTypeFactory.create( const relationType = this.relationTypeFactory.create(