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:
@ -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}`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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}`,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -55,7 +55,7 @@ export class RelationMetadataHealthService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const relationDirection = deduceRelationDirection(
|
const relationDirection = deduceRelationDirection(
|
||||||
objectMetadata.id,
|
fieldMetadata,
|
||||||
relationMetadata,
|
relationMetadata,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
Reference in New Issue
Block a user