[Refactor] generateDepthOneRecordGqlFieldsFromRecord (#10499)

## Introduction
This refactor results from this
https://github.com/twentyhq/twenty/pull/10493 review
Introduced a new abstraction to the extinsting
`generateDepthOneRecordGqlFields` that was accepting an optional record
in arg in order to map generated `recordGqlFields` to the keys in the
record

1/ Created a dedicated util method
`generateDepthOneRecordGqlFieldsFromRecord` to do so
2/ Updated each previous `generateDepthOneRecordGqlFields` passing a
record to call new `generateDepthOneRecordGqlFieldsFromRecord`
This commit is contained in:
Paul Rastoin
2025-02-26 12:11:45 +01:00
committed by GitHub
parent 41a412bd55
commit ec87218b9c
10 changed files with 98 additions and 79 deletions

View File

@ -7,7 +7,7 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache';
import { getRecordNodeFromRecord } from '@/object-record/cache/utils/getRecordNodeFromRecord';
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
import { computeDepthOneRecordGqlFieldsFromRecord } from '@/object-record/graphql/utils/computeDepthOneRecordGqlFieldsFromRecord';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { prefillRecord } from '@/object-record/utils/prefillRecord';
import { capitalize } from 'twenty-shared';
@ -28,7 +28,7 @@ export const useCreateOneRecordInCache = <T extends ObjectRecord>({
objectMetadataItem,
input: record,
});
const recordGqlFields = generateDepthOneRecordGqlFields({
const recordGqlFields = computeDepthOneRecordGqlFieldsFromRecord({
objectMetadataItem,
record: prefilledRecord,
});

View File

@ -0,0 +1,49 @@
import { computeDepthOneRecordGqlFieldsFromRecord } from '@/object-record/graphql/utils/computeDepthOneRecordGqlFieldsFromRecord';
import {
getPersonObjectMetadataItem,
getPersonRecord,
} from '~/testing/mock-data/people';
describe('computeDepthOneRecordGqlFieldsFromRecord', () => {
const objectMetadataItem = getPersonObjectMetadataItem();
it('Should handle basic call', () => {
const personRecord = getPersonRecord();
const result = computeDepthOneRecordGqlFieldsFromRecord({
objectMetadataItem,
record: personRecord,
});
expect(result).toMatchInlineSnapshot(`
{
"attachments": false,
"avatarUrl": false,
"calendarEventParticipants": false,
"city": true,
"company": true,
"companyId": false,
"createdAt": true,
"createdBy": true,
"deletedAt": true,
"emails": false,
"favorites": false,
"id": true,
"intro": false,
"jobTitle": true,
"linkedinLink": true,
"messageParticipants": false,
"name": true,
"noteTargets": true,
"performanceRating": false,
"phones": true,
"pointOfContactForOpportunities": false,
"position": true,
"searchVector": false,
"taskTargets": true,
"timelineActivities": false,
"updatedAt": false,
"whatsapp": false,
"workPreference": false,
"xLink": true,
}
`);
});
});

View File

@ -1,52 +1,8 @@
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
import {
getPersonObjectMetadataItem,
getPersonRecord,
} from '~/testing/mock-data/people';
import { getPersonObjectMetadataItem } from '~/testing/mock-data/people';
describe('generateDepthOneRecordGqlFields', () => {
const objectMetadataItem = getPersonObjectMetadataItem();
it('Should handle basic call with both objectMetadataItem and record', () => {
const personRecord = getPersonRecord();
const result = generateDepthOneRecordGqlFields({
objectMetadataItem,
record: personRecord,
});
expect(result).toMatchInlineSnapshot(`
{
"attachments": false,
"avatarUrl": false,
"calendarEventParticipants": false,
"city": true,
"company": true,
"companyId": false,
"createdAt": true,
"createdBy": true,
"deletedAt": true,
"emails": false,
"favorites": false,
"id": true,
"intro": false,
"jobTitle": true,
"linkedinLink": true,
"messageParticipants": false,
"name": true,
"noteTargets": true,
"performanceRating": false,
"phones": true,
"pointOfContactForOpportunities": false,
"position": true,
"searchVector": false,
"taskTargets": true,
"timelineActivities": false,
"updatedAt": false,
"whatsapp": false,
"workPreference": false,
"xLink": true,
}
`);
});
it('Should handle basic call with standalone objectMetadataItem', () => {
const result = generateDepthOneRecordGqlFields({
objectMetadataItem,

View File

@ -0,0 +1,29 @@
import {
GenerateDepthOneRecordGqlFields,
generateDepthOneRecordGqlFields,
} from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
type ComputeDepthOneRecordGqlFieldsFromRecordArgs =
GenerateDepthOneRecordGqlFields & {
record: Partial<ObjectRecord>;
};
export const computeDepthOneRecordGqlFieldsFromRecord = ({
objectMetadataItem,
record,
}: ComputeDepthOneRecordGqlFieldsFromRecordArgs) => {
const depthOneRecordGqlFields = generateDepthOneRecordGqlFields({
objectMetadataItem,
});
const recordKeys = Object.keys(record);
return Object.keys(depthOneRecordGqlFields).reduce<Record<string, boolean>>(
(acc, key) => {
return {
...acc,
[key]: recordKeys.includes(key),
};
},
depthOneRecordGqlFields,
);
};

View File

@ -1,30 +1,14 @@
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { isDefined } from 'twenty-shared';
export type GenerateDepthOneRecordGqlFields = {
objectMetadataItem: ObjectMetadataItem;
};
export const generateDepthOneRecordGqlFields = ({
objectMetadataItem,
record,
}: {
objectMetadataItem: ObjectMetadataItem;
record?: Record<string, any>;
}) => {
const gqlFieldsFromObjectMetadataItem = objectMetadataItem.fields.reduce<
Record<string, boolean>
>((acc, field) => {
}: GenerateDepthOneRecordGqlFields) =>
objectMetadataItem.fields.reduce<Record<string, true>>((acc, field) => {
return {
...acc,
[field.name]: true,
};
}, {});
if (isDefined(record)) {
return Object.keys(gqlFieldsFromObjectMetadataItem).reduce((acc, key) => {
return {
...acc,
[key]: Object.keys(record).includes(key),
};
}, gqlFieldsFromObjectMetadataItem);
}
return gqlFieldsFromObjectMetadataItem;
};

View File

@ -2,7 +2,7 @@ import { renderHook, waitFor } from '@testing-library/react';
import { getRecordFromCache } from '@/object-record/cache/utils/getRecordFromCache';
import { updateRecordFromCache } from '@/object-record/cache/utils/updateRecordFromCache';
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
import { computeDepthOneRecordGqlFieldsFromRecord } from '@/object-record/graphql/utils/computeDepthOneRecordGqlFieldsFromRecord';
import {
personIds,
personRecords,
@ -115,7 +115,7 @@ describe('useDeleteManyRecords', () => {
objectMetadataItem,
objectMetadataItems,
record,
recordGqlFields: generateDepthOneRecordGqlFields({
recordGqlFields: computeDepthOneRecordGqlFieldsFromRecord({
objectMetadataItem,
record,
}),

View File

@ -3,7 +3,7 @@ import { act } from 'react';
import { getRecordFromCache } from '@/object-record/cache/utils/getRecordFromCache';
import { updateRecordFromCache } from '@/object-record/cache/utils/updateRecordFromCache';
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
import { computeDepthOneRecordGqlFieldsFromRecord } from '@/object-record/graphql/utils/computeDepthOneRecordGqlFieldsFromRecord';
import {
query,
responseData,
@ -169,7 +169,7 @@ describe('useDeleteOneRecord', () => {
describe('B. Starting from filled cache', () => {
beforeEach(() => {
const recordGqlFields = generateDepthOneRecordGqlFields({
const recordGqlFields = computeDepthOneRecordGqlFieldsFromRecord({
objectMetadataItem,
record: personRecord,
});

View File

@ -4,7 +4,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache';
import { updateRecordFromCache } from '@/object-record/cache/utils/updateRecordFromCache';
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
import { computeDepthOneRecordGqlFieldsFromRecord } from '@/object-record/graphql/utils/computeDepthOneRecordGqlFieldsFromRecord';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { isDefined } from 'twenty-shared';
@ -85,7 +85,7 @@ export const useAttachRelatedRecordFromRecord = ({
...cachedRelatedRecord,
[fieldOnRelatedObject]: previousRecord,
};
const gqlFields = generateDepthOneRecordGqlFields({
const gqlFields = computeDepthOneRecordGqlFieldsFromRecord({
objectMetadataItem: relatedObjectMetadataItem,
record: previousRecordWithRelation,
});

View File

@ -8,6 +8,7 @@ import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordF
import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename';
import { getRecordNodeFromRecord } from '@/object-record/cache/utils/getRecordNodeFromRecord';
import { updateRecordFromCache } from '@/object-record/cache/utils/updateRecordFromCache';
import { computeDepthOneRecordGqlFieldsFromRecord } from '@/object-record/graphql/utils/computeDepthOneRecordGqlFieldsFromRecord';
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
import { useRefetchAggregateQueries } from '@/object-record/hooks/useRefetchAggregateQueries';
import { useUpdateOneRecordMutation } from '@/object-record/hooks/useUpdateOneRecordMutation';
@ -105,7 +106,7 @@ export const useUpdateOneRecord = <
isDefined(cachedRecordWithConnection);
if (shouldHandleOptimisticCache) {
const recordGqlFields = generateDepthOneRecordGqlFields({
const recordGqlFields = computeDepthOneRecordGqlFieldsFromRecord({
objectMetadataItem,
record: optimisticRecordInput,
});
@ -165,7 +166,7 @@ export const useUpdateOneRecord = <
).filter((diffKey) => !cachedRecordKeys.has(diffKey));
const recordGqlFields = {
...generateDepthOneRecordGqlFields({
...computeDepthOneRecordGqlFieldsFromRecord({
objectMetadataItem,
record: cachedRecord,
}),

View File

@ -1,6 +1,6 @@
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { updateRecordFromCache } from '@/object-record/cache/utils/updateRecordFromCache';
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
import { computeDepthOneRecordGqlFieldsFromRecord } from '@/object-record/graphql/utils/computeDepthOneRecordGqlFieldsFromRecord';
import { FieldActorForInputValue } from '@/object-record/record-field/types/FieldMetadata';
import { computeOptimisticRecordFromInput } from '@/object-record/utils/computeOptimisticRecordFromInput';
import { InMemoryCache } from '@apollo/client';
@ -123,7 +123,7 @@ describe('computeOptimisticRecordFromInput', () => {
(field) => field.name === 'id',
),
};
const recordGqlFields = generateDepthOneRecordGqlFields({
const recordGqlFields = computeDepthOneRecordGqlFieldsFromRecord({
objectMetadataItem,
record: companyRecord,
});
@ -168,7 +168,7 @@ describe('computeOptimisticRecordFromInput', () => {
(field) => field.name === 'id',
),
};
const recordGqlFields = generateDepthOneRecordGqlFields({
const recordGqlFields = computeDepthOneRecordGqlFieldsFromRecord({
objectMetadataItem,
record: companyRecord,
});