@graphql-box/cache-manager 5.1.0 → 5.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/cjs/index.cjs +1 -1
  2. package/dist/cjs/index.cjs.map +1 -1
  3. package/dist/esm/index.mjs +1 -1
  4. package/dist/esm/index.mjs.map +1 -1
  5. package/dist/production.analysis.txt +98 -127
  6. package/dist/types/cjs/debug/logCacheEntry.d.cts +1 -1
  7. package/dist/types/cjs/debug/logCacheEntry.d.cts.map +1 -1
  8. package/dist/types/cjs/debug/logCacheQuery.d.cts +1 -1
  9. package/dist/types/cjs/debug/logCacheQuery.d.cts.map +1 -1
  10. package/dist/types/cjs/debug/logPartialCompiled.d.cts +1 -1
  11. package/dist/types/cjs/debug/logPartialCompiled.d.cts.map +1 -1
  12. package/dist/types/cjs/helpers/areOnlyPopulatedFieldsTypeIdKeys.d.cts +1 -1
  13. package/dist/types/cjs/helpers/areOnlyPopulatedFieldsTypeIdKeys.d.cts.map +1 -1
  14. package/dist/types/cjs/helpers/filterOutPropsWithArgsOrDirectives.d.cts +6 -0
  15. package/dist/types/cjs/helpers/filterOutPropsWithArgsOrDirectives.d.cts.map +1 -0
  16. package/dist/types/cjs/helpers/validTypeIdValue.d.cts +1 -1
  17. package/dist/types/cjs/helpers/validTypeIdValue.d.cts.map +1 -1
  18. package/dist/types/cjs/main.d.cts +5 -3
  19. package/dist/types/cjs/main.d.cts.map +1 -1
  20. package/dist/types/cjs/types.d.cts +5 -5
  21. package/dist/types/cjs/types.d.cts.map +1 -1
  22. package/dist/types/esm/debug/logCacheEntry.d.ts +1 -1
  23. package/dist/types/esm/debug/logCacheEntry.d.ts.map +1 -1
  24. package/dist/types/esm/debug/logCacheQuery.d.ts +1 -1
  25. package/dist/types/esm/debug/logCacheQuery.d.ts.map +1 -1
  26. package/dist/types/esm/debug/logPartialCompiled.d.ts +1 -1
  27. package/dist/types/esm/debug/logPartialCompiled.d.ts.map +1 -1
  28. package/dist/types/esm/helpers/areOnlyPopulatedFieldsTypeIdKeys.d.ts +1 -1
  29. package/dist/types/esm/helpers/areOnlyPopulatedFieldsTypeIdKeys.d.ts.map +1 -1
  30. package/dist/types/esm/helpers/filterOutPropsWithArgsOrDirectives.d.ts +6 -0
  31. package/dist/types/esm/helpers/filterOutPropsWithArgsOrDirectives.d.ts.map +1 -0
  32. package/dist/types/esm/helpers/validTypeIdValue.d.ts +1 -1
  33. package/dist/types/esm/helpers/validTypeIdValue.d.ts.map +1 -1
  34. package/dist/types/esm/main.d.ts +5 -3
  35. package/dist/types/esm/main.d.ts.map +1 -1
  36. package/dist/types/esm/types.d.ts +5 -5
  37. package/dist/types/esm/types.d.ts.map +1 -1
  38. package/dist/types/tsconfig.build.tsbuildinfo +1 -1
  39. package/package.json +5 -5
  40. package/src/__snapshots__/index.test.ts.snap +18519 -18519
  41. package/src/debug/logCacheEntry.ts +1 -1
  42. package/src/debug/logCacheQuery.ts +1 -1
  43. package/src/debug/logPartialCompiled.ts +1 -1
  44. package/src/helpers/areOnlyPopulatedFieldsTypeIdKeys.ts +1 -1
  45. package/src/helpers/filterOutPropsWithArgsOrDirectives.ts +29 -0
  46. package/src/helpers/validTypeIdValue.ts +3 -3
  47. package/src/index.test.ts +137 -153
  48. package/src/main.ts +180 -122
  49. package/src/types.ts +5 -5
  50. package/dist/types/cjs/helpers/createEntityDataKey.d.cts +0 -4
  51. package/dist/types/cjs/helpers/createEntityDataKey.d.cts.map +0 -1
  52. package/dist/types/cjs/helpers/filterOutPropsWithEntityArgsOrDirectives.d.cts +0 -5
  53. package/dist/types/cjs/helpers/filterOutPropsWithEntityArgsOrDirectives.d.cts.map +0 -1
  54. package/dist/types/cjs/helpers/filterOutPropsWithEntityOrArgs.d.cts +0 -6
  55. package/dist/types/cjs/helpers/filterOutPropsWithEntityOrArgs.d.cts.map +0 -1
  56. package/dist/types/cjs/helpers/isFieldEntity.d.cts +0 -3
  57. package/dist/types/cjs/helpers/isFieldEntity.d.cts.map +0 -1
  58. package/dist/types/esm/helpers/createEntityDataKey.d.ts +0 -4
  59. package/dist/types/esm/helpers/createEntityDataKey.d.ts.map +0 -1
  60. package/dist/types/esm/helpers/filterOutPropsWithEntityArgsOrDirectives.d.ts +0 -5
  61. package/dist/types/esm/helpers/filterOutPropsWithEntityArgsOrDirectives.d.ts.map +0 -1
  62. package/dist/types/esm/helpers/filterOutPropsWithEntityOrArgs.d.ts +0 -6
  63. package/dist/types/esm/helpers/filterOutPropsWithEntityOrArgs.d.ts.map +0 -1
  64. package/dist/types/esm/helpers/isFieldEntity.d.ts +0 -3
  65. package/dist/types/esm/helpers/isFieldEntity.d.ts.map +0 -1
  66. package/src/helpers/createEntityDataKey.ts +0 -11
  67. package/src/helpers/filterOutPropsWithEntityArgsOrDirectives.ts +0 -45
  68. package/src/helpers/filterOutPropsWithEntityOrArgs.ts +0 -31
  69. package/src/helpers/isFieldEntity.ts +0 -24
package/src/main.ts CHANGED
@@ -36,19 +36,16 @@ import {
36
36
  } from '@graphql-box/helpers';
37
37
  import { Cacheability } from 'cacheability';
38
38
  import { type FieldNode, Kind, OperationTypeNode, print } from 'graphql';
39
- import { assign, get, isEqual, isNumber, isUndefined, set, unset } from 'lodash-es';
39
+ import { assign, cloneDeep, get, isEqual, isNumber, isUndefined, set, unset } from 'lodash-es';
40
40
  import { CACHE_CONTROL, HEADER_NO_CACHE, METADATA, NO_CACHE } from './constants.ts';
41
41
  import { logCacheEntry, logCacheQuery, logPartialCompiled } from './debug/index.ts';
42
42
  import { areOnlyPopulatedFieldsTypeIdKeys } from './helpers/areOnlyPopulatedFieldsTypeIdKeys.ts';
43
43
  import { combineDataSets } from './helpers/combineData.ts';
44
- import { createEntityDataKey } from './helpers/createEntityDataKey.ts';
45
44
  import { deriveOpCacheability } from './helpers/deriveOpCacheability.ts';
46
- import { filterOutPropsWithEntityArgsOrDirectives } from './helpers/filterOutPropsWithEntityArgsOrDirectives.ts';
47
- import { filterOutPropsWithEntityOrArgs } from './helpers/filterOutPropsWithEntityOrArgs.ts';
45
+ import { filterOutPropsWithArgsOrDirectives } from './helpers/filterOutPropsWithArgsOrDirectives.ts';
48
46
  import { filterQuery } from './helpers/filterQuery.ts';
49
47
  import { getDataValue } from './helpers/getDataValue.ts';
50
48
  import { hasTypename } from './helpers/hasTypename.ts';
51
- import { isFieldEntity } from './helpers/isFieldEntity.ts';
52
49
  import { isLastResponseChunk } from './helpers/isLastResponseChunk.ts';
53
50
  import { isNotLastResponseChunk } from './helpers/isNotLastResponseChunk.ts';
54
51
  import { isNotResponseChunk } from './helpers/isNotResponseChunk.ts';
@@ -91,7 +88,7 @@ export class CacheManager implements CacheManagerDef {
91
88
 
92
89
  private static _getFieldDataFromAncestor<T>(ancestorFieldData: unknown, propNameOrIndex: string | number) {
93
90
  const dataValue = getDataValue<T>(ancestorFieldData, propNameOrIndex);
94
- return isObjectLike(dataValue) ? structuredClone(dataValue) : dataValue;
91
+ return isObjectLike(dataValue) ? cloneDeep(dataValue) : dataValue;
95
92
  }
96
93
 
97
94
  private static _getOperationCacheControl(cacheMetadata: CacheMetadata | undefined, operation: string): string {
@@ -279,12 +276,18 @@ export class CacheManager implements CacheManagerDef {
279
276
  }
280
277
 
281
278
  if (!fieldCount.missing) {
282
- this._setQueryResponseCacheEntry(hash, { cacheMetadata, data }, options, cacheManagerContext);
279
+ const dataCaching = this._setQueryResponseCacheEntry(hash, { cacheMetadata, data }, options, cacheManagerContext);
280
+
281
+ if (options.awaitDataCaching) {
282
+ await dataCaching;
283
+ }
284
+
283
285
  return { response: { cacheMetadata, data } };
284
286
  }
285
287
 
286
288
  const filteredAST = filterQuery(requestData, cachedResponseData, cacheManagerContext);
287
289
  const filteredRequest = print(filteredAST);
290
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
288
291
  const { fragmentDefinitions, typeIDKey, ...rest } = cacheManagerContext;
289
292
  assign(context, { ...rest, filteredRequest });
290
293
  this._setPartialQueryResponse(hash, { cacheMetadata, data }, options, context);
@@ -298,13 +301,13 @@ export class CacheManager implements CacheManagerDef {
298
301
  return this._cache;
299
302
  }
300
303
 
301
- public cacheQuery(
304
+ public async cacheQuery(
302
305
  requestData: RequestData,
303
306
  updatedRequestData: RequestData | undefined,
304
307
  rawResponseData: RawResponseDataWithMaybeCacheMetadata,
305
308
  options: RequestOptions,
306
309
  context: RequestContext
307
- ): ResponseData {
310
+ ): Promise<ResponseData> {
308
311
  const cacheManagerContext: CacheManagerContext = {
309
312
  ...context,
310
313
  fragmentDefinitions: getFragmentDefinitions((updatedRequestData ?? requestData).ast),
@@ -314,12 +317,12 @@ export class CacheManager implements CacheManagerDef {
314
317
  return this._cacheResponse(requestData, updatedRequestData, rawResponseData, options, cacheManagerContext);
315
318
  }
316
319
 
317
- public cacheResponse(
320
+ public async cacheResponse(
318
321
  requestData: RequestData,
319
322
  rawResponseData: RawResponseDataWithMaybeCacheMetadata,
320
323
  options: RequestOptions,
321
324
  context: RequestContext
322
- ): ResponseData {
325
+ ): Promise<ResponseData> {
323
326
  const cacheManagerContext: CacheManagerContext = {
324
327
  ...context,
325
328
  fragmentDefinitions: getFragmentDefinitions(requestData.ast),
@@ -361,13 +364,13 @@ export class CacheManager implements CacheManagerDef {
361
364
  this._partialQueryResponses.delete(hash);
362
365
  }
363
366
 
364
- public setQueryResponseCacheEntry(
367
+ public async setQueryResponseCacheEntry(
365
368
  requestData: RequestData,
366
369
  responseData: ResponseData,
367
370
  options: RequestOptions,
368
371
  context: CacheManagerContext
369
- ): void {
370
- this._setQueryResponseCacheEntry(requestData.hash, responseData, options, context);
372
+ ): Promise<void> {
373
+ return this._setQueryResponseCacheEntry(requestData.hash, responseData, options, context);
371
374
  }
372
375
 
373
376
  private async _analyzeFieldNode(
@@ -448,7 +451,7 @@ export class CacheManager implements CacheManagerDef {
448
451
  ): Promise<void> {
449
452
  const keysAndPaths = buildFieldKeysAndPaths(fieldNode, cachedAncestorFieldData, context);
450
453
  const { propNameOrIndex, requestFieldCacheKey, requestFieldPath } = keysAndPaths;
451
- const fieldTypeInfo = context.fieldTypeMap.get(requestFieldPath);
454
+ const fieldTypeInfo = context.fieldTypeMap.get(requestFieldPath)!;
452
455
 
453
456
  const { cacheability, data, entityData, requestFieldPathData } = await this._retrieveCachedParentNodeData(
454
457
  cachedAncestorFieldData,
@@ -551,13 +554,13 @@ export class CacheManager implements CacheManagerDef {
551
554
  return cacheMetadata;
552
555
  }
553
556
 
554
- private _cacheResponse(
557
+ private async _cacheResponse(
555
558
  requestData: RequestData,
556
559
  updatedRequestData: RequestData | undefined,
557
560
  rawResponseData: RawResponseDataWithMaybeCacheMetadata,
558
561
  options: RequestOptions,
559
562
  context: CacheManagerContext
560
- ): ResponseData {
563
+ ): Promise<ResponseData> {
561
564
  const normalizedResponseData = normalizePatchResponseData(rawResponseData, context);
562
565
  let responseDataForCaching: RawResponseDataWithMaybeCacheMetadata | undefined = normalizedResponseData;
563
566
 
@@ -570,22 +573,24 @@ export class CacheManager implements CacheManagerDef {
570
573
  responseDataForCaching = this._retrieveResponseDataForCaching(normalizedResponseData, context);
571
574
  }
572
575
 
576
+ const dataCaching: Promise<void>[] = [];
577
+
573
578
  if (responseDataForCaching) {
574
579
  const { data } = responseDataForCaching;
575
580
  const cacheMetadata = this._buildCacheMetadata(requestData, responseDataForCaching, options, context);
576
581
 
577
- void new Promise(() => {
582
+ dataCaching.push(
578
583
  this._setEntityAndRequestFieldPathCacheEntries(
579
584
  requestData,
580
585
  {
581
586
  cacheMetadata,
582
- entityData: structuredClone(data),
583
- requestFieldPathData: structuredClone(data),
587
+ entityData: cloneDeep(data),
588
+ requestFieldPathData: cloneDeep(data),
584
589
  },
585
590
  options,
586
591
  context
587
- );
588
- });
592
+ )
593
+ );
589
594
 
590
595
  let queryCacheMetadata: CacheMetadata | undefined;
591
596
  let queryData: PlainData | undefined;
@@ -594,21 +599,30 @@ export class CacheManager implements CacheManagerDef {
594
599
  let partialQueryResponse: PartialQueryResponse | undefined;
595
600
 
596
601
  if (context.queryFiltered && updatedRequestData) {
597
- this._setQueryResponseCacheEntry(updatedRequestData.hash, { cacheMetadata, data }, options, context);
602
+ dataCaching.push(
603
+ this._setQueryResponseCacheEntry(updatedRequestData.hash, { cacheMetadata, data }, options, context)
604
+ );
605
+
598
606
  partialQueryResponse = this._getPartialQueryResponse(requestData.hash);
599
607
  }
600
608
 
601
609
  queryCacheMetadata = CacheManager._mergeResponseCacheMetadata(cacheMetadata, partialQueryResponse);
602
610
  queryData = this._mergeResponseData(data, partialQueryResponse);
603
611
 
604
- this._setQueryResponseCacheEntry(
605
- requestData.hash,
606
- { cacheMetadata: queryCacheMetadata, data: queryData },
607
- options,
608
- context
612
+ dataCaching.push(
613
+ this._setQueryResponseCacheEntry(
614
+ requestData.hash,
615
+ { cacheMetadata: queryCacheMetadata, data: queryData },
616
+ options,
617
+ context
618
+ )
609
619
  );
610
620
  }
611
621
 
622
+ if (options.awaitDataCaching) {
623
+ await Promise.all(dataCaching);
624
+ }
625
+
612
626
  if (isNotResponseChunk(normalizedResponseData, context) && queryCacheMetadata && queryData) {
613
627
  return {
614
628
  cacheMetadata: queryCacheMetadata,
@@ -697,6 +711,22 @@ export class CacheManager implements CacheManagerDef {
697
711
  }
698
712
  }
699
713
 
714
+ private _isFieldEntity(fieldData: unknown, { isEntity, possibleTypes }: FieldTypeInfo): boolean {
715
+ if (!isPlainObject(fieldData) || !(this._typeIDKey in fieldData)) {
716
+ return false;
717
+ }
718
+
719
+ if (isEntity) {
720
+ return true;
721
+ }
722
+
723
+ if (possibleTypes.length === 0) {
724
+ return false;
725
+ }
726
+
727
+ return possibleTypes.some(type => type.typeName === fieldData.__typename);
728
+ }
729
+
700
730
  private _mergeResponseData(responseData: PlainData, partialQueryResponse?: PartialQueryResponse): PlainData {
701
731
  if (!partialQueryResponse) {
702
732
  return responseData;
@@ -705,24 +735,25 @@ export class CacheManager implements CacheManagerDef {
705
735
  return mergeDataSets(partialQueryResponse.data, responseData, this._typeIDKey);
706
736
  }
707
737
 
708
- private _parseEntityAndRequestFieldPathCacheEntryData(
738
+ private async _parseEntityAndRequestFieldPathCacheEntryData(
709
739
  field: FieldNode,
710
740
  ancestorKeysAndPaths: AncestorKeysAndPaths,
711
741
  { cacheMetadata, entityData, requestFieldPathData }: ResponseDataForCaching,
712
742
  options: RequestOptions,
713
743
  context: CacheManagerContext
714
- ): void {
744
+ ): Promise<void> {
715
745
  const keysAndPaths = buildFieldKeysAndPaths(field, ancestorKeysAndPaths, context);
716
- const { hashedRequestFieldCacheKey, requestFieldCacheKey, requestFieldPath, responseDataPath } = keysAndPaths;
746
+ const { requestFieldCacheKey, requestFieldPath, responseDataPath } = keysAndPaths;
717
747
  const fieldData = get(requestFieldPathData, responseDataPath) as unknown;
718
748
  const fieldTypeInfo = context.fieldTypeMap.get(requestFieldPath);
719
- const cacheability = cacheMetadata.get(requestFieldPath);
720
749
 
721
750
  if (!isObjectLike(fieldData) && !fieldTypeInfo?.hasDirectives) {
722
751
  return;
723
752
  }
724
753
 
725
754
  if (isObjectLike(fieldData)) {
755
+ const promises: Promise<void>[] = [];
756
+
726
757
  iterateChildFields(
727
758
  field,
728
759
  fieldData,
@@ -734,81 +765,41 @@ export class CacheManager implements CacheManagerDef {
734
765
  _fragmentName: string | undefined,
735
766
  childIndex?: number
736
767
  ) => {
737
- this._parseEntityAndRequestFieldPathCacheEntryData(
738
- childField,
739
- { index: childIndex, requestFieldCacheKey, requestFieldPath, responseDataPath },
740
- { cacheMetadata, entityData, requestFieldPathData },
741
- options,
742
- context
768
+ promises.push(
769
+ this._parseEntityAndRequestFieldPathCacheEntryData(
770
+ childField,
771
+ { index: childIndex, requestFieldCacheKey, requestFieldPath, responseDataPath },
772
+ { cacheMetadata, entityData, requestFieldPathData },
773
+ options,
774
+ context
775
+ )
743
776
  );
744
777
  }
745
778
  );
746
- }
747
-
748
- if (isUndefined(fieldData) || !fieldTypeInfo || !cacheability) {
749
- return;
750
- }
751
-
752
- const isEntity = isFieldEntity(fieldData, fieldTypeInfo, this._typeIDKey);
753
- const hasArgsOrDirectives = !!fieldTypeInfo.hasArguments || !!fieldTypeInfo.hasDirectives;
754
779
 
755
- if (context.operation === OperationTypeNode.QUERY && (isEntity || hasArgsOrDirectives)) {
756
- void this._setRequestFieldPathCacheEntry(
757
- keysAndPaths,
758
- {
759
- cacheability,
760
- fieldData: filterOutPropsWithEntityArgsOrDirectives(structuredClone(fieldData), field, keysAndPaths, context),
761
- fieldTypeInfo,
762
- },
763
- options,
764
- context
765
- );
766
-
767
- if (hasChildFields(field, { fragmentDefinitions: context.fragmentDefinitions })) {
768
- if (isEntity) {
769
- set(requestFieldPathData, responseDataPath, {
770
- __cacheKey: `${REQUEST_FIELD_PATHS}::${hashedRequestFieldCacheKey}`,
771
- });
772
- } else {
773
- unset(requestFieldPathData, responseDataPath);
774
- }
775
- }
780
+ await Promise.all(promises);
776
781
  }
777
782
 
778
- if (isEntity) {
779
- void this._setEntityCacheEntry(
780
- {
781
- cacheability,
782
- fieldData: filterOutPropsWithEntityOrArgs(
783
- structuredClone(get(entityData, responseDataPath)) as EntityData,
784
- field,
785
- keysAndPaths,
786
- context
787
- ),
788
- fieldTypeInfo,
789
- },
790
- options,
791
- context
792
- );
793
-
794
- set(entityData, responseDataPath, {
795
- __cacheKey: `${DATA_ENTITIES}::${createEntityDataKey(fieldData, fieldTypeInfo, context)}`,
796
- });
797
- }
783
+ await this._setEntityAndRequestFieldPathCacheEntry(
784
+ field,
785
+ keysAndPaths,
786
+ { cacheMetadata, entityData, requestFieldPathData },
787
+ options,
788
+ context
789
+ );
798
790
  }
799
791
 
800
792
  private async _retrieveCachedEntityData(
801
793
  validTypeIDValue: string | number,
802
- fieldTypeInfo: FieldTypeInfo | undefined,
794
+ { possibleTypes, typeName }: FieldTypeInfo,
803
795
  options: RequestOptions,
804
796
  context: CacheManagerContext
805
797
  ): Promise<Partial<CheckCacheEntryResult<EntityData>>> {
806
- const { possibleTypes = [], typeName } = fieldTypeInfo ?? {};
807
798
  const typeNames = [...possibleTypes.map(type => type.typeName), typeName];
808
799
 
809
800
  const checkResults = await Promise.all(
810
801
  typeNames.map(name =>
811
- this._checkCacheEntry<EntityData>(DATA_ENTITIES, `${String(name)}::${validTypeIDValue}`, options, context)
802
+ this._checkCacheEntry<EntityData>(DATA_ENTITIES, `${name}::${validTypeIDValue}`, options, context)
812
803
  )
813
804
  );
814
805
 
@@ -835,7 +826,7 @@ export class CacheManager implements CacheManagerDef {
835
826
  private async _retrieveCachedParentNodeData(
836
827
  { entityData: ancestorEntityData, requestFieldPathData: ancestorRequestFieldPathData }: CachedAncestorFieldData,
837
828
  { hashedRequestFieldCacheKey, propNameOrIndex, requestFieldCacheKey }: KeysAndPaths,
838
- fieldTypeInfo: FieldTypeInfo | undefined,
829
+ fieldTypeInfo: FieldTypeInfo,
839
830
  options: RequestOptions,
840
831
  context: CacheManagerContext
841
832
  ) {
@@ -952,18 +943,18 @@ export class CacheManager implements CacheManagerDef {
952
943
  _context: CacheManagerContext & { requestFieldCacheKey?: string }
953
944
  ): Promise<void> {
954
945
  try {
955
- await this._cache.set(`${cacheType}::${hash}`, value, cachemapOptions);
946
+ await this._cache.set(`${cacheType}::${hash}`, cloneDeep(value), cachemapOptions);
956
947
  } catch {
957
948
  // no catch
958
949
  }
959
950
  }
960
951
 
961
- private _setEntityAndRequestFieldPathCacheEntries(
952
+ private async _setEntityAndRequestFieldPathCacheEntries(
962
953
  requestData: RequestData,
963
954
  responseData: ResponseDataForCaching,
964
955
  options: RequestOptions,
965
956
  context: CacheManagerContext
966
- ): void {
957
+ ): Promise<void> {
967
958
  const operationNode = getOperationDefinitions(requestData.ast, context.operation)[0];
968
959
 
969
960
  if (!operationNode) {
@@ -976,22 +967,69 @@ export class CacheManager implements CacheManagerDef {
976
967
  return;
977
968
  }
978
969
 
979
- fieldsAndTypeNames.map(({ fieldNode }) => {
980
- this._parseEntityAndRequestFieldPathCacheEntryData(
981
- fieldNode,
982
- { requestFieldPath: context.operation },
983
- responseData,
970
+ await Promise.all(
971
+ fieldsAndTypeNames.map(({ fieldNode }) => {
972
+ return this._parseEntityAndRequestFieldPathCacheEntryData(
973
+ fieldNode,
974
+ { requestFieldPath: context.operation },
975
+ responseData,
976
+ options,
977
+ context
978
+ );
979
+ })
980
+ );
981
+ }
982
+
983
+ private async _setEntityAndRequestFieldPathCacheEntry(
984
+ field: FieldNode,
985
+ keysAndPaths: KeysAndPaths,
986
+ { cacheMetadata, entityData, requestFieldPathData }: ResponseDataForCaching,
987
+ options: RequestOptions,
988
+ context: CacheManagerContext
989
+ ) {
990
+ const { requestFieldPath, responseDataPath } = keysAndPaths;
991
+ const fieldData = get(entityData, responseDataPath) as unknown;
992
+ const fieldTypeInfo = context.fieldTypeMap.get(requestFieldPath);
993
+ const cacheability = cacheMetadata.get(requestFieldPath);
994
+
995
+ if (isUndefined(fieldData) || !fieldTypeInfo || !cacheability) {
996
+ return;
997
+ }
998
+
999
+ const promises: Promise<void>[] = [];
1000
+
1001
+ promises.push(
1002
+ this._setRequestFieldPathCacheEntry(
1003
+ field,
1004
+ keysAndPaths,
1005
+ { cacheability, data: requestFieldPathData, fieldTypeInfo },
984
1006
  options,
985
1007
  context
1008
+ )
1009
+ );
1010
+
1011
+ const isEntity = this._isFieldEntity(fieldData, fieldTypeInfo);
1012
+
1013
+ if (!isEntity && fieldTypeInfo.hasArguments) {
1014
+ unset(entityData, responseDataPath);
1015
+ }
1016
+
1017
+ if (isEntity) {
1018
+ promises.push(
1019
+ this._setEntityCacheEntry(keysAndPaths, { cacheability, data: entityData, fieldTypeInfo }, options, context)
986
1020
  );
987
- });
1021
+ }
1022
+
1023
+ await Promise.all(promises);
988
1024
  }
989
1025
 
990
1026
  private async _setEntityCacheEntry(
991
- { cacheability, fieldData, fieldTypeInfo }: DataForCachingEntry<EntityData>,
1027
+ { responseDataPath }: KeysAndPaths,
1028
+ { cacheability, data, fieldTypeInfo }: DataForCachingEntry,
992
1029
  options: RequestOptions,
993
1030
  context: CacheManagerContext
994
1031
  ) {
1032
+ let fieldData = get(data, responseDataPath) as EntityData;
995
1033
  const fieldTypeName = fieldTypeInfo.isEntity ? fieldTypeInfo.typeName : fieldData.__typename;
996
1034
  const entityDataKey = `${fieldTypeName}::${String(fieldData[this._typeIDKey])}`;
997
1035
  const result = await this._checkCacheEntry<EntityData>(DATA_ENTITIES, entityDataKey, options, context);
@@ -1000,7 +1038,7 @@ export class CacheManager implements CacheManagerDef {
1000
1038
  fieldData = mergeDataSets(result.entry, fieldData, this._typeIDKey);
1001
1039
  }
1002
1040
 
1003
- void this._setCacheEntry(
1041
+ await this._setCacheEntry(
1004
1042
  DATA_ENTITIES,
1005
1043
  entityDataKey,
1006
1044
  fieldData,
@@ -1008,6 +1046,8 @@ export class CacheManager implements CacheManagerDef {
1008
1046
  options,
1009
1047
  context
1010
1048
  );
1049
+
1050
+ set(data, responseDataPath, { __cacheKey: `${DATA_ENTITIES}::${entityDataKey}` });
1011
1051
  }
1012
1052
 
1013
1053
  private _setFieldCacheability(
@@ -1092,16 +1132,16 @@ export class CacheManager implements CacheManagerDef {
1092
1132
  this._partialQueryResponses.set(hash, partialQueryResponse);
1093
1133
  }
1094
1134
 
1095
- private _setQueryResponseCacheEntry(
1135
+ private async _setQueryResponseCacheEntry(
1096
1136
  hash: string,
1097
1137
  { cacheMetadata, data }: ResponseData,
1098
1138
  options: RequestOptions,
1099
1139
  context: CacheManagerContext
1100
- ): void {
1140
+ ): Promise<void> {
1101
1141
  const dehydratedCacheMetadata = dehydrateCacheMetadata(cacheMetadata);
1102
1142
  const cacheControl = CacheManager._getOperationCacheControl(cacheMetadata, context.operation);
1103
1143
 
1104
- void this._setCacheEntry(
1144
+ await this._setCacheEntry(
1105
1145
  QUERY_RESPONSES,
1106
1146
  hash,
1107
1147
  { cacheMetadata: dehydratedCacheMetadata, data },
@@ -1112,30 +1152,48 @@ export class CacheManager implements CacheManagerDef {
1112
1152
  }
1113
1153
 
1114
1154
  private async _setRequestFieldPathCacheEntry(
1155
+ field: FieldNode,
1115
1156
  keysAndPaths: KeysAndPaths,
1116
- { cacheability, fieldData }: DataForCachingEntry,
1157
+ { cacheability, data, fieldTypeInfo }: DataForCachingEntry,
1117
1158
  options: RequestOptions,
1118
1159
  context: CacheManagerContext
1119
1160
  ): Promise<void> {
1120
- const { hashedRequestFieldCacheKey, requestFieldCacheKey } = keysAndPaths;
1161
+ const { hashedRequestFieldCacheKey, requestFieldCacheKey, responseDataPath } = keysAndPaths;
1162
+ let fieldData = get(data, responseDataPath) as unknown;
1163
+ const isEntity = this._isFieldEntity(fieldData, fieldTypeInfo);
1164
+ const hasArgsOrDirectives = fieldTypeInfo.hasArguments || fieldTypeInfo.hasDirectives;
1121
1165
 
1122
- const result = await this._checkCacheEntry(REQUEST_FIELD_PATHS, hashedRequestFieldCacheKey, options, {
1123
- ...context,
1124
- requestFieldCacheKey,
1125
- });
1166
+ if (context.operation === OperationTypeNode.QUERY && (isEntity || hasArgsOrDirectives)) {
1167
+ if (isPlainObject(fieldData) && field.selectionSet?.selections) {
1168
+ fieldData = filterOutPropsWithArgsOrDirectives(fieldData, field.selectionSet.selections, keysAndPaths, context);
1169
+ }
1126
1170
 
1127
- if (result && isObjectLike(result.entry) && isObjectLike(fieldData)) {
1128
- fieldData = mergeDataSets(result.entry, fieldData, this._typeIDKey);
1129
- }
1171
+ const result = await this._checkCacheEntry(REQUEST_FIELD_PATHS, hashedRequestFieldCacheKey, options, {
1172
+ ...context,
1173
+ requestFieldCacheKey,
1174
+ });
1130
1175
 
1131
- void this._setCacheEntry(
1132
- REQUEST_FIELD_PATHS,
1133
- hashedRequestFieldCacheKey,
1134
- fieldData,
1135
- { cacheHeaders: { cacheControl: cacheability.printCacheControl() }, tag: options.tag },
1136
- options,
1137
- { ...context, requestFieldCacheKey }
1138
- );
1176
+ if (result && isObjectLike(result.entry) && isObjectLike(fieldData)) {
1177
+ fieldData = mergeDataSets(result.entry, fieldData, this._typeIDKey);
1178
+ }
1179
+
1180
+ await this._setCacheEntry(
1181
+ REQUEST_FIELD_PATHS,
1182
+ hashedRequestFieldCacheKey,
1183
+ fieldData,
1184
+ { cacheHeaders: { cacheControl: cacheability.printCacheControl() }, tag: options.tag },
1185
+ options,
1186
+ { ...context, requestFieldCacheKey }
1187
+ );
1188
+
1189
+ if (hasChildFields(field, { fragmentDefinitions: context.fragmentDefinitions })) {
1190
+ if (isEntity) {
1191
+ set(data, responseDataPath, { __cacheKey: `${REQUEST_FIELD_PATHS}::${hashedRequestFieldCacheKey}` });
1192
+ } else {
1193
+ unset(data, responseDataPath);
1194
+ }
1195
+ }
1196
+ }
1139
1197
  }
1140
1198
 
1141
1199
  private _setResponseChunksAwaitingCaching(
package/src/types.ts CHANGED
@@ -122,9 +122,9 @@ export interface ResponseDataForCaching {
122
122
  requestFieldPathData: PlainData;
123
123
  }
124
124
 
125
- export interface DataForCachingEntry<Data = unknown> {
125
+ export interface DataForCachingEntry {
126
126
  cacheability: Cacheability;
127
- fieldData: Data;
127
+ data: PlainData;
128
128
  fieldTypeInfo: FieldTypeInfo;
129
129
  }
130
130
 
@@ -157,13 +157,13 @@ export interface CacheManagerDef {
157
157
  responseData: RawResponseDataWithMaybeCacheMetadata,
158
158
  options: RequestOptions,
159
159
  context: RequestContext
160
- ): ResponseData;
160
+ ): Promise<ResponseData>;
161
161
  cacheResponse(
162
162
  requestData: RequestData,
163
163
  responseData: RawResponseDataWithMaybeCacheMetadata,
164
164
  options: RequestOptions,
165
165
  context: RequestContext
166
- ): ResponseData;
166
+ ): Promise<ResponseData>;
167
167
  checkCacheEntry(
168
168
  cacheType: CacheTypes,
169
169
  hash: string,
@@ -181,5 +181,5 @@ export interface CacheManagerDef {
181
181
  responseData: ResponseData,
182
182
  options: RequestOptions,
183
183
  context: CacheManagerContext
184
- ): void;
184
+ ): Promise<void>;
185
185
  }
@@ -1,4 +0,0 @@
1
- import type { EntityData, FieldTypeInfo } from '@graphql-box/core';
2
- import type { CacheManagerContext } from '../types.cts';
3
- export declare const createEntityDataKey: (fieldData: EntityData, fieldTypeInfo: FieldTypeInfo, context: CacheManagerContext) => string;
4
- //# sourceMappingURL=createEntityDataKey.d.cts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createEntityDataKey.d.cts","sourceRoot":"","sources":["../../../../src/helpers/createEntityDataKey.cts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvD,eAAO,MAAM,mBAAmB,cACnB,UAAU,iBACN,aAAa,WACnB,mBAAmB,WAI7B,CAAC"}
@@ -1,5 +0,0 @@
1
- import { type KeysAndPaths } from '@graphql-box/helpers';
2
- import { type FieldNode } from 'graphql';
3
- import { type CacheManagerContext } from '../types.cts';
4
- export declare const filterOutPropsWithEntityArgsOrDirectives: (fieldData: unknown, field: FieldNode, ancestorKeysAndPaths: KeysAndPaths, context: CacheManagerContext) => unknown;
5
- //# sourceMappingURL=filterOutPropsWithEntityArgsOrDirectives.d.cts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"filterOutPropsWithEntityArgsOrDirectives.d.cts","sourceRoot":"","sources":["../../../../src/helpers/filterOutPropsWithEntityArgsOrDirectives.cts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,YAAY,EAKlB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGvD,eAAO,MAAM,wCAAwC,cACxC,OAAO,SACX,SAAS,wBACM,YAAY,WACzB,mBAAmB,YA2B7B,CAAC"}
@@ -1,6 +0,0 @@
1
- import { type EntityData } from '@graphql-box/core';
2
- import { type KeysAndPaths } from '@graphql-box/helpers';
3
- import { type FieldNode } from 'graphql';
4
- import { type CacheManagerContext } from '../types.cts';
5
- export declare const filterOutPropsWithEntityOrArgs: (fieldData: EntityData, field: FieldNode, ancestorKeysAndPaths: KeysAndPaths, context: CacheManagerContext) => EntityData;
6
- //# sourceMappingURL=filterOutPropsWithEntityOrArgs.d.cts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"filterOutPropsWithEntityOrArgs.d.cts","sourceRoot":"","sources":["../../../../src/helpers/filterOutPropsWithEntityOrArgs.cts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,KAAK,YAAY,EAAqD,MAAM,sBAAsB,CAAC;AAC5G,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGvD,eAAO,MAAM,8BAA8B,cAC9B,UAAU,SACd,SAAS,wBACM,YAAY,WACzB,mBAAmB,eAmB7B,CAAC"}
@@ -1,3 +0,0 @@
1
- import type { EntityData, FieldTypeInfo } from '@graphql-box/core';
2
- export declare const isFieldEntity: (fieldData: unknown, fieldTypeInfo: FieldTypeInfo | undefined, typeIDKey: string) => fieldData is EntityData;
3
- //# sourceMappingURL=isFieldEntity.d.cts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"isFieldEntity.d.cts","sourceRoot":"","sources":["../../../../src/helpers/isFieldEntity.cts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGnE,eAAO,MAAM,aAAa,cACb,OAAO,iBACH,aAAa,GAAG,SAAS,aAC7B,MAAM,4BAiBlB,CAAC"}
@@ -1,4 +0,0 @@
1
- import type { EntityData, FieldTypeInfo } from '@graphql-box/core';
2
- import type { CacheManagerContext } from '../types.ts';
3
- export declare const createEntityDataKey: (fieldData: EntityData, fieldTypeInfo: FieldTypeInfo, context: CacheManagerContext) => string;
4
- //# sourceMappingURL=createEntityDataKey.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createEntityDataKey.d.ts","sourceRoot":"","sources":["../../../../src/helpers/createEntityDataKey.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvD,eAAO,MAAM,mBAAmB,cACnB,UAAU,iBACN,aAAa,WACnB,mBAAmB,WAI7B,CAAC"}
@@ -1,5 +0,0 @@
1
- import { type KeysAndPaths } from '@graphql-box/helpers';
2
- import { type FieldNode } from 'graphql';
3
- import { type CacheManagerContext } from '../types.ts';
4
- export declare const filterOutPropsWithEntityArgsOrDirectives: (fieldData: unknown, field: FieldNode, ancestorKeysAndPaths: KeysAndPaths, context: CacheManagerContext) => unknown;
5
- //# sourceMappingURL=filterOutPropsWithEntityArgsOrDirectives.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"filterOutPropsWithEntityArgsOrDirectives.d.ts","sourceRoot":"","sources":["../../../../src/helpers/filterOutPropsWithEntityArgsOrDirectives.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,YAAY,EAKlB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGvD,eAAO,MAAM,wCAAwC,cACxC,OAAO,SACX,SAAS,wBACM,YAAY,WACzB,mBAAmB,YA2B7B,CAAC"}
@@ -1,6 +0,0 @@
1
- import { type EntityData } from '@graphql-box/core';
2
- import { type KeysAndPaths } from '@graphql-box/helpers';
3
- import { type FieldNode } from 'graphql';
4
- import { type CacheManagerContext } from '../types.ts';
5
- export declare const filterOutPropsWithEntityOrArgs: (fieldData: EntityData, field: FieldNode, ancestorKeysAndPaths: KeysAndPaths, context: CacheManagerContext) => EntityData;
6
- //# sourceMappingURL=filterOutPropsWithEntityOrArgs.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"filterOutPropsWithEntityOrArgs.d.ts","sourceRoot":"","sources":["../../../../src/helpers/filterOutPropsWithEntityOrArgs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,KAAK,YAAY,EAAqD,MAAM,sBAAsB,CAAC;AAC5G,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGvD,eAAO,MAAM,8BAA8B,cAC9B,UAAU,SACd,SAAS,wBACM,YAAY,WACzB,mBAAmB,eAmB7B,CAAC"}
@@ -1,3 +0,0 @@
1
- import type { EntityData, FieldTypeInfo } from '@graphql-box/core';
2
- export declare const isFieldEntity: (fieldData: unknown, fieldTypeInfo: FieldTypeInfo | undefined, typeIDKey: string) => fieldData is EntityData;
3
- //# sourceMappingURL=isFieldEntity.d.ts.map