[REFACTOR][BUG] Dynamically compute field to write in cache CREATE (#10130)
# Introduction While importing records encountering missing expected fields when writting a fragment from apollo cache ## Updates ### 1/ `createdBy` Default value When inserting in cache in create single or many we will now make optimistic behavior on the createdBy value ### 2/ `createRecordInCache` dynamically create `recordGrqlFields` When creating an entry in cache, we will now dynamically generate fields to be written in the fragment instead of expecting all of them. As by nature record could be partial ### 3/ Strictly typed `RecordGqlFields` # Conclusion closes #9927
This commit is contained in:
@ -3,8 +3,10 @@ import { v4 } from 'uuid';
|
||||
|
||||
import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect';
|
||||
import { triggerDestroyRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerDestroyRecordsOptimisticEffect';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { checkObjectMetadataItemHasFieldCreatedBy } from '@/object-metadata/utils/checkObjectMetadataItemHasFieldCreatedBy';
|
||||
import { useCreateOneRecordInCache } from '@/object-record/cache/hooks/useCreateOneRecordInCache';
|
||||
import { deleteRecordFromCache } from '@/object-record/cache/utils/deleteRecordFromCache';
|
||||
import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename';
|
||||
@ -13,10 +15,12 @@ import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types
|
||||
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
|
||||
import { useCreateManyRecordsMutation } from '@/object-record/hooks/useCreateManyRecordsMutation';
|
||||
import { useRefetchAggregateQueries } from '@/object-record/hooks/useRefetchAggregateQueries';
|
||||
import { FieldActorForInputValue } from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { computeOptimisticRecordFromInput } from '@/object-record/utils/computeOptimisticRecordFromInput';
|
||||
import { getCreateManyRecordsMutationResponseField } from '@/object-record/utils/getCreateManyRecordsMutationResponseField';
|
||||
import { sanitizeRecordInput } from '@/object-record/utils/sanitizeRecordInput';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
type PartialObjectRecordWithId = Partial<ObjectRecord> & {
|
||||
@ -44,6 +48,9 @@ export const useCreateManyRecords = <
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const objectMetadataHasCreatedByField =
|
||||
checkObjectMetadataItemHasFieldCreatedBy(objectMetadataItem);
|
||||
|
||||
const computedRecordGqlFields =
|
||||
recordGqlFields ?? generateDepthOneRecordGqlFields({ objectMetadataItem });
|
||||
|
||||
@ -56,6 +63,8 @@ export const useCreateManyRecords = <
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||
|
||||
const { objectMetadataItems } = useObjectMetadataItems();
|
||||
|
||||
const { refetchAggregateQueries } = useRefetchAggregateQueries({
|
||||
@ -77,12 +86,26 @@ export const useCreateManyRecords = <
|
||||
}),
|
||||
id: idForCreation,
|
||||
};
|
||||
const baseOptimisticRecordInputCreatedBy:
|
||||
| { createdBy: FieldActorForInputValue }
|
||||
| undefined = objectMetadataHasCreatedByField
|
||||
? {
|
||||
createdBy: {
|
||||
source: 'MANUAL',
|
||||
context: {},
|
||||
},
|
||||
}
|
||||
: undefined;
|
||||
const optimisticRecordInput = {
|
||||
...computeOptimisticRecordFromInput({
|
||||
cache: apolloClient.cache,
|
||||
objectMetadataItem,
|
||||
objectMetadataItems,
|
||||
recordInput: recordToCreate,
|
||||
currentWorkspaceMember: currentWorkspaceMember,
|
||||
recordInput: {
|
||||
...baseOptimisticRecordInputCreatedBy,
|
||||
...recordToCreate,
|
||||
},
|
||||
}),
|
||||
id: idForCreation,
|
||||
};
|
||||
|
||||
@ -4,8 +4,10 @@ import { v4 } from 'uuid';
|
||||
|
||||
import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect';
|
||||
import { triggerDestroyRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerDestroyRecordsOptimisticEffect';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { checkObjectMetadataItemHasFieldCreatedBy } from '@/object-metadata/utils/checkObjectMetadataItemHasFieldCreatedBy';
|
||||
import { useCreateOneRecordInCache } from '@/object-record/cache/hooks/useCreateOneRecordInCache';
|
||||
import { deleteRecordFromCache } from '@/object-record/cache/utils/deleteRecordFromCache';
|
||||
import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename';
|
||||
@ -14,10 +16,12 @@ import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types
|
||||
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
|
||||
import { useCreateOneRecordMutation } from '@/object-record/hooks/useCreateOneRecordMutation';
|
||||
import { useRefetchAggregateQueries } from '@/object-record/hooks/useRefetchAggregateQueries';
|
||||
import { FieldActorForInputValue } from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { computeOptimisticRecordFromInput } from '@/object-record/utils/computeOptimisticRecordFromInput';
|
||||
import { getCreateOneRecordMutationResponseField } from '@/object-record/utils/getCreateOneRecordMutationResponseField';
|
||||
import { sanitizeRecordInput } from '@/object-record/utils/sanitizeRecordInput';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
type useCreateOneRecordProps = {
|
||||
@ -42,6 +46,9 @@ export const useCreateOneRecord = <
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const objectMetadataHasCreatedByField =
|
||||
checkObjectMetadataItemHasFieldCreatedBy(objectMetadataItem);
|
||||
|
||||
const computedRecordGqlFields =
|
||||
recordGqlFields ?? generateDepthOneRecordGqlFields({ objectMetadataItem });
|
||||
|
||||
@ -50,6 +57,8 @@ export const useCreateOneRecord = <
|
||||
recordGqlFields: computedRecordGqlFields,
|
||||
});
|
||||
|
||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||
|
||||
const createOneRecordInCache = useCreateOneRecordInCache<CreatedObjectRecord>(
|
||||
{
|
||||
objectMetadataItem,
|
||||
@ -75,11 +84,26 @@ export const useCreateOneRecord = <
|
||||
id: idForCreation,
|
||||
};
|
||||
|
||||
const baseOptimisticRecordInputCreatedBy:
|
||||
| { createdBy: FieldActorForInputValue }
|
||||
| undefined = objectMetadataHasCreatedByField
|
||||
? {
|
||||
createdBy: {
|
||||
source: 'MANUAL',
|
||||
context: {},
|
||||
},
|
||||
}
|
||||
: undefined;
|
||||
const optimisticRecordInput = computeOptimisticRecordFromInput({
|
||||
cache: apolloClient.cache,
|
||||
currentWorkspaceMember: currentWorkspaceMember,
|
||||
objectMetadataItem,
|
||||
objectMetadataItems,
|
||||
recordInput: { ...recordInput, id: idForCreation },
|
||||
recordInput: {
|
||||
...baseOptimisticRecordInputCreatedBy,
|
||||
...recordInput,
|
||||
id: idForCreation,
|
||||
},
|
||||
});
|
||||
const recordCreatedInCache = createOneRecordInCache({
|
||||
...optimisticRecordInput,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
|
||||
import { triggerUpdateRecordOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerUpdateRecordOptimisticEffect';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache';
|
||||
@ -15,6 +16,7 @@ import { computeOptimisticRecordFromInput } from '@/object-record/utils/computeO
|
||||
import { getUpdateOneRecordMutationResponseField } from '@/object-record/utils/getUpdateOneRecordMutationResponseField';
|
||||
import { sanitizeRecordInput } from '@/object-record/utils/sanitizeRecordInput';
|
||||
import { isNull } from '@sniptt/guards';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { buildRecordFromKeysWithSameValue } from '~/utils/array/buildRecordFromKeysWithSameValue';
|
||||
|
||||
@ -22,7 +24,11 @@ type useUpdateOneRecordProps = {
|
||||
objectNameSingular: string;
|
||||
recordGqlFields?: Record<string, any>;
|
||||
};
|
||||
|
||||
type UpdateOneRecordArgs<UpdatedObjectRecord> = {
|
||||
idToUpdate: string;
|
||||
updateOneRecordInput: Partial<Omit<UpdatedObjectRecord, 'id'>>;
|
||||
optimisticRecord?: Partial<ObjectRecord>;
|
||||
};
|
||||
export const useUpdateOneRecord = <
|
||||
UpdatedObjectRecord extends ObjectRecord = ObjectRecord,
|
||||
>({
|
||||
@ -47,6 +53,8 @@ export const useUpdateOneRecord = <
|
||||
recordGqlFields: computedRecordGqlFields,
|
||||
});
|
||||
|
||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||
|
||||
const { objectMetadataItems } = useObjectMetadataItems();
|
||||
|
||||
const { refetchAggregateQueries } = useRefetchAggregateQueries({
|
||||
@ -57,15 +65,12 @@ export const useUpdateOneRecord = <
|
||||
idToUpdate,
|
||||
updateOneRecordInput,
|
||||
optimisticRecord,
|
||||
}: {
|
||||
idToUpdate: string;
|
||||
updateOneRecordInput: Partial<Omit<UpdatedObjectRecord, 'id'>>;
|
||||
optimisticRecord?: Partial<ObjectRecord>;
|
||||
}) => {
|
||||
}: UpdateOneRecordArgs<UpdatedObjectRecord>) => {
|
||||
const optimisticRecordInput =
|
||||
optimisticRecord ??
|
||||
computeOptimisticRecordFromInput({
|
||||
objectMetadataItem,
|
||||
currentWorkspaceMember: currentWorkspaceMember,
|
||||
recordInput: updateOneRecordInput,
|
||||
cache: apolloClient.cache,
|
||||
objectMetadataItems,
|
||||
|
||||
Reference in New Issue
Block a user