diff --git a/packages/twenty-server/src/engine/core-modules/related-person-ids/utils/__tests__/find-relation-paths-to-person.util.spec.ts b/packages/twenty-server/src/engine/core-modules/related-person-ids/utils/__tests__/find-relation-paths-to-person.util.spec.ts index 04717ee5b6..d07eac2cc9 100644 --- a/packages/twenty-server/src/engine/core-modules/related-person-ids/utils/__tests__/find-relation-paths-to-person.util.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/related-person-ids/utils/__tests__/find-relation-paths-to-person.util.spec.ts @@ -18,7 +18,11 @@ type RelationSpec = { inverseFieldName: string; }; -const buildGraphFixtures = (graph: Record) => { +const buildGraphFixtures = ( + graph: Record, + options: { systemObjectNames?: string[] } = {}, +) => { + const systemObjectNames = options.systemObjectNames ?? []; const fieldId = (objectNameSingular: string, fieldName: string) => `${objectNameSingular}.${fieldName}`; @@ -82,6 +86,7 @@ const buildGraphFixtures = (graph: Record) => { targetObjectMetadata: { id: spec.targetObjectNameSingular, nameSingular: spec.targetObjectNameSingular, + isSystem: systemObjectNames.includes(spec.targetObjectNameSingular), }, sourceFieldMetadata: { name: spec.fieldName }, targetFieldMetadata: { name: spec.inverseFieldName }, @@ -261,6 +266,62 @@ describe('findRelationPathsToPerson', () => { ]); }); + it('does not traverse system objects while looking for related people', () => { + const { flatObjectMetadataMaps, flatFieldMetadataMaps } = + buildGraphFixtures( + { + opportunity: [ + { + fieldName: 'pointOfContact', + relationType: RelationType.MANY_TO_ONE, + targetObjectNameSingular: 'person', + inverseFieldName: 'pointOfContactForOpportunities', + }, + { + fieldName: 'owner', + relationType: RelationType.MANY_TO_ONE, + targetObjectNameSingular: 'workspaceMember', + inverseFieldName: 'ownedOpportunities', + }, + ], + workspaceMember: [ + { + fieldName: 'messageParticipants', + relationType: RelationType.ONE_TO_MANY, + targetObjectNameSingular: 'messageParticipant', + inverseFieldName: 'workspaceMember', + }, + ], + messageParticipant: [ + { + fieldName: 'person', + relationType: RelationType.MANY_TO_ONE, + targetObjectNameSingular: 'person', + inverseFieldName: 'messageParticipants', + }, + ], + person: [], + }, + { systemObjectNames: ['workspaceMember', 'messageParticipant'] }, + ); + + expect( + findRelationPathsToPerson({ + rootObjectNameSingular: 'opportunity', + flatObjectMetadataMaps, + flatFieldMetadataMaps, + }), + ).toEqual([ + [ + { + direction: RelationType.MANY_TO_ONE, + queryObjectNameSingular: 'opportunity', + joinColumnName: 'pointOfContactId', + }, + ], + ]); + }); + it('returns no path when person is unreachable, terminating on relation cycles', () => { const { flatObjectMetadataMaps, flatFieldMetadataMaps } = buildGraphFixtures({ diff --git a/packages/twenty-server/src/engine/core-modules/related-person-ids/utils/find-relation-paths-to-person.util.ts b/packages/twenty-server/src/engine/core-modules/related-person-ids/utils/find-relation-paths-to-person.util.ts index 0cc45716c2..f948a00618 100644 --- a/packages/twenty-server/src/engine/core-modules/related-person-ids/utils/find-relation-paths-to-person.util.ts +++ b/packages/twenty-server/src/engine/core-modules/related-person-ids/utils/find-relation-paths-to-person.util.ts @@ -15,6 +15,9 @@ import { buildObjectIdByNameMaps } from 'src/engine/metadata-modules/flat-object const PERSON_OBJECT_NAME_SINGULAR = 'person'; const DEFAULT_MAX_RELATION_DEPTH_TO_PERSON = 3; +const isSystemObjectMetadata = (objectMetadata: { isSystem?: boolean }) => + objectMetadata.isSystem === true; + export type RelationHopToPerson = { direction: RelationType; queryObjectNameSingular: string; @@ -103,14 +106,21 @@ export const findRelationPathsToPerson = ({ }, ]; - const targetObjectId = relation.targetObjectMetadata.id; - if ( relation.targetObjectMetadata.nameSingular === PERSON_OBJECT_NAME_SINGULAR ) { pathsToPerson.push(nextPath); - } else if (!visitedObjectIds.has(targetObjectId)) { + continue; + } + + if (isSystemObjectMetadata(relation.targetObjectMetadata)) { + continue; + } + + const targetObjectId = relation.targetObjectMetadata.id; + + if (!visitedObjectIds.has(targetObjectId)) { objectIdsReachedThisDepth.add(targetObjectId); nextFrontier.push({ objectId: targetObjectId, path: nextPath }); }