@graphql-box/cache-manager 5.3.1 → 5.3.2

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@graphql-box/cache-manager",
3
3
  "description": "The GraphQL Box cache manager module.",
4
- "version": "5.3.1",
4
+ "version": "5.3.2",
5
5
  "author": "Dylan Aubrey",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/badbatch/graphql-box",
@@ -0,0 +1,15 @@
1
+ import { type CacheTiersEnabled } from '../types.ts';
2
+
3
+ export const allCacheTiersDisabled = ({ entity, queryResponse, requestPath }: CacheTiersEnabled) =>
4
+ !entity && !queryResponse && !requestPath;
5
+
6
+ export const entityCacheTierEnabled = (tiersEnabled: CacheTiersEnabled) => !!tiersEnabled.entity;
7
+
8
+ export const entityOrRequestPathCacheTiersEnabled = ({ entity, requestPath }: CacheTiersEnabled) =>
9
+ !!(entity ?? requestPath);
10
+
11
+ export const queryResponseCacheTierEnabled = (tiersEnabled: CacheTiersEnabled) => !!tiersEnabled.queryResponse;
12
+
13
+ export const requestPathCacheTierEnabled = (tiersEnabled: CacheTiersEnabled) => !!tiersEnabled.requestPath;
14
+
15
+ export const someCacheTiersEnabled = (tiersEnabled: CacheTiersEnabled) => !allCacheTiersDisabled(tiersEnabled);
package/src/main.ts CHANGED
@@ -40,6 +40,14 @@ import { assign, get, isEqual, isNumber, isUndefined, set, unset } from 'lodash-
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
+ import {
44
+ allCacheTiersDisabled,
45
+ entityCacheTierEnabled,
46
+ entityOrRequestPathCacheTiersEnabled,
47
+ queryResponseCacheTierEnabled,
48
+ requestPathCacheTierEnabled,
49
+ someCacheTiersEnabled,
50
+ } from './helpers/cacheTiersEnabled.ts';
43
51
  import { combineDataSets } from './helpers/combineData.ts';
44
52
  import { createEntityDataKey } from './helpers/createEntityDataKey.ts';
45
53
  import { deriveOpCacheability } from './helpers/deriveOpCacheability.ts';
@@ -61,6 +69,7 @@ import {
61
69
  type AncestorKeysAndPaths,
62
70
  type CacheManagerContext,
63
71
  type CacheManagerDef,
72
+ type CacheTiersEnabled,
64
73
  type CachedAncestorFieldData,
65
74
  type CachedResponseData,
66
75
  type CheckCacheEntryResult,
@@ -159,7 +168,7 @@ export class CacheManager implements CacheManagerDef {
159
168
  }
160
169
  }
161
170
 
162
- private static _setCachedResponseData(
171
+ private static _setCachedResponseSlice(
163
172
  cachedFieldData: MergedCachedFieldData,
164
173
  { cacheMetadata, data, fieldPathChecklist }: CachedResponseData,
165
174
  { propNameOrIndex, requestFieldPath }: KeysAndPaths,
@@ -223,6 +232,7 @@ export class CacheManager implements CacheManagerDef {
223
232
  }
224
233
 
225
234
  private _cache: Core;
235
+ private _cacheTiersEnabled: CacheTiersEnabled = { entity: true, queryResponse: true, requestPath: true };
226
236
  private _cascadeCacheControl: boolean;
227
237
  private _fallbackOperationCacheability: string;
228
238
  private _partialQueryResponses: PartialQueryResponses = new Map();
@@ -247,6 +257,7 @@ export class CacheManager implements CacheManagerDef {
247
257
  }
248
258
 
249
259
  this._cache = options.cache;
260
+ this._cacheTiersEnabled = { ...this._cacheTiersEnabled, ...options.cacheTiersEnabled };
250
261
  this._cascadeCacheControl = options.cascadeCacheControl ?? false;
251
262
  this._fallbackOperationCacheability = options.fallbackOperationCacheability ?? NO_CACHE;
252
263
  this._typeCacheDirectives = options.typeCacheDirectives ?? {};
@@ -258,6 +269,13 @@ export class CacheManager implements CacheManagerDef {
258
269
  options: RequestOptions,
259
270
  context: RequestContext
260
271
  ): Promise<AnalyzeQueryResult> {
272
+ // the client has already checked the query response cache with
273
+ // `checkQueryResponseCacheEntry`, so at this point the entity and
274
+ // request path caches are the only relevant ones.
275
+ if (!entityOrRequestPathCacheTiersEnabled(this._cacheTiersEnabled)) {
276
+ return { updated: requestData };
277
+ }
278
+
261
279
  const { ast, hash } = requestData;
262
280
 
263
281
  const cacheManagerContext: CacheManagerContext = {
@@ -278,7 +296,7 @@ export class CacheManager implements CacheManagerDef {
278
296
  return { updated: requestData };
279
297
  }
280
298
 
281
- if (!fieldCount.missing) {
299
+ if (!fieldCount.missing && queryResponseCacheTierEnabled(this._cacheTiersEnabled)) {
282
300
  const dataCaching = this._setQueryResponseCacheEntry(hash, { cacheMetadata, data }, options, cacheManagerContext);
283
301
 
284
302
  if (options.awaitDataCaching) {
@@ -293,7 +311,10 @@ export class CacheManager implements CacheManagerDef {
293
311
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
294
312
  const { fragmentDefinitions, typeIDKey, ...rest } = cacheManagerContext;
295
313
  assign(context, { ...rest, filteredRequest });
296
- this._setPartialQueryResponse(hash, { cacheMetadata, data }, options, context);
314
+
315
+ if (queryResponseCacheTierEnabled(this._cacheTiersEnabled)) {
316
+ this._setPartialQueryResponse(hash, { cacheMetadata, data }, options, context);
317
+ }
297
318
 
298
319
  return {
299
320
  updated: { ast: filteredAST, hash: hashRequest(filteredRequest), request: filteredRequest },
@@ -341,6 +362,10 @@ export class CacheManager implements CacheManagerDef {
341
362
  options: RequestOptions,
342
363
  context: RequestContext & { requestFieldCacheKey?: string }
343
364
  ): Promise<CheckCacheEntryResult | false> {
365
+ if (allCacheTiersDisabled(this._cacheTiersEnabled)) {
366
+ return false;
367
+ }
368
+
344
369
  return this._checkCacheEntry(cacheType, hash, options, context);
345
370
  }
346
371
 
@@ -349,6 +374,10 @@ export class CacheManager implements CacheManagerDef {
349
374
  options: RequestOptions,
350
375
  context: RequestContext
351
376
  ): Promise<ResponseData | false> {
377
+ if (!queryResponseCacheTierEnabled(this._cacheTiersEnabled)) {
378
+ return false;
379
+ }
380
+
352
381
  const result = await this._checkCacheEntry(QUERY_RESPONSES, hash, options, context);
353
382
 
354
383
  if (!result) {
@@ -364,7 +393,9 @@ export class CacheManager implements CacheManagerDef {
364
393
  }
365
394
 
366
395
  public deletePartialQueryResponse(hash: string): void {
367
- this._partialQueryResponses.delete(hash);
396
+ if (queryResponseCacheTierEnabled(this._cacheTiersEnabled)) {
397
+ this._partialQueryResponses.delete(hash);
398
+ }
368
399
  }
369
400
 
370
401
  public async setQueryResponseCacheEntry(
@@ -373,7 +404,9 @@ export class CacheManager implements CacheManagerDef {
373
404
  options: RequestOptions,
374
405
  context: CacheManagerContext
375
406
  ): Promise<void> {
376
- return this._setQueryResponseCacheEntry(requestData.hash, responseData, options, context);
407
+ if (queryResponseCacheTierEnabled(this._cacheTiersEnabled)) {
408
+ return this._setQueryResponseCacheEntry(requestData.hash, responseData, options, context);
409
+ }
377
410
  }
378
411
 
379
412
  private async _analyzeFieldNode(
@@ -413,7 +446,20 @@ export class CacheManager implements CacheManagerDef {
413
446
  fragmentName,
414
447
  };
415
448
 
416
- if (CacheManager._isNodeRequestFieldPath(fieldTypeInfo)) {
449
+ if (!CacheManager._isNodeRequestFieldPath(fieldTypeInfo)) {
450
+ const cachedFieldData =
451
+ CacheManager._getFieldDataFromAncestor(entityData, propNameOrIndex) ??
452
+ CacheManager._getFieldDataFromAncestor(requestFieldPathData, propNameOrIndex);
453
+
454
+ CacheManager._setFieldPathChecklist(
455
+ cachedResponseData.fieldPathChecklist,
456
+ { data: cachedFieldData },
457
+ requestFieldPath,
458
+ typenamesAndKind
459
+ );
460
+
461
+ CacheManager._setCachedData(cachedResponseData.data, { data: cachedFieldData }, propNameOrIndex);
462
+ } else if (requestPathCacheTierEnabled(this._cacheTiersEnabled)) {
417
463
  const { cacheability, entry } = await this._retrieveCachedRequestFieldPathData(
418
464
  hashedRequestFieldCacheKey,
419
465
  requestFieldCacheKey,
@@ -421,7 +467,7 @@ export class CacheManager implements CacheManagerDef {
421
467
  context
422
468
  );
423
469
 
424
- CacheManager._setCachedResponseData(
470
+ CacheManager._setCachedResponseSlice(
425
471
  { cacheability, data: entry },
426
472
  cachedResponseData,
427
473
  keysAndPaths,
@@ -429,19 +475,6 @@ export class CacheManager implements CacheManagerDef {
429
475
  options,
430
476
  context
431
477
  );
432
- } else {
433
- const cachedFieldData =
434
- CacheManager._getFieldDataFromAncestor(entityData, propNameOrIndex) ??
435
- CacheManager._getFieldDataFromAncestor(requestFieldPathData, propNameOrIndex);
436
-
437
- CacheManager._setFieldPathChecklist(
438
- cachedResponseData.fieldPathChecklist,
439
- { data: cachedFieldData },
440
- requestFieldPath,
441
- typenamesAndKind
442
- );
443
-
444
- CacheManager._setCachedData(cachedResponseData.data, { data: cachedFieldData }, propNameOrIndex);
445
478
  }
446
479
  }
447
480
 
@@ -466,7 +499,7 @@ export class CacheManager implements CacheManagerDef {
466
499
 
467
500
  const { fragmentKind, fragmentName, typeName } = cachedAncestorFieldData;
468
501
 
469
- CacheManager._setCachedResponseData(
502
+ CacheManager._setCachedResponseSlice(
470
503
  { cacheability, data },
471
504
  cachedResponseData,
472
505
  keysAndPaths,
@@ -578,27 +611,29 @@ export class CacheManager implements CacheManagerDef {
578
611
 
579
612
  const dataCaching: Promise<void>[] = [];
580
613
 
581
- if (responseDataForCaching) {
614
+ if (responseDataForCaching && someCacheTiersEnabled(this._cacheTiersEnabled)) {
582
615
  const { data } = responseDataForCaching;
583
616
  const cacheMetadata = this._buildCacheMetadata(requestData, responseDataForCaching, options, context);
584
617
 
585
- dataCaching.push(
586
- this._setEntityAndRequestFieldPathCacheEntries(
587
- requestData,
588
- {
589
- cacheMetadata,
590
- entityData: structuredClone(data),
591
- requestFieldPathData: structuredClone(data),
592
- },
593
- options,
594
- context
595
- )
596
- );
618
+ if (entityOrRequestPathCacheTiersEnabled(this._cacheTiersEnabled)) {
619
+ dataCaching.push(
620
+ this._setEntityAndRequestFieldPathCacheEntries(
621
+ requestData,
622
+ {
623
+ cacheMetadata,
624
+ entityData: structuredClone(data),
625
+ requestFieldPathData: structuredClone(data),
626
+ },
627
+ options,
628
+ context
629
+ )
630
+ );
631
+ }
597
632
 
598
633
  let queryCacheMetadata: CacheMetadata | undefined;
599
634
  let queryData: PlainData | undefined;
600
635
 
601
- if (context.operation === OperationTypeNode.QUERY) {
636
+ if (context.operation === OperationTypeNode.QUERY && queryResponseCacheTierEnabled(this._cacheTiersEnabled)) {
602
637
  let partialQueryResponse: PartialQueryResponse | undefined;
603
638
 
604
639
  if (context.queryFiltered && updatedRequestData) {
@@ -775,7 +810,11 @@ export class CacheManager implements CacheManagerDef {
775
810
  const isEntity = isFieldEntity(fieldData, fieldTypeInfo, this._typeIDKey);
776
811
  const hasArgsOrDirectives = !!fieldTypeInfo.hasArguments || !!fieldTypeInfo.hasDirectives;
777
812
 
778
- if (context.operation === OperationTypeNode.QUERY && (isEntity || hasArgsOrDirectives)) {
813
+ if (
814
+ context.operation === OperationTypeNode.QUERY &&
815
+ (isEntity || hasArgsOrDirectives) &&
816
+ requestPathCacheTierEnabled(this._cacheTiersEnabled)
817
+ ) {
779
818
  await this._setRequestFieldPathCacheEntry(
780
819
  keysAndPaths,
781
820
  {
@@ -798,7 +837,7 @@ export class CacheManager implements CacheManagerDef {
798
837
  }
799
838
  }
800
839
 
801
- if (isEntity) {
840
+ if (isEntity && entityCacheTierEnabled(this._cacheTiersEnabled)) {
802
841
  await this._setEntityCacheEntry(
803
842
  {
804
843
  cacheability,
@@ -865,7 +904,7 @@ export class CacheManager implements CacheManagerDef {
865
904
  let requestFieldPathData = CacheManager._getFieldDataFromAncestor(ancestorRequestFieldPathData, propNameOrIndex);
866
905
  let cacheability: Cacheability | undefined;
867
906
 
868
- if (CacheManager._isNodeRequestFieldPath(fieldTypeInfo)) {
907
+ if (CacheManager._isNodeRequestFieldPath(fieldTypeInfo) && requestPathCacheTierEnabled(this._cacheTiersEnabled)) {
869
908
  const { cacheability: entryCacheability, entry } = await this._retrieveCachedRequestFieldPathData(
870
909
  hashedRequestFieldCacheKey,
871
910
  requestFieldCacheKey,
@@ -882,7 +921,11 @@ export class CacheManager implements CacheManagerDef {
882
921
 
883
922
  const validTypeIDValue = getValidTypeIdValue(requestFieldPathData, fieldTypeInfo, this._typeIDKey);
884
923
 
885
- if (CacheManager._isNodeEntity(fieldTypeInfo) && validTypeIDValue) {
924
+ if (
925
+ CacheManager._isNodeEntity(fieldTypeInfo) &&
926
+ validTypeIDValue &&
927
+ entityCacheTierEnabled(this._cacheTiersEnabled)
928
+ ) {
886
929
  const { cacheability: entryCacheability, entry } = await this._retrieveCachedEntityData(
887
930
  validTypeIDValue,
888
931
  fieldTypeInfo,
package/src/types.ts CHANGED
@@ -15,12 +15,23 @@ import {
15
15
  } from '@graphql-box/core';
16
16
  import { type Cacheability } from 'cacheability';
17
17
 
18
+ export type CacheTiersEnabled = {
19
+ entity?: boolean;
20
+ queryResponse?: boolean;
21
+ requestPath?: boolean;
22
+ };
23
+
18
24
  export interface UserOptions {
19
25
  /**
20
26
  * The cache to use for storing query responses, data entities,
21
27
  * and request field paths.
22
28
  */
23
29
  cache: Core;
30
+ /**
31
+ * Whether to enable/disable any/all of the three cache tiers
32
+ * the CacheManager uses. All three are enabled by default.
33
+ */
34
+ cacheTiersEnabled?: CacheTiersEnabled;
24
35
  /**
25
36
  * Whether to cascade cache control directives down to
26
37
  * child nodes if a child node does not have its down