@graphql-box/cache-manager 2.4.2 → 2.5.0

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 (58) hide show
  1. package/lib/browser/index.js +1 -1
  2. package/lib/browser/index.js.map +1 -1
  3. package/lib/browser/production.analysis.txt +62 -26
  4. package/lib/main/helpers/isFirstResponseChunk.js +11 -0
  5. package/lib/main/helpers/isFirstResponseChunk.js.map +1 -0
  6. package/lib/main/helpers/isLastResponseChunk.js +11 -0
  7. package/lib/main/helpers/isLastResponseChunk.js.map +1 -0
  8. package/lib/main/helpers/isNotLastResponseChunk.js +11 -0
  9. package/lib/main/helpers/isNotLastResponseChunk.js.map +1 -0
  10. package/lib/main/helpers/isNotResponseChunk.js +11 -0
  11. package/lib/main/helpers/isNotResponseChunk.js.map +1 -0
  12. package/lib/main/helpers/mergeResponseDataSets.js +53 -0
  13. package/lib/main/helpers/mergeResponseDataSets.js.map +1 -0
  14. package/lib/main/helpers/normalizePatchResponseData.js +10 -5
  15. package/lib/main/helpers/normalizePatchResponseData.js.map +1 -1
  16. package/lib/main/main/index.js +124 -89
  17. package/lib/main/main/index.js.map +1 -1
  18. package/lib/module/helpers/isFirstResponseChunk.js +2 -0
  19. package/lib/module/helpers/isFirstResponseChunk.js.map +1 -0
  20. package/lib/module/helpers/isLastResponseChunk.js +2 -0
  21. package/lib/module/helpers/isLastResponseChunk.js.map +1 -0
  22. package/lib/module/helpers/isNotLastResponseChunk.js +2 -0
  23. package/lib/module/helpers/isNotLastResponseChunk.js.map +1 -0
  24. package/lib/module/helpers/isNotResponseChunk.js +2 -0
  25. package/lib/module/helpers/isNotResponseChunk.js.map +1 -0
  26. package/lib/module/helpers/mergeResponseDataSets.js +41 -0
  27. package/lib/module/helpers/mergeResponseDataSets.js.map +1 -0
  28. package/lib/module/helpers/normalizePatchResponseData.js +10 -5
  29. package/lib/module/helpers/normalizePatchResponseData.js.map +1 -1
  30. package/lib/module/main/index.js +121 -89
  31. package/lib/module/main/index.js.map +1 -1
  32. package/lib/types/defs/index.d.ts +2 -2
  33. package/lib/types/defs/index.d.ts.map +1 -1
  34. package/lib/types/helpers/isFirstResponseChunk.d.ts +5 -0
  35. package/lib/types/helpers/isFirstResponseChunk.d.ts.map +1 -0
  36. package/lib/types/helpers/isLastResponseChunk.d.ts +5 -0
  37. package/lib/types/helpers/isLastResponseChunk.d.ts.map +1 -0
  38. package/lib/types/helpers/isNotLastResponseChunk.d.ts +5 -0
  39. package/lib/types/helpers/isNotLastResponseChunk.d.ts.map +1 -0
  40. package/lib/types/helpers/isNotResponseChunk.d.ts +5 -0
  41. package/lib/types/helpers/isNotResponseChunk.d.ts.map +1 -0
  42. package/lib/types/helpers/mergeResponseDataSets.d.ts +4 -0
  43. package/lib/types/helpers/mergeResponseDataSets.d.ts.map +1 -0
  44. package/lib/types/helpers/normalizePatchResponseData.d.ts +2 -8
  45. package/lib/types/helpers/normalizePatchResponseData.d.ts.map +1 -1
  46. package/lib/types/main/index.d.ts +6 -3
  47. package/lib/types/main/index.d.ts.map +1 -1
  48. package/package.json +1 -1
  49. package/src/__snapshots__/index.test.ts.snap +12481 -11881
  50. package/src/defs/index.ts +13 -13
  51. package/src/helpers/isFirstResponseChunk.ts +5 -0
  52. package/src/helpers/isLastResponseChunk.ts +5 -0
  53. package/src/helpers/isNotLastResponseChunk.ts +5 -0
  54. package/src/helpers/isNotResponseChunk.ts +5 -0
  55. package/src/helpers/mergeResponseDataSets.ts +35 -0
  56. package/src/helpers/normalizePatchResponseData.ts +8 -1
  57. package/src/index.test.ts +162 -86
  58. package/src/main/index.ts +150 -110
package/src/main/index.ts CHANGED
@@ -63,6 +63,10 @@ import { buildFieldKeysAndPaths } from "../helpers/buildKeysAndPaths";
63
63
  import deriveOpCacheability from "../helpers/deriveOpCacheability";
64
64
  import filterOutPropsWithArgsOrDirectives from "../helpers/filterOutPropsWithArgsOrDirectives";
65
65
  import filterQuery from "../helpers/filterQuery";
66
+ import isLastResponseChunk from "../helpers/isLastResponseChunk";
67
+ import isNotLastResponseChunk from "../helpers/isNotLastResponseChunk";
68
+ import isNotResponseChunk from "../helpers/isNotResponseChunk";
69
+ import mergeResponseDataSets from "../helpers/mergeResponseDataSets";
66
70
  import normalizePatchResponseData from "../helpers/normalizePatchResponseData";
67
71
  import { getValidTypeIDValue } from "../helpers/validTypeIDValue";
68
72
 
@@ -225,6 +229,7 @@ export class CacheManager implements CacheManagerDef {
225
229
  private _cascadeCacheControl: boolean;
226
230
  private _fallbackOperationCacheability: string;
227
231
  private _partialQueryResponses: PartialQueryResponses = new Map();
232
+ private _responseChunksAwaitingCaching: Map<string, RawResponseDataWithMaybeCacheMetadata[]> = new Map();
228
233
  private _typeCacheDirectives: PlainObjectStringMap;
229
234
  private _typeIDKey: string;
230
235
 
@@ -283,6 +288,37 @@ export class CacheManager implements CacheManagerDef {
283
288
  return { updated: { ast: filteredAST, hash: hashRequest(request), request } };
284
289
  }
285
290
 
291
+ public async cacheQuery(
292
+ requestData: RequestData,
293
+ updatedRequestData: RequestData,
294
+ rawResponseData: RawResponseDataWithMaybeCacheMetadata,
295
+ options: RequestOptions,
296
+ context: RequestContext,
297
+ ): Promise<ResponseData> {
298
+ const cacheManagerContext: CacheManagerContext = {
299
+ ...context,
300
+ fragmentDefinitions: getFragmentDefinitions(updatedRequestData.ast),
301
+ typeIDKey: this._typeIDKey,
302
+ };
303
+
304
+ return this._cacheResponse(requestData, updatedRequestData, rawResponseData, options, cacheManagerContext);
305
+ }
306
+
307
+ public async cacheResponse(
308
+ requestData: RequestData,
309
+ rawResponseData: RawResponseDataWithMaybeCacheMetadata,
310
+ options: RequestOptions,
311
+ context: RequestContext,
312
+ ): Promise<ResponseData> {
313
+ const cacheManagerContext: CacheManagerContext = {
314
+ ...context,
315
+ fragmentDefinitions: getFragmentDefinitions(requestData.ast),
316
+ typeIDKey: this._typeIDKey,
317
+ };
318
+
319
+ return this._cacheResponse(requestData, undefined, rawResponseData, options, cacheManagerContext);
320
+ }
321
+
286
322
  public async checkCacheEntry(
287
323
  cacheType: CacheTypes,
288
324
  hash: string,
@@ -315,83 +351,6 @@ export class CacheManager implements CacheManagerDef {
315
351
  this._partialQueryResponses.delete(hash);
316
352
  }
317
353
 
318
- public async resolveQuery(
319
- requestData: RequestData,
320
- updatedRequestData: RequestData,
321
- rawResponseData: RawResponseDataWithMaybeCacheMetadata,
322
- options: RequestOptions,
323
- context: RequestContext,
324
- ): Promise<ResponseData> {
325
- const cacheManagerContext: CacheManagerContext = {
326
- ...context,
327
- fragmentDefinitions: getFragmentDefinitions(updatedRequestData.ast),
328
- typeIDKey: this._typeIDKey,
329
- };
330
-
331
- const dataCaching: Promise<void>[] = [];
332
-
333
- const { cacheMetadata, data, hasNext, paths } = await this._resolveRequest(
334
- updatedRequestData,
335
- rawResponseData,
336
- options,
337
- cacheManagerContext,
338
- );
339
-
340
- let partialQueryResponse: PartialQueryResponse | undefined;
341
-
342
- if (cacheManagerContext.queryFiltered) {
343
- if (!(rawResponseData.hasNext || rawResponseData.paths)) {
344
- dataCaching.push(
345
- this._setQueryResponseCacheEntry(
346
- updatedRequestData.hash,
347
- { cacheMetadata, data },
348
- options,
349
- cacheManagerContext,
350
- ),
351
- );
352
- }
353
-
354
- if (!rawResponseData.paths) {
355
- partialQueryResponse = this._getPartialQueryResponse(requestData.hash);
356
- }
357
- }
358
-
359
- const responseCacheMetadata = CacheManager._mergeResponseCacheMetadata(cacheMetadata, partialQueryResponse);
360
- const responseData = this._mergeResponseData(data, partialQueryResponse);
361
-
362
- if (!(rawResponseData.hasNext || rawResponseData.paths)) {
363
- dataCaching.push(
364
- this._setQueryResponseCacheEntry(
365
- requestData.hash,
366
- { cacheMetadata: responseCacheMetadata, data: responseData },
367
- options,
368
- cacheManagerContext,
369
- ),
370
- );
371
- }
372
-
373
- if (options.awaitDataCaching) {
374
- await Promise.all(dataCaching);
375
- }
376
-
377
- return { cacheMetadata: responseCacheMetadata, data: responseData, hasNext, paths };
378
- }
379
-
380
- public async resolveRequest(
381
- requestData: RequestData,
382
- rawResponseData: RawResponseDataWithMaybeCacheMetadata,
383
- options: RequestOptions,
384
- context: RequestContext,
385
- ): Promise<ResponseData> {
386
- const cacheManagerContext: CacheManagerContext = {
387
- ...context,
388
- fragmentDefinitions: getFragmentDefinitions(requestData.ast),
389
- typeIDKey: this._typeIDKey,
390
- };
391
-
392
- return this._resolveRequest(requestData, rawResponseData, options, cacheManagerContext);
393
- }
394
-
395
354
  private async _analyzeFieldNode(
396
355
  fieldNode: FieldNode,
397
356
  cachedAncestorFieldData: CachedAncestorFieldData,
@@ -399,7 +358,7 @@ export class CacheManager implements CacheManagerDef {
399
358
  options: RequestOptions,
400
359
  context: CacheManagerContext,
401
360
  ): Promise<void> {
402
- if (hasChildFields(fieldNode)) {
361
+ if (hasChildFields(fieldNode, { fragmentDefinitions: context.fragmentDefinitions })) {
403
362
  await this._analyzeParentFieldNode(fieldNode, cachedAncestorFieldData, cachedResponseData, options, context);
404
363
  } else {
405
364
  await this._analyzeLeafFieldNode(fieldNode, cachedAncestorFieldData, cachedResponseData, options, context);
@@ -556,6 +515,93 @@ export class CacheManager implements CacheManagerDef {
556
515
  return cacheMetadata;
557
516
  }
558
517
 
518
+ private async _cacheResponse(
519
+ requestData: RequestData,
520
+ updatedRequestData: RequestData | undefined,
521
+ rawResponseData: RawResponseDataWithMaybeCacheMetadata,
522
+ options: RequestOptions,
523
+ context: CacheManagerContext,
524
+ ): Promise<ResponseData> {
525
+ const normalizedResponseData = normalizePatchResponseData(rawResponseData, context);
526
+ let responseDataForCaching: RawResponseDataWithMaybeCacheMetadata | undefined = normalizedResponseData;
527
+
528
+ if (isNotLastResponseChunk(rawResponseData, context)) {
529
+ this._setResponseChunksAwaitingCaching(normalizedResponseData, context);
530
+ responseDataForCaching = undefined;
531
+ }
532
+
533
+ if (isLastResponseChunk(rawResponseData, context)) {
534
+ responseDataForCaching = this._retrieveResponseDataForCaching(normalizedResponseData, context);
535
+ }
536
+
537
+ const dataCaching: Promise<void>[] = [];
538
+
539
+ if (responseDataForCaching) {
540
+ const { data } = responseDataForCaching;
541
+ const cacheMetadata = this._buildCacheMetadata(requestData, responseDataForCaching, options, context);
542
+
543
+ dataCaching.push(
544
+ this._setEntityAndRequestFieldPathCacheEntries(
545
+ requestData,
546
+ {
547
+ cacheMetadata,
548
+ entityData: cloneDeep(data),
549
+ requestFieldPathData: cloneDeep(data),
550
+ },
551
+ options,
552
+ context,
553
+ ),
554
+ );
555
+
556
+ let queryCacheMetadata: CacheMetadata | undefined;
557
+ let queryData: PlainObjectMap | undefined;
558
+
559
+ if (context.operation === QUERY) {
560
+ let partialQueryResponse: PartialQueryResponse | undefined;
561
+
562
+ if (context.queryFiltered && updatedRequestData) {
563
+ dataCaching.push(
564
+ this._setQueryResponseCacheEntry(updatedRequestData.hash, { cacheMetadata, data }, options, context),
565
+ );
566
+
567
+ partialQueryResponse = this._getPartialQueryResponse(requestData.hash);
568
+ }
569
+
570
+ queryCacheMetadata = CacheManager._mergeResponseCacheMetadata(cacheMetadata, partialQueryResponse);
571
+ queryData = this._mergeResponseData(data, partialQueryResponse);
572
+
573
+ dataCaching.push(
574
+ this._setQueryResponseCacheEntry(
575
+ requestData.hash,
576
+ { cacheMetadata: queryCacheMetadata, data: queryData },
577
+ options,
578
+ context,
579
+ ),
580
+ );
581
+ }
582
+
583
+ if (options.awaitDataCaching) {
584
+ await Promise.all(dataCaching);
585
+ }
586
+
587
+ if (isNotResponseChunk(normalizedResponseData, context) && queryCacheMetadata && queryData) {
588
+ return {
589
+ cacheMetadata: queryCacheMetadata,
590
+ data: queryData,
591
+ };
592
+ }
593
+ }
594
+
595
+ const { data, hasNext, paths } = normalizedResponseData;
596
+
597
+ return {
598
+ cacheMetadata: this._buildCacheMetadata(requestData, normalizedResponseData, options, context),
599
+ data,
600
+ hasNext,
601
+ paths,
602
+ };
603
+ }
604
+
559
605
  private async _checkCacheEntry(
560
606
  cacheType: CacheTypes,
561
607
  hash: string,
@@ -717,37 +763,6 @@ export class CacheManager implements CacheManagerDef {
717
763
  );
718
764
  }
719
765
 
720
- private async _resolveRequest(
721
- requestData: RequestData,
722
- rawResponseData: RawResponseDataWithMaybeCacheMetadata,
723
- options: RequestOptions,
724
- context: CacheManagerContext,
725
- ): Promise<ResponseData> {
726
- const normalizedResponseData =
727
- rawResponseData.paths && context.normalizePatchResponseData
728
- ? normalizePatchResponseData(rawResponseData)
729
- : rawResponseData;
730
-
731
- const dataCaching: Promise<void>[] = [];
732
- const cacheMetadata = this._buildCacheMetadata(requestData, normalizedResponseData, options, context);
733
- const { data, hasNext, paths } = normalizedResponseData;
734
-
735
- dataCaching.push(
736
- this._setEntityAndRequestFieldPathCacheEntries(
737
- requestData,
738
- { cacheMetadata, entityData: cloneDeep(data), requestFieldPathData: cloneDeep(data) },
739
- options,
740
- context,
741
- ),
742
- );
743
-
744
- if (options.awaitDataCaching) {
745
- await Promise.all(dataCaching);
746
- }
747
-
748
- return { cacheMetadata, data, hasNext, paths };
749
- }
750
-
751
766
  private async _retrieveCachedEntityData(
752
767
  validTypeIDValue: string | number,
753
768
  { possibleTypes, typeName }: FieldTypeInfo,
@@ -879,6 +894,18 @@ export class CacheManager implements CacheManagerDef {
879
894
  return cachedResponseData;
880
895
  }
881
896
 
897
+ private _retrieveResponseDataForCaching(
898
+ normalizedResponseData: RawResponseDataWithMaybeCacheMetadata,
899
+ context: CacheManagerContext,
900
+ ) {
901
+ const responseChunks = this._responseChunksAwaitingCaching.get(
902
+ context.boxID,
903
+ ) as RawResponseDataWithMaybeCacheMetadata[];
904
+
905
+ this._responseChunksAwaitingCaching.delete(context.boxID);
906
+ return mergeResponseDataSets([...responseChunks, normalizedResponseData]);
907
+ }
908
+
882
909
  @logCacheEntry()
883
910
  private async _setCacheEntry(
884
911
  cacheType: CacheTypes,
@@ -1119,7 +1146,7 @@ export class CacheManager implements CacheManagerDef {
1119
1146
  context,
1120
1147
  );
1121
1148
 
1122
- if (hasChildFields(field)) {
1149
+ if (hasChildFields(field, { fragmentDefinitions: context.fragmentDefinitions })) {
1123
1150
  if (isEntity) {
1124
1151
  set(data, responseDataPath, { __cacheKey: `${REQUEST_FIELD_PATHS}::${hashedRequestFieldCacheKey}` });
1125
1152
  } else {
@@ -1128,6 +1155,19 @@ export class CacheManager implements CacheManagerDef {
1128
1155
  }
1129
1156
  }
1130
1157
  }
1158
+
1159
+ private _setResponseChunksAwaitingCaching(
1160
+ normalizedResponseData: RawResponseDataWithMaybeCacheMetadata,
1161
+ context: CacheManagerContext,
1162
+ ) {
1163
+ const responseChunks = this._responseChunksAwaitingCaching.get(context.boxID);
1164
+
1165
+ if (responseChunks) {
1166
+ this._responseChunksAwaitingCaching.set(context.boxID, [...responseChunks, normalizedResponseData]);
1167
+ } else {
1168
+ this._responseChunksAwaitingCaching.set(context.boxID, [normalizedResponseData]);
1169
+ }
1170
+ }
1131
1171
  }
1132
1172
 
1133
1173
  export default function init(userOptions: UserOptions): CacheManagerInit {