refactor: stop reading joinColumnName from relation field settings (#20304)
## Summary `joinColumnName` on relation field settings is always derivable from the field name (and the target object name for morph relations). This PR stops reading it from settings anywhere in production code; the stored value is no longer used. The settings field is **not** removed from data yet — a follow-up can drop it once we are confident nothing depends on the stored value. ## Helpers The helpers are split by layer because frontend and backend hold morph relations differently: the frontend has a base name plus a `morphRelations[]` array, the backend has one row per target with the name already morph-resolved. | Helper | Layer | When to use | |---|---|---| | `computeRelationGqlFieldJoinColumnName` | Shared / frontend (`gqlField`) | Non-morph relation on the frontend. | | `computeMorphRelationGqlFieldName` | Shared / frontend (`gqlField`) | Need the per-target morph gqlField name (e.g. `targetCompany`). | | `computeMorphRelationGqlFieldJoinColumnName` | Shared / frontend (`gqlField`) | Per-target morph join column on the frontend. Prefer over the non-morph helper for any morph field — it forces the per-target inputs. | | `computeMorphOrRelationFieldJoinColumnName` | Backend (`FlatFieldMetadata.name`) | Any backend read or write — the flat name is already morph-resolved, so one helper covers both cases. | | `computeMorphRelationFlatFieldName` | Backend (`FlatFieldMetadata.name`) | **Mutation paths only** (create / update / object rename). Reads consume the stored `field.name` and never call this. | ## Test plan - [x] Typecheck and lint (front, server, shared) - [x] Existing unit tests pass - [ ] CI green
This commit is contained in:
+2
-2
@@ -1,9 +1,9 @@
|
||||
type ComputeRelationFieldJoinColumnNameArgs = {
|
||||
type ComputeMorphOrRelationFieldJoinColumnNameArgs = {
|
||||
name: string;
|
||||
};
|
||||
|
||||
export const computeMorphOrRelationFieldJoinColumnName = ({
|
||||
name,
|
||||
}: ComputeRelationFieldJoinColumnNameArgs) => {
|
||||
}: ComputeMorphOrRelationFieldJoinColumnNameArgs): string => {
|
||||
return `${name}Id`;
|
||||
};
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
import { RelationType } from 'twenty-shared/types';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
|
||||
import {
|
||||
FieldMetadataException,
|
||||
FieldMetadataExceptionCode,
|
||||
} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
|
||||
|
||||
type ComputeMorphRelationFlatFieldNameArgs = {
|
||||
fieldName: string;
|
||||
relationType: RelationType;
|
||||
targetObjectMetadataNameSingular: string;
|
||||
targetObjectMetadataNamePlural: string;
|
||||
};
|
||||
|
||||
export const computeMorphRelationFlatFieldName = ({
|
||||
fieldName,
|
||||
relationType,
|
||||
targetObjectMetadataNameSingular: nameSingular,
|
||||
targetObjectMetadataNamePlural: namePlural,
|
||||
}: ComputeMorphRelationFlatFieldNameArgs): string => {
|
||||
if (relationType === RelationType.MANY_TO_ONE) {
|
||||
return `${fieldName}${capitalize(nameSingular)}`;
|
||||
}
|
||||
|
||||
if (relationType === RelationType.ONE_TO_MANY) {
|
||||
return `${fieldName}${capitalize(namePlural)}`;
|
||||
}
|
||||
|
||||
throw new FieldMetadataException(
|
||||
`Invalid relation type (${relationType}) for field ${fieldName} on ${nameSingular}`,
|
||||
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
|
||||
);
|
||||
};
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import { FieldMetadataType, RelationType } from 'twenty-shared/types';
|
||||
|
||||
import { getFlatFieldsFromFlatObjectMetadata } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-flat-fields-for-flat-object-metadata.util';
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { getFlatFieldsFromFlatObjectMetadata } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-flat-fields-for-flat-object-metadata.util';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { isFlatFieldMetadataOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
|
||||
|
||||
+4
-3
@@ -2,10 +2,11 @@ import {
|
||||
FieldMetadataType,
|
||||
type RelationUpdatePayload,
|
||||
} from 'twenty-shared/types';
|
||||
import { computeMorphRelationFieldName, isDefined } from 'twenty-shared/utils';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { computeMorphRelationFlatFieldName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-relation-flat-field-name.util';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
@@ -89,7 +90,7 @@ export const computeFlatFieldToUpdateFromMorphRelationUpdatePayload = ({
|
||||
flatEntityMaps: flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
const computedMorphName = computeMorphRelationFieldName({
|
||||
const computedMorphName = computeMorphRelationFlatFieldName({
|
||||
fieldName: morphNameWithoutObjectName,
|
||||
relationType: fieldMetadataToUpdate.settings.relationType,
|
||||
targetObjectMetadataNameSingular: newTargetObjectMetadata.nameSingular,
|
||||
|
||||
+4
-3
@@ -1,12 +1,13 @@
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { computeMorphRelationFieldName, isDefined } from 'twenty-shared/utils';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { computeMorphRelationFlatFieldName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-relation-flat-field-name.util';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
||||
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { type FieldInputTranspilationResult } from 'src/engine/metadata-modules/flat-field-metadata/types/field-input-transpilation-result.type';
|
||||
@@ -86,7 +87,7 @@ export const fromMorphRelationCreateFieldInputToFlatFieldMetadatas = async ({
|
||||
const morphId = v4();
|
||||
const flatFieldsAndIndexes = morphRelationCreationPayload.reduce(
|
||||
(acc, { relationCreationPayload, targetFlatObjectMetadata }) => {
|
||||
const currentMorphRelationFieldName = computeMorphRelationFieldName({
|
||||
const currentMorphRelationFieldName = computeMorphRelationFlatFieldName({
|
||||
fieldName: createFieldInput.name,
|
||||
relationType: relationCreationPayload.type,
|
||||
targetObjectMetadataNameSingular: targetFlatObjectMetadata.nameSingular,
|
||||
|
||||
+1
-1
@@ -2,10 +2,10 @@ import { msg } from '@lingui/core/macro';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
||||
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { type FieldInputTranspilationResult } from 'src/engine/metadata-modules/flat-field-metadata/types/field-input-transpilation-result.type';
|
||||
|
||||
+2
-1
@@ -4,12 +4,13 @@ import {
|
||||
RelationOnDeleteAction,
|
||||
RelationType,
|
||||
} from 'twenty-shared/types';
|
||||
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
||||
import { type MorphOrRelationFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/types/morph-or-relation-field-metadata-type.type';
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { generateIndexForFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/generate-index-for-flat-field-metadata.util';
|
||||
import { getDefaultFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/get-default-flat-field-metadata-from-create-field-input.util';
|
||||
|
||||
+5
-4
@@ -1,6 +1,6 @@
|
||||
import { RelationType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { findManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-universal-identifier-in-universal-flat-entity-maps.util';
|
||||
import { isMorphOrRelationUniversalFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
|
||||
import { type UniversalFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-maps.type';
|
||||
@@ -39,15 +39,16 @@ export const getObjectFieldNamesAndJoinColumnNames = ({
|
||||
universalFlatFieldMetadata,
|
||||
) &&
|
||||
universalFlatFieldMetadata.universalSettings.relationType ===
|
||||
RelationType.MANY_TO_ONE &&
|
||||
isDefined(universalFlatFieldMetadata.universalSettings.joinColumnName)
|
||||
RelationType.MANY_TO_ONE
|
||||
) {
|
||||
return {
|
||||
...acc,
|
||||
fieldNames: [...acc.fieldNames, universalFlatFieldMetadata.name],
|
||||
joinColumnNames: [
|
||||
...acc.joinColumnNames,
|
||||
universalFlatFieldMetadata.universalSettings.joinColumnName,
|
||||
computeMorphOrRelationFieldJoinColumnName({
|
||||
name: universalFlatFieldMetadata.name,
|
||||
}),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
+2
-2
@@ -3,9 +3,9 @@ import {
|
||||
type FieldMetadataType,
|
||||
type FromTo,
|
||||
} from 'twenty-shared/types';
|
||||
import { computeMorphRelationFieldName } from 'twenty-shared/utils';
|
||||
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { computeMorphRelationFlatFieldName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-relation-flat-field-name.util';
|
||||
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
@@ -37,7 +37,7 @@ const updateMorphFlatFieldName = ({
|
||||
namePlural: fromRelationTargetFlatObjectMetadata.namePlural,
|
||||
});
|
||||
|
||||
const newMorphFieldName = computeMorphRelationFieldName({
|
||||
const newMorphFieldName = computeMorphRelationFlatFieldName({
|
||||
fieldName: initialMorphRelationFieldName,
|
||||
relationType: fromMorphFlatFieldMetadata.universalSettings.relationType,
|
||||
targetObjectMetadataNameSingular:
|
||||
|
||||
+11
-5
@@ -1,9 +1,11 @@
|
||||
import { RelationType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import {
|
||||
FlatEntityMapsException,
|
||||
FlatEntityMapsExceptionCode,
|
||||
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { isMorphOrRelationUniversalFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
|
||||
import { generateDeterministicIndexNameV2 } from 'src/engine/metadata-modules/index-metadata/utils/generate-deterministic-index-name-v2';
|
||||
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
|
||||
@@ -36,11 +38,15 @@ export const generateFlatIndexMetadataWithNameOrThrow = ({
|
||||
);
|
||||
}
|
||||
|
||||
const name = isMorphOrRelationUniversalFlatFieldMetadata(
|
||||
relatedFlatFieldMetadata,
|
||||
)
|
||||
? (relatedFlatFieldMetadata.universalSettings.joinColumnName ??
|
||||
relatedFlatFieldMetadata.name)
|
||||
const isManyToOneRelation =
|
||||
isMorphOrRelationUniversalFlatFieldMetadata(relatedFlatFieldMetadata) &&
|
||||
relatedFlatFieldMetadata.universalSettings?.relationType ===
|
||||
RelationType.MANY_TO_ONE;
|
||||
|
||||
const name = isManyToOneRelation
|
||||
? computeMorphOrRelationFieldJoinColumnName({
|
||||
name: relatedFlatFieldMetadata.name,
|
||||
})
|
||||
: relatedFlatFieldMetadata.name;
|
||||
|
||||
return {
|
||||
|
||||
+1
-1
@@ -5,10 +5,10 @@ import {
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { capitalize, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { generateMorphOrRelationFlatFieldMetadataPair } from 'src/engine/metadata-modules/flat-field-metadata/utils/generate-morph-or-relation-flat-field-metadata-pair.util';
|
||||
|
||||
Reference in New Issue
Block a user