Activity cache injection (#3791)
* WIP * Minor fixes * Added TODO * Fix post merge * Fix * Fixed warnings * Fixed comments * Fixed comments * Fixed naming * Removed comment * WIP * WIP 2 * Finished working version * Fixes * Fixed typing * Fixes * Fixes * Fixes * Naming fixes * WIP * Fix import * WIP * Working version on title * Fixed create record id overwrite * Removed unecessary callback * Masterpiece * Fixed delete on click outside drawer or delete * Cleaned * Cleaned * Cleaned * Minor fixes * Fixes * Fixed naming * WIP * Fix * Fixed create from target inline cell * Removed console.log * Fixed delete activity optimistic effect * Fixed no title * Fixed debounce and title body creation --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -0,0 +1 @@
|
||||
export const MAX_QUERY_DEPTH_FOR_CACHE_INJECTION = 1;
|
||||
@ -4,7 +4,8 @@ import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMapFieldMetadataToGraphQLQuery';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { useGenerateFindOneRecordQuery } from '@/object-record/hooks/useGenerateFindOneRecordQuery';
|
||||
import { MAX_QUERY_DEPTH_FOR_CACHE_INJECTION } from '@/object-record/cache/constants/MaxQueryDepthForCacheInjection';
|
||||
import { useInjectIntoFindOneRecordQueryCache } from '@/object-record/cache/hooks/useInjectIntoFindOneRecordQueryCache';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { capitalize } from '~/utils/string/capitalize';
|
||||
@ -17,47 +18,44 @@ export const useAddRecordInCache = ({
|
||||
const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery();
|
||||
const apolloClient = useApolloClient();
|
||||
|
||||
const generateFindOneRecordQuery = useGenerateFindOneRecordQuery();
|
||||
|
||||
const findOneRecordQuery = generateFindOneRecordQuery({
|
||||
objectMetadataItem,
|
||||
});
|
||||
const { injectIntoFindOneRecordQueryCache } =
|
||||
useInjectIntoFindOneRecordQueryCache({
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
return useRecoilCallback(
|
||||
({ set }) =>
|
||||
(record: ObjectRecord) => {
|
||||
const fragment = gql`
|
||||
fragment Create${capitalize(
|
||||
objectMetadataItem.nameSingular,
|
||||
)}InCache on ${capitalize(objectMetadataItem.nameSingular)} {
|
||||
__typename
|
||||
id
|
||||
${objectMetadataItem.fields
|
||||
.map((field) =>
|
||||
mapFieldMetadataToGraphQLQuery({
|
||||
field,
|
||||
maxDepthForRelations: MAX_QUERY_DEPTH_FOR_CACHE_INJECTION,
|
||||
}),
|
||||
)
|
||||
.join('\n')}
|
||||
}
|
||||
`;
|
||||
|
||||
const cachedObjectRecord = {
|
||||
__typename: `${capitalize(objectMetadataItem.nameSingular)}`,
|
||||
...record,
|
||||
};
|
||||
|
||||
apolloClient.writeFragment({
|
||||
id: `${capitalize(objectMetadataItem.nameSingular)}:${record.id}`,
|
||||
fragment: gql`
|
||||
fragment Create${capitalize(
|
||||
objectMetadataItem.nameSingular,
|
||||
)}InCache on ${capitalize(objectMetadataItem.nameSingular)} {
|
||||
__typename
|
||||
id
|
||||
${objectMetadataItem.fields
|
||||
.map((field) => mapFieldMetadataToGraphQLQuery(field))
|
||||
.join('\n')}
|
||||
}
|
||||
`,
|
||||
data: {
|
||||
__typename: `${capitalize(objectMetadataItem.nameSingular)}`,
|
||||
...record,
|
||||
},
|
||||
fragment,
|
||||
data: cachedObjectRecord,
|
||||
});
|
||||
|
||||
// TODO: Turn into injectIntoFindOneRecordQueryCache
|
||||
apolloClient.writeQuery({
|
||||
query: findOneRecordQuery,
|
||||
variables: {
|
||||
objectRecordId: record.id,
|
||||
},
|
||||
data: {
|
||||
[objectMetadataItem.nameSingular]: {
|
||||
__typename: `${capitalize(objectMetadataItem.nameSingular)}`,
|
||||
...record,
|
||||
},
|
||||
},
|
||||
});
|
||||
// TODO: should we keep this here ? Or should the caller of createOneRecordInCache/createManyRecordsInCache be responsible for this ?
|
||||
injectIntoFindOneRecordQueryCache(cachedObjectRecord);
|
||||
|
||||
// TODO: remove this once we get rid of entityFieldsFamilyState
|
||||
set(recordStoreFamilyState(record.id), record);
|
||||
@ -66,7 +64,7 @@ export const useAddRecordInCache = ({
|
||||
objectMetadataItem,
|
||||
apolloClient,
|
||||
mapFieldMetadataToGraphQLQuery,
|
||||
findOneRecordQuery,
|
||||
injectIntoFindOneRecordQueryCache,
|
||||
],
|
||||
);
|
||||
};
|
||||
|
||||
@ -0,0 +1,50 @@
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { useReadFindManyRecordsQueryInCache } from '@/object-record/cache/hooks/useReadFindManyRecordsQueryInCache';
|
||||
import { useUpsertFindManyRecordsQueryInCache } from '@/object-record/cache/hooks/useUpsertFindManyRecordsQueryInCache';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables';
|
||||
|
||||
export const useAppendToFindManyRecordsQueryInCache = ({
|
||||
objectMetadataItem,
|
||||
}: {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
}) => {
|
||||
const { readFindManyRecordsQueryInCache } =
|
||||
useReadFindManyRecordsQueryInCache({
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
const {
|
||||
upsertFindManyRecordsQueryInCache: overwriteFindManyRecordsQueryInCache,
|
||||
} = useUpsertFindManyRecordsQueryInCache({
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
const appendToFindManyRecordsQueryInCache = <
|
||||
T extends ObjectRecord = ObjectRecord,
|
||||
>({
|
||||
queryVariables,
|
||||
objectRecordsToAppend,
|
||||
}: {
|
||||
queryVariables: ObjectRecordQueryVariables;
|
||||
objectRecordsToAppend: T[];
|
||||
}) => {
|
||||
const existingObjectRecords = readFindManyRecordsQueryInCache({
|
||||
queryVariables,
|
||||
});
|
||||
|
||||
const newObjectRecordList = [
|
||||
...existingObjectRecords,
|
||||
...objectRecordsToAppend,
|
||||
];
|
||||
|
||||
overwriteFindManyRecordsQueryInCache({
|
||||
objectRecordsToOverwrite: newObjectRecordList,
|
||||
queryVariables,
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
appendToFindManyRecordsQueryInCache,
|
||||
};
|
||||
};
|
||||
@ -27,7 +27,7 @@ export const useGetRecordFromCache = ({
|
||||
fragment ${capitalizedObjectName}Fragment on ${capitalizedObjectName} {
|
||||
id
|
||||
${objectMetadataItem.fields
|
||||
.map((field) => mapFieldMetadataToGraphQLQuery(field))
|
||||
.map((field) => mapFieldMetadataToGraphQLQuery({ field }))
|
||||
.join('\n')}
|
||||
}
|
||||
`;
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { useGenerateFindOneRecordQuery } from '@/object-record/hooks/useGenerateFindOneRecordQuery';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { capitalize } from '~/utils/string/capitalize';
|
||||
|
||||
export const useInjectIntoFindOneRecordQueryCache = ({
|
||||
objectMetadataItem,
|
||||
}: {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
}) => {
|
||||
const apolloClient = useApolloClient();
|
||||
|
||||
const generateFindOneRecordQuery = useGenerateFindOneRecordQuery();
|
||||
|
||||
const injectIntoFindOneRecordQueryCache = <
|
||||
T extends ObjectRecord = ObjectRecord,
|
||||
>(
|
||||
record: T,
|
||||
) => {
|
||||
const findOneRecordQueryForCacheInjection = generateFindOneRecordQuery({
|
||||
objectMetadataItem,
|
||||
depth: 1,
|
||||
});
|
||||
|
||||
apolloClient.writeQuery({
|
||||
query: findOneRecordQueryForCacheInjection,
|
||||
variables: {
|
||||
objectRecordId: record.id,
|
||||
},
|
||||
data: {
|
||||
[objectMetadataItem.nameSingular]: {
|
||||
__typename: `${capitalize(objectMetadataItem.nameSingular)}`,
|
||||
...record,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
injectIntoFindOneRecordQueryCache,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,53 @@
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection';
|
||||
import { useGenerateFindManyRecordsQuery } from '@/object-record/hooks/useGenerateFindManyRecordsQuery';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { ObjectRecordQueryResult } from '@/object-record/types/ObjectRecordQueryResult';
|
||||
import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useReadFindManyRecordsQueryInCache = ({
|
||||
objectMetadataItem,
|
||||
}: {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
}) => {
|
||||
const apolloClient = useApolloClient();
|
||||
|
||||
const generateFindManyRecordsQuery = useGenerateFindManyRecordsQuery();
|
||||
|
||||
const readFindManyRecordsQueryInCache = <
|
||||
T extends ObjectRecord = ObjectRecord,
|
||||
>({
|
||||
queryVariables,
|
||||
}: {
|
||||
queryVariables: ObjectRecordQueryVariables;
|
||||
}) => {
|
||||
const findManyRecordsQueryForCacheRead = generateFindManyRecordsQuery({
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
const existingRecordsQueryResult = apolloClient.readQuery<
|
||||
ObjectRecordQueryResult<T>
|
||||
>({
|
||||
query: findManyRecordsQueryForCacheRead,
|
||||
variables: queryVariables,
|
||||
});
|
||||
|
||||
const existingRecordConnection =
|
||||
existingRecordsQueryResult?.[objectMetadataItem.namePlural];
|
||||
|
||||
const existingObjectRecords = isDefined(existingRecordConnection)
|
||||
? getRecordsFromRecordConnection({
|
||||
recordConnection: existingRecordConnection,
|
||||
})
|
||||
: [];
|
||||
|
||||
return existingObjectRecords;
|
||||
};
|
||||
|
||||
return {
|
||||
readFindManyRecordsQueryInCache,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,51 @@
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { MAX_QUERY_DEPTH_FOR_CACHE_INJECTION } from '@/object-record/cache/constants/MaxQueryDepthForCacheInjection';
|
||||
import { getRecordConnectionFromRecords } from '@/object-record/cache/utils/getRecordConnectionFromRecords';
|
||||
import { useGenerateFindManyRecordsQuery } from '@/object-record/hooks/useGenerateFindManyRecordsQuery';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables';
|
||||
|
||||
export const useUpsertFindManyRecordsQueryInCache = ({
|
||||
objectMetadataItem,
|
||||
}: {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
}) => {
|
||||
const apolloClient = useApolloClient();
|
||||
|
||||
const generateFindManyRecordsQuery = useGenerateFindManyRecordsQuery();
|
||||
|
||||
const upsertFindManyRecordsQueryInCache = <
|
||||
T extends ObjectRecord = ObjectRecord,
|
||||
>({
|
||||
queryVariables,
|
||||
objectRecordsToOverwrite,
|
||||
}: {
|
||||
queryVariables: ObjectRecordQueryVariables;
|
||||
objectRecordsToOverwrite: T[];
|
||||
}) => {
|
||||
const findManyRecordsQueryForCacheOverwrite = generateFindManyRecordsQuery({
|
||||
objectMetadataItem,
|
||||
depth: MAX_QUERY_DEPTH_FOR_CACHE_INJECTION,
|
||||
});
|
||||
|
||||
const newObjectRecordConnection = getRecordConnectionFromRecords({
|
||||
objectNameSingular: CoreObjectNameSingular.ActivityTarget,
|
||||
records: objectRecordsToOverwrite,
|
||||
});
|
||||
|
||||
apolloClient.writeQuery({
|
||||
query: findManyRecordsQueryForCacheOverwrite,
|
||||
variables: queryVariables,
|
||||
data: {
|
||||
[objectMetadataItem.namePlural]: newObjectRecordConnection,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
upsertFindManyRecordsQueryInCache,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user