Fix and refactor relation field name collision validation (#15920)

# Introduction
Fixes https://github.com/twentyhq/private-issues/issues/371
We weren't strictly validating relation field collision on join column
name availability of the target field object

## Refactor
Extracted morph or relation specific condition out of the common flat
field metadata name validate availability to be located in the dedicated
morph or relation flat field validator

## Tests
Added two tests, ONE_TO_MANY and MANY_TO_ONE in order to cover the use
case
This commit is contained in:
Paul Rastoin
2025-11-20 16:10:35 +01:00
committed by GitHub
parent 9c6d8330df
commit e5255df1a1
11 changed files with 484 additions and 86 deletions
@@ -0,0 +1,59 @@
import { RelationType } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
type ObjectFieldNamesAndJoinColumnNames = {
fieldNames: string[];
joinColumnNames: string[];
};
export const getObjectFieldNamesAndJoinColumnNames = ({
flatFieldMetadataMaps,
flatObjectMetadata,
}: {
flatObjectMetadata: FlatObjectMetadata;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
}): {
objectFieldNamesAndJoinColumnNames: ObjectFieldNamesAndJoinColumnNames;
} => {
const objectFlatFieldMetadatas =
findManyFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityMaps: flatFieldMetadataMaps,
flatEntityIds: flatObjectMetadata.fieldMetadataIds,
});
const initialAccumulator: ObjectFieldNamesAndJoinColumnNames = {
joinColumnNames: [],
fieldNames: [],
};
const objectFieldNamesAndJoinColumnNames = objectFlatFieldMetadatas.reduce(
(acc, flatFieldMetadata) => {
if (
isMorphOrRelationFlatFieldMetadata(flatFieldMetadata) &&
flatFieldMetadata.settings.relationType === RelationType.MANY_TO_ONE &&
isDefined(flatFieldMetadata.settings.joinColumnName)
) {
return {
...acc,
fieldNames: [...acc.fieldNames, flatFieldMetadata.name],
joinColumnNames: [
...acc.joinColumnNames,
flatFieldMetadata.settings.joinColumnName,
],
};
}
return {
...acc,
fieldNames: [...acc.fieldNames, flatFieldMetadata.name],
};
},
initialAccumulator,
);
return { objectFieldNamesAndJoinColumnNames };
};