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:
+5
-5
@@ -1,8 +1,8 @@
|
||||
import { computeMorphRelationFieldName } from '@/utils/fieldMetadata/compute-morph-relation-field-name';
|
||||
import { computeMorphRelationGqlFieldName } from '@/utils/fieldMetadata/compute-morph-relation-gql-field-name';
|
||||
|
||||
describe('computeMorphRelationFieldName', () => {
|
||||
describe('computeMorphRelationGqlFieldName', () => {
|
||||
it('should return singular-based name for MANY_TO_ONE', () => {
|
||||
const result = computeMorphRelationFieldName({
|
||||
const result = computeMorphRelationGqlFieldName({
|
||||
fieldName: 'assigned',
|
||||
relationType: 'MANY_TO_ONE' as any,
|
||||
targetObjectMetadataNameSingular: 'person',
|
||||
@@ -13,7 +13,7 @@ describe('computeMorphRelationFieldName', () => {
|
||||
});
|
||||
|
||||
it('should return plural-based name for ONE_TO_MANY', () => {
|
||||
const result = computeMorphRelationFieldName({
|
||||
const result = computeMorphRelationGqlFieldName({
|
||||
fieldName: 'assigned',
|
||||
relationType: 'ONE_TO_MANY' as any,
|
||||
targetObjectMetadataNameSingular: 'person',
|
||||
@@ -25,7 +25,7 @@ describe('computeMorphRelationFieldName', () => {
|
||||
|
||||
it('should throw for invalid relation type', () => {
|
||||
expect(() =>
|
||||
computeMorphRelationFieldName({
|
||||
computeMorphRelationGqlFieldName({
|
||||
fieldName: 'assigned',
|
||||
relationType: 'INVALID' as any,
|
||||
targetObjectMetadataNameSingular: 'person',
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
import {
|
||||
computeMorphRelationGqlFieldJoinColumnName,
|
||||
computeRelationGqlFieldJoinColumnName,
|
||||
} from '@/utils/fieldMetadata/compute-relation-gql-field-join-column-name';
|
||||
|
||||
describe('computeRelationGqlFieldJoinColumnName', () => {
|
||||
it('should append `Id` to a simple field name', () => {
|
||||
expect(computeRelationGqlFieldJoinColumnName({ name: 'company' })).toBe(
|
||||
'companyId',
|
||||
);
|
||||
});
|
||||
|
||||
it('should preserve camelCase field names', () => {
|
||||
expect(
|
||||
computeRelationGqlFieldJoinColumnName({ name: 'pointOfContact' }),
|
||||
).toBe('pointOfContactId');
|
||||
});
|
||||
|
||||
it('should append `Id` to a morph-aware field name', () => {
|
||||
expect(
|
||||
computeRelationGqlFieldJoinColumnName({ name: 'targetOpportunity' }),
|
||||
).toBe('targetOpportunityId');
|
||||
});
|
||||
|
||||
it('should not strip an existing trailing `Id` (it just appends)', () => {
|
||||
expect(computeRelationGqlFieldJoinColumnName({ name: 'companyId' })).toBe(
|
||||
'companyIdId',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('computeMorphRelationGqlFieldJoinColumnName', () => {
|
||||
it('should combine field name and capitalized singular target for MANY_TO_ONE', () => {
|
||||
expect(
|
||||
computeMorphRelationGqlFieldJoinColumnName({
|
||||
fieldName: 'target',
|
||||
relationType: 'MANY_TO_ONE' as any,
|
||||
targetObjectMetadataNameSingular: 'opportunity',
|
||||
targetObjectMetadataNamePlural: 'opportunities',
|
||||
}),
|
||||
).toBe('targetOpportunityId');
|
||||
});
|
||||
|
||||
it('should combine field name and capitalized plural target for ONE_TO_MANY', () => {
|
||||
expect(
|
||||
computeMorphRelationGqlFieldJoinColumnName({
|
||||
fieldName: 'caretaker',
|
||||
relationType: 'ONE_TO_MANY' as any,
|
||||
targetObjectMetadataNameSingular: 'person',
|
||||
targetObjectMetadataNamePlural: 'people',
|
||||
}),
|
||||
).toBe('caretakerPeopleId');
|
||||
});
|
||||
|
||||
it('should handle simple plurals (e.g. `companies`)', () => {
|
||||
expect(
|
||||
computeMorphRelationGqlFieldJoinColumnName({
|
||||
fieldName: 'parent',
|
||||
relationType: 'ONE_TO_MANY' as any,
|
||||
targetObjectMetadataNameSingular: 'company',
|
||||
targetObjectMetadataNamePlural: 'companies',
|
||||
}),
|
||||
).toBe('parentCompaniesId');
|
||||
});
|
||||
|
||||
it('should throw on an invalid relation type', () => {
|
||||
expect(() =>
|
||||
computeMorphRelationGqlFieldJoinColumnName({
|
||||
fieldName: 'target',
|
||||
relationType: 'INVALID' as any,
|
||||
targetObjectMetadataNameSingular: 'opportunity',
|
||||
targetObjectMetadataNamePlural: 'opportunities',
|
||||
}),
|
||||
).toThrow();
|
||||
});
|
||||
});
|
||||
+4
-4
@@ -6,19 +6,19 @@ enum RelationType {
|
||||
ONE_TO_MANY = 'ONE_TO_MANY',
|
||||
}
|
||||
|
||||
type ComputeMorphRelationFieldNameArgs = {
|
||||
type ComputeMorphRelationGqlFieldNameArgs = {
|
||||
fieldName: string;
|
||||
relationType: RelationType;
|
||||
targetObjectMetadataNameSingular: string;
|
||||
targetObjectMetadataNamePlural: string;
|
||||
};
|
||||
|
||||
export const computeMorphRelationFieldName = ({
|
||||
export const computeMorphRelationGqlFieldName = ({
|
||||
fieldName,
|
||||
relationType,
|
||||
targetObjectMetadataNameSingular: nameSingular,
|
||||
targetObjectMetadataNamePlural: namePlural,
|
||||
}: ComputeMorphRelationFieldNameArgs): string => {
|
||||
}: ComputeMorphRelationGqlFieldNameArgs): string => {
|
||||
if (relationType === RelationType.MANY_TO_ONE) {
|
||||
return `${fieldName}${capitalize(nameSingular)}`;
|
||||
}
|
||||
@@ -29,6 +29,6 @@ export const computeMorphRelationFieldName = ({
|
||||
|
||||
throw new CustomError(
|
||||
`Invalid relation type (${relationType}) for field ${fieldName} on ${nameSingular}`,
|
||||
'INVALID_RELATION_TYPE_FOR_COMPUTE_MORPH_RELATION_FIELD_NAME',
|
||||
'INVALID_RELATION_TYPE_FOR_COMPUTE_MORPH_RELATION_GQL_FIELD_NAME',
|
||||
);
|
||||
};
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
import { computeMorphRelationGqlFieldName } from '@/utils/fieldMetadata/compute-morph-relation-gql-field-name';
|
||||
|
||||
enum RelationType {
|
||||
MANY_TO_ONE = 'MANY_TO_ONE',
|
||||
ONE_TO_MANY = 'ONE_TO_MANY',
|
||||
}
|
||||
|
||||
type ComputeRelationGqlFieldJoinColumnNameArgs = {
|
||||
name: string;
|
||||
};
|
||||
|
||||
export const computeRelationGqlFieldJoinColumnName = ({
|
||||
name,
|
||||
}: ComputeRelationGqlFieldJoinColumnNameArgs): string => {
|
||||
return `${name}Id`;
|
||||
};
|
||||
|
||||
type ComputeMorphRelationGqlFieldJoinColumnNameArgs = {
|
||||
fieldName: string;
|
||||
relationType: RelationType;
|
||||
targetObjectMetadataNameSingular: string;
|
||||
targetObjectMetadataNamePlural: string;
|
||||
};
|
||||
|
||||
export const computeMorphRelationGqlFieldJoinColumnName = ({
|
||||
fieldName,
|
||||
relationType,
|
||||
targetObjectMetadataNameSingular,
|
||||
targetObjectMetadataNamePlural,
|
||||
}: ComputeMorphRelationGqlFieldJoinColumnNameArgs): string => {
|
||||
const morphGqlFieldName = computeMorphRelationGqlFieldName({
|
||||
fieldName,
|
||||
relationType,
|
||||
targetObjectMetadataNameSingular,
|
||||
targetObjectMetadataNamePlural,
|
||||
});
|
||||
|
||||
return computeRelationGqlFieldJoinColumnName({ name: morphGqlFieldName });
|
||||
};
|
||||
Reference in New Issue
Block a user