@graphql-box/cache-manager 5.0.0 → 5.0.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.
@@ -1,1475 +1,2 @@
1
- import _defineProperty from '@babel/runtime/helpers/defineProperty';
2
- import _applyDecoratedDescriptor from '@babel/runtime/helpers/applyDecoratedDescriptor';
3
- import 'core-js/modules/es.array.push.js';
4
- import { CACHE_ENTRY_ADDED, CACHE_ENTRY_QUERIED, PARTIAL_QUERY_COMPILED, TYPE_NAME_KEY, DEFAULT_TYPE_ID_KEY, QUERY_RESPONSES, DATA_ENTITIES, REQUEST_FIELD_PATHS } from '@graphql-box/core';
5
- import { isPlainObject, isArray, mergeObjects, isObjectLike, resolveFragments, getName, buildFieldKeysAndPaths, deleteFragmentSpreads, getChildFields, deleteChildFields, getInlineFragments, deleteInlineFragments, hasChildFields, deleteFragmentDefinitions, getOperationDefinitions, ArgsError, GroupedError, getFragmentDefinitions, hashRequest, rehydrateCacheMetadata, iterateChildFields, dehydrateCacheMetadata } from '@graphql-box/helpers';
6
- import { Cacheability } from 'cacheability';
7
- import { Kind, print, OperationTypeNode } from 'graphql';
8
- import { isNumber, isString, isEmpty, keys, merge, set, cloneDeep, get, isUndefined, assign, isEqual, unset } from 'lodash-es';
9
-
10
- const METADATA = 'metadata';
11
- const CACHE_CONTROL = 'cacheControl';
12
- const NO_CACHE = 'noCache';
13
- const HEADER_CACHE_CONTROL = 'cache-control';
14
- const HEADER_NO_CACHE = 'no-cache';
15
-
16
- const logCacheEntry = () => {
17
- return (_target, _propertyName, descriptor) => {
18
- const method = descriptor.value;
19
- if (!method) {
20
- return;
21
- }
22
- descriptor.value = async function descriptorValue(...args) {
23
- return new Promise(resolve => {
24
- void (async () => {
25
- const {
26
- debugManager,
27
- requestFieldCacheKey,
28
- ...otherContext
29
- } = args[5];
30
- if (!debugManager) {
31
- await method.apply(this, args);
32
- resolve();
33
- return;
34
- }
35
- const startTime = debugManager.now();
36
- await method.apply(this, args);
37
- const endTime = debugManager.now();
38
- const duration = endTime - startTime;
39
- resolve();
40
- const payload = {
41
- cacheType: args[0],
42
- cachemapOptions: args[3],
43
- context: otherContext,
44
- options: args[4],
45
- requestHash: args[1],
46
- stats: {
47
- duration,
48
- endTime,
49
- startTime
50
- },
51
- value: args[2],
52
- ...(requestFieldCacheKey ? {
53
- decryptedCacheKey: requestFieldCacheKey
54
- } : {})
55
- };
56
- debugManager.log(CACHE_ENTRY_ADDED, payload);
57
- })();
58
- });
59
- };
60
- };
61
- };
62
-
63
- const logCacheQuery = () => {
64
- return (_target, _propertyName, descriptor) => {
65
- const method = descriptor.value;
66
- if (!method) {
67
- return;
68
- }
69
- descriptor.value = async function descriptorValue(...args) {
70
- return new Promise(resolve => {
71
- void (async () => {
72
- const {
73
- debugManager,
74
- requestFieldCacheKey,
75
- ...otherContext
76
- } = args[3];
77
- if (!debugManager) {
78
- resolve(await method.apply(this, args));
79
- return;
80
- }
81
- const startTime = debugManager.now();
82
- const result = await method.apply(this, args);
83
- const endTime = debugManager.now();
84
- const duration = endTime - startTime;
85
- resolve(result);
86
- const payload = {
87
- cacheType: args[0],
88
- context: otherContext,
89
- options: args[2],
90
- requestHash: args[1],
91
- result,
92
- stats: {
93
- duration,
94
- endTime,
95
- startTime
96
- },
97
- ...(requestFieldCacheKey ? {
98
- decryptedCacheKey: requestFieldCacheKey
99
- } : {})
100
- };
101
- debugManager.log(CACHE_ENTRY_QUERIED, payload);
102
- })();
103
- });
104
- };
105
- };
106
- };
107
-
108
- const logPartialCompiled = () => {
109
- return (_target, _propertyName, descriptor) => {
110
- const method = descriptor.value;
111
- if (!method) {
112
- return;
113
- }
114
- descriptor.value = function descriptorValue(...args) {
115
- const {
116
- debugManager,
117
- ...otherContext
118
- } = args[3];
119
- if (!debugManager) {
120
- method.apply(this, args);
121
- return;
122
- }
123
- const startTime = debugManager.now();
124
- method.apply(this, args);
125
- const endTime = debugManager.now();
126
- const duration = endTime - startTime;
127
- debugManager.log(PARTIAL_QUERY_COMPILED, {
128
- context: otherContext,
129
- options: args[2],
130
- requestHash: args[0],
131
- result: args[1],
132
- stats: {
133
- duration,
134
- endTime,
135
- startTime
136
- }
137
- });
138
- };
139
- };
140
- };
141
-
142
- const checkValue = (value, typeIDKey) => {
143
- if (isArray(value)) {
144
- return value.reduce((acc, entry) => {
145
- if (!acc) {
146
- return false;
147
- }
148
- return checkValue(entry, typeIDKey);
149
- }, true);
150
- }
151
- if (isPlainObject(value)) {
152
- return recursivelyCheckProps(value, typeIDKey);
153
- }
154
- return false;
155
- };
156
- const recursivelyCheckProps = (data, typeIDKey) => {
157
- const keys = isPlainObject(data) ? Object.keys(data) : [...data.keys()];
158
- if (keys.length === 1 && isPlainObject(data) && !!data[typeIDKey]) {
159
- return true;
160
- }
161
- return keys.reduce((acc, key) => {
162
- if (!acc) {
163
- return false;
164
- }
165
- if (isNumber(key) && isArray(data)) {
166
- return checkValue(data[key], typeIDKey);
167
- } else if (isString(key) && isPlainObject(data)) {
168
- return checkValue(data[key], typeIDKey);
169
- }
170
- return acc;
171
- }, true);
172
- };
173
- const areOnlyPopulatedFieldsTypeIdKeys = (data, typeIDKey) => {
174
- return recursivelyCheckProps(data, typeIDKey);
175
- };
176
-
177
- const mergeDataSets = (obj, source, typeIDKey) => {
178
- return mergeObjects(obj, source, (_key, value) => {
179
- return isPlainObject(value) && value[typeIDKey] ? value[typeIDKey] : undefined;
180
- });
181
- };
182
-
183
- const combineDataSets = (dataSetA, dataSetB, typeIDKey) => {
184
- if (!dataSetA && dataSetB) {
185
- return dataSetB;
186
- }
187
- if (isObjectLike(dataSetA) && isObjectLike(dataSetB)) {
188
- return mergeDataSets(dataSetA, dataSetB, typeIDKey);
189
- }
190
- return dataSetA;
191
- };
192
-
193
- const deriveOpCacheability = ({
194
- _cacheMetadata,
195
- fallback,
196
- headers
197
- }) => {
198
- if (_cacheMetadata && !isEmpty(_cacheMetadata)) {
199
- const [first, ...rest] = Object.values(_cacheMetadata);
200
- return new Cacheability({
201
- metadata: rest.reduce((acc, metadata) => {
202
- if (!acc) {
203
- return metadata;
204
- }
205
- if (metadata.ttl < acc.ttl) {
206
- return metadata;
207
- }
208
- return acc;
209
- }, first)
210
- });
211
- }
212
- if (headers?.has(HEADER_CACHE_CONTROL)) {
213
- return new Cacheability({
214
- headers
215
- });
216
- }
217
- return new Cacheability({
218
- cacheControl: fallback
219
- });
220
- };
221
-
222
- const filterOutPropsWithArgsOrDirectives = (fieldData, selectionNodes, ancestorKeysAndPaths, context) => {
223
- const fieldAndTypeName = resolveFragments(selectionNodes, context.fragmentDefinitions);
224
- return keys(fieldData).reduce((acc, key) => {
225
- const match = fieldAndTypeName.find(({
226
- fieldNode
227
- }) => getName(fieldNode) === key);
228
- if (match) {
229
- const {
230
- requestFieldPath
231
- } = buildFieldKeysAndPaths(match.fieldNode, ancestorKeysAndPaths, context);
232
- const fieldTypeInfo = context.fieldTypeMap.get(requestFieldPath);
233
- if (!fieldTypeInfo?.hasArguments && !fieldTypeInfo?.hasDirectives) {
234
- acc[key] = fieldData[key];
235
- }
236
- }
237
- return acc;
238
- }, {});
239
- };
240
-
241
- const createFragmentSpreadChecklist = ({
242
- request
243
- }, {
244
- fragmentDefinitions
245
- }) => keys(fragmentDefinitions ?? {}).reduce((acc, name) => {
246
- acc[name] = {
247
- deleted: 0,
248
- paths: [],
249
- total: (request.match(new RegExp(`\\.\\.\\.${name}`, 'g')) ?? []).length
250
- };
251
- return acc;
252
- }, {});
253
-
254
- const checkFieldPathChecklist = (fieldPathChecklistValues, fieldTypeName) => {
255
- if (!fieldPathChecklistValues || fieldPathChecklistValues.length === 0) {
256
- return {
257
- hasData: false,
258
- typeUnused: !!fieldTypeName
259
- };
260
- }
261
- const [fieldPathChecklistValue] = fieldPathChecklistValues;
262
- if (fieldPathChecklistValue) {
263
- const {
264
- hasData,
265
- typeName
266
- } = fieldPathChecklistValue;
267
- const typeUnused = typeName ? typeName !== fieldTypeName : undefined;
268
- return {
269
- hasData,
270
- typeUnused
271
- };
272
- }
273
- return {
274
- hasData: fieldPathChecklistValues.some(({
275
- hasData,
276
- typeName
277
- }) => typeName === fieldTypeName && hasData),
278
- typeUnused: !fieldPathChecklistValues.every(({
279
- typeName
280
- }) => typeName === fieldTypeName)
281
- };
282
- };
283
-
284
- const filterFragmentSpreads = (field, fragmentSpreadFieldCounter, fragmentSpreadChecklist, ancestorRequestFieldPath) => {
285
- if (isEmpty(fragmentSpreadFieldCounter)) {
286
- return;
287
- }
288
- for (const key of Object.keys(fragmentSpreadFieldCounter)) {
289
- const checklist = fragmentSpreadChecklist[key];
290
- if (!checklist) {
291
- continue;
292
- }
293
- checklist.paths.push(ancestorRequestFieldPath);
294
- const {
295
- hasData,
296
- total
297
- } = fragmentSpreadFieldCounter[key];
298
- if (hasData === total) {
299
- deleteFragmentSpreads(field, key);
300
- checklist.deleted += 1;
301
- }
302
- }
303
- };
304
-
305
- const filterIDsAndTypeNames = (field, {
306
- fragmentDefinitions,
307
- typeIDKey
308
- }) => {
309
- const fieldsAndTypeNames = getChildFields(field, {
310
- fragmentDefinitions
311
- });
312
- if (!fieldsAndTypeNames || fieldsAndTypeNames.length > 3) {
313
- return false;
314
- }
315
- const fieldNames = fieldsAndTypeNames.map(({
316
- fieldNode
317
- }) => getName(fieldNode));
318
- if (fieldNames.length === 2 && fieldNames.every(name => name === typeIDKey || name === TYPE_NAME_KEY)) {
319
- deleteChildFields(field, fieldsAndTypeNames.map(({
320
- fieldNode
321
- }) => fieldNode));
322
- return true;
323
- }
324
- if (fieldNames.length === 1 && fieldNames[0] === typeIDKey || fieldNames[0] === TYPE_NAME_KEY) {
325
- const [fieldAndTypeName] = fieldsAndTypeNames;
326
- if (fieldAndTypeName) {
327
- const {
328
- fieldNode
329
- } = fieldAndTypeName;
330
- deleteChildFields(field, fieldNode);
331
- return true;
332
- }
333
- }
334
- return false;
335
- };
336
-
337
- const filterInlineFragments = (field, {
338
- fragmentDefinitions,
339
- typeIDKey
340
- }) => {
341
- const inlineFragments = getInlineFragments(field);
342
- let filtered = false;
343
- for (const fragment of inlineFragments) {
344
- const fieldsAndTypeNames = getChildFields(fragment, {
345
- fragmentDefinitions
346
- });
347
- if (!fieldsAndTypeNames || fieldsAndTypeNames.length === 0) {
348
- deleteInlineFragments(field, fragment);
349
- filtered = true;
350
- continue;
351
- }
352
- const [fieldAndTypeName] = fieldsAndTypeNames;
353
- if (fieldAndTypeName) {
354
- const {
355
- fieldNode
356
- } = fieldAndTypeName;
357
- if (getName(fieldNode) === typeIDKey) {
358
- deleteInlineFragments(field, fragment);
359
- filtered = true;
360
- }
361
- }
362
- }
363
- return filtered;
364
- };
365
-
366
- const filterField = (field, fieldPathChecklist, fragmentSpreadChecklist, ancestorRequestFieldPath, context) => {
367
- const {
368
- fragmentDefinitions,
369
- typeIDKey
370
- } = context;
371
- const fieldsAndTypeNames = getChildFields(field, {
372
- fragmentDefinitions
373
- });
374
- if (!fieldsAndTypeNames) {
375
- return false;
376
- }
377
- const fragmentSpreadFieldCounter = {};
378
- for (let index = fieldsAndTypeNames.length - 1; index >= 0; index -= 1) {
379
- const fieldAndTypeName = fieldsAndTypeNames[index];
380
- if (!fieldAndTypeName) {
381
- continue;
382
- }
383
- const {
384
- fieldNode: childField,
385
- fragmentKind,
386
- fragmentName,
387
- typeName: childTypeName
388
- } = fieldAndTypeName;
389
- if (fragmentKind === Kind.FRAGMENT_SPREAD && fragmentName && !fragmentSpreadFieldCounter[fragmentName]) {
390
- fragmentSpreadFieldCounter[fragmentName] = {
391
- hasData: 0,
392
- total: fragmentDefinitions?.[fragmentName] ? getChildFields(fragmentDefinitions[fragmentName], {
393
- fragmentDefinitions
394
- })?.length ?? 0 : 0
395
- };
396
- }
397
- const childFieldName = getName(childField);
398
- if (childFieldName === typeIDKey || childFieldName === TYPE_NAME_KEY) {
399
- continue;
400
- }
401
- const {
402
- requestFieldPath
403
- } = buildFieldKeysAndPaths(childField, {
404
- requestFieldPath: ancestorRequestFieldPath
405
- }, context);
406
- const {
407
- hasData,
408
- typeUnused
409
- } = checkFieldPathChecklist(fieldPathChecklist.get(requestFieldPath), childTypeName);
410
- if (hasData || typeUnused) {
411
- if (fragmentKind === Kind.FRAGMENT_SPREAD && fragmentName) {
412
- const counter = fragmentSpreadFieldCounter[fragmentName];
413
- if (counter) {
414
- counter.hasData += 1;
415
- }
416
- } else if (!hasChildFields(childField, {
417
- fragmentDefinitions
418
- })) {
419
- deleteChildFields(field, childField);
420
- } else if (filterField(childField, fieldPathChecklist, fragmentSpreadChecklist, requestFieldPath, context)) {
421
- deleteChildFields(field, childField);
422
- }
423
- }
424
- }
425
- filterFragmentSpreads(field, fragmentSpreadFieldCounter, fragmentSpreadChecklist, ancestorRequestFieldPath);
426
- filterInlineFragments(field, context);
427
- filterIDsAndTypeNames(field, context);
428
- return !hasChildFields(field, {
429
- fragmentDefinitions
430
- });
431
- };
432
-
433
- const filterFragmentDefinitions = (ast, fieldPathChecklist, fragmentSpreadChecklist, context) => {
434
- const definitionsToFilter = keys(fragmentSpreadChecklist).reduce((namesAndPaths, key) => {
435
- const checklist = fragmentSpreadChecklist[key];
436
- if (!checklist) {
437
- return namesAndPaths;
438
- }
439
- const {
440
- deleted,
441
- paths,
442
- total
443
- } = checklist;
444
- return deleted === 0 && total === 1 ? [...namesAndPaths, {
445
- name: key,
446
- path: paths[0]
447
- }] : namesAndPaths;
448
- }, []);
449
- const {
450
- fragmentDefinitions = {}
451
- } = context;
452
- for (const {
453
- name,
454
- path
455
- } of definitionsToFilter) {
456
- const fragmentDefinition = fragmentDefinitions[name];
457
- if (!fragmentDefinition) {
458
- continue;
459
- }
460
- filterField(fragmentDefinition, fieldPathChecklist, fragmentSpreadChecklist, path, context);
461
- }
462
- const definitionsToDelete = keys(fragmentSpreadChecklist).reduce((names, key) => {
463
- const checklist = fragmentSpreadChecklist[key];
464
- if (!checklist) {
465
- return names;
466
- }
467
- const {
468
- deleted,
469
- total
470
- } = checklist;
471
- return deleted > 0 && deleted === total ? [...names, key] : names;
472
- }, []);
473
- if (definitionsToDelete.length === 0) {
474
- return ast;
475
- }
476
- return deleteFragmentDefinitions(ast, {
477
- include: definitionsToDelete
478
- });
479
- };
480
-
481
- const filterQuery = (requestData, {
482
- fieldPathChecklist
483
- }, context) => {
484
- const {
485
- ast
486
- } = requestData;
487
- const queryNode = getOperationDefinitions(ast, context.operation)[0];
488
- if (!queryNode) {
489
- return ast;
490
- }
491
- const {
492
- fragmentDefinitions,
493
- operation
494
- } = context;
495
- const fieldsAndTypeNames = getChildFields(queryNode, {
496
- fragmentDefinitions
497
- });
498
- if (!fieldsAndTypeNames) {
499
- return ast;
500
- }
501
- const fragmentSpreadChecklist = createFragmentSpreadChecklist(requestData, context);
502
- for (let index = fieldsAndTypeNames.length - 1; index >= 0; index -= 1) {
503
- const {
504
- fieldNode
505
- } = fieldsAndTypeNames[index];
506
- const {
507
- requestFieldPath
508
- } = buildFieldKeysAndPaths(fieldNode, {
509
- requestFieldPath: operation
510
- }, context);
511
- if (filterField(fieldNode, fieldPathChecklist, fragmentSpreadChecklist, requestFieldPath, context)) {
512
- deleteChildFields(queryNode, fieldNode);
513
- }
514
- }
515
- context.queryFiltered = true;
516
- return filterFragmentDefinitions(ast, fieldPathChecklist, fragmentSpreadChecklist, context);
517
- };
518
-
519
- const getDataValue = (value, key) => {
520
- if (isArray(value) && isNumber(key)) {
521
- return value[key];
522
- }
523
- if (isPlainObject(value) && isString(key)) {
524
- return value[key];
525
- }
526
- return;
527
- };
528
-
529
- const hasTypename = value => {
530
- if (!isObjectLike(value)) {
531
- return false;
532
- }
533
- return TYPE_NAME_KEY in value && isString(value[TYPE_NAME_KEY]);
534
- };
535
-
536
- const isLastResponseChunk = (rawResponseData, context) => context.hasDeferOrStream && !rawResponseData.hasNext && rawResponseData.paths;
537
-
538
- const isNotLastResponseChunk = (rawResponseData, context) => context.hasDeferOrStream && rawResponseData.hasNext;
539
-
540
- const isNotResponseChunk = (rawResponseData, context) => !context.hasDeferOrStream && !rawResponseData.hasNext && !rawResponseData.paths;
541
-
542
- const mergeResponseDataSets = responseDataSets => {
543
- return responseDataSets.reduce((acc, dataSet, index) => {
544
- const {
545
- _cacheMetadata,
546
- data,
547
- hasNext,
548
- headers,
549
- paths
550
- } = dataSet;
551
- if (_cacheMetadata) {
552
- acc._cacheMetadata = acc._cacheMetadata ? {
553
- ...acc._cacheMetadata,
554
- ..._cacheMetadata
555
- } : _cacheMetadata;
556
- }
557
- acc.data = merge(acc.data, data);
558
- if (index === 0) {
559
- acc.headers = headers;
560
- }
561
- if (index === responseDataSets.length - 1) {
562
- acc.hasNext = hasNext;
563
- }
564
- if (paths) {
565
- if (!acc.paths) {
566
- acc.paths = [];
567
- }
568
- acc.paths.push(...paths);
569
- }
570
- return acc;
571
- }, {
572
- data: {}
573
- });
574
- };
575
-
576
- const normalizePatchResponseData = (rawResponseData, context) => {
577
- if (!context.normalizePatchResponseData) {
578
- return rawResponseData;
579
- }
580
- const {
581
- data,
582
- paths,
583
- ...rest
584
- } = rawResponseData;
585
- if (!paths?.length || !isString(paths[0])) {
586
- return rawResponseData;
587
- }
588
- return {
589
- ...rest,
590
- data: set({}, paths[0], data),
591
- paths
592
- };
593
- };
594
-
595
- const getValidTypeIdValue = (requestFieldPathData, {
596
- typeIDValue
597
- }, typeIDKey) => {
598
- if (typeIDValue) {
599
- return typeIDValue;
600
- }
601
- if (isPlainObject(requestFieldPathData)) {
602
- return requestFieldPathData[typeIDKey];
603
- }
604
- return;
605
- };
606
-
607
- var _dec, _dec2, _dec3, _class;
608
- let CacheManager = (_dec = logCacheQuery(), _dec2 = logCacheEntry(), _dec3 = logPartialCompiled(), (_class = class CacheManager {
609
- static _countFieldPathChecklist(fieldPathChecklist) {
610
- const fieldCount = {
611
- missing: 0,
612
- total: 0
613
- };
614
- for (const [, checklistValues] of fieldPathChecklist) {
615
- fieldCount.total += checklistValues.length;
616
- const missing = checklistValues.filter(({
617
- hasData
618
- }) => !hasData);
619
- fieldCount.missing += missing.length;
620
- }
621
- return fieldCount;
622
- }
623
- static _getFieldDataFromAncestor(ancestorFieldData, propNameOrIndex) {
624
- const dataValue = getDataValue(ancestorFieldData, propNameOrIndex);
625
- return isObjectLike(dataValue) ? cloneDeep(dataValue) : dataValue;
626
- }
627
- static _getOperationCacheControl(cacheMetadata, operation) {
628
- const defaultCacheControl = HEADER_NO_CACHE;
629
- if (!cacheMetadata) {
630
- return defaultCacheControl;
631
- }
632
- const cacheability = cacheMetadata.get(operation);
633
- return cacheability ? cacheability.printCacheControl() : defaultCacheControl;
634
- }
635
- static _isNodeEntity(fieldTypeInfo) {
636
- if (!fieldTypeInfo) {
637
- return false;
638
- }
639
- const {
640
- isEntity,
641
- possibleTypes
642
- } = fieldTypeInfo;
643
- return isEntity || possibleTypes.some(type => !!type.isEntity);
644
- }
645
- static _isNodeRequestFieldPath(fieldTypeInfo) {
646
- return !!fieldTypeInfo && (this._isNodeEntity(fieldTypeInfo) || fieldTypeInfo.hasArguments || fieldTypeInfo.hasDirectives);
647
- }
648
- static _isValid(cacheability) {
649
- const noCache = get(cacheability, [METADATA, CACHE_CONTROL, NO_CACHE], false);
650
- return !noCache && cacheability.checkTTL();
651
- }
652
- static _mergeResponseCacheMetadata(cacheMetadata, partialQueryResponse) {
653
- if (!partialQueryResponse) {
654
- return cacheMetadata;
655
- }
656
- return new Map([...partialQueryResponse.cacheMetadata, ...cacheMetadata]);
657
- }
658
- static _setCachedData(responseData, {
659
- data
660
- }, propNameOrIndex) {
661
- const setData = value => {
662
- if (isArray(responseData) && isNumber(propNameOrIndex)) {
663
- responseData[propNameOrIndex] = value;
664
- } else if (isPlainObject(responseData)) {
665
- responseData[propNameOrIndex] = value;
666
- }
667
- };
668
- if (!isObjectLike(data) && !isUndefined(data)) {
669
- setData(data);
670
- } else if (isArray(data)) {
671
- setData([]);
672
- } else if (isPlainObject(data)) {
673
- setData({});
674
- }
675
- }
676
- static _setCachedResponseData(cachedFieldData, {
677
- cacheMetadata,
678
- data,
679
- fieldPathChecklist
680
- }, {
681
- propNameOrIndex,
682
- requestFieldPath
683
- }, typeNamesAndKind, _options, {
684
- operation
685
- }) {
686
- CacheManager._setCacheMetadata(cacheMetadata, cachedFieldData.cacheability, requestFieldPath, operation);
687
- CacheManager._setFieldPathChecklist(fieldPathChecklist, cachedFieldData, requestFieldPath, typeNamesAndKind);
688
- CacheManager._setCachedData(data, cachedFieldData, propNameOrIndex);
689
- }
690
- static _setCacheMetadata(cacheMetadata, cacheability, requestFieldPath, operation) {
691
- if (!cacheability) {
692
- return;
693
- }
694
- cacheMetadata.set(requestFieldPath, cacheability);
695
- const operationCacheability = cacheMetadata.get(operation);
696
- if (!operationCacheability || operationCacheability.metadata.ttl > cacheability.metadata.ttl) {
697
- cacheMetadata.set(operation, cacheability);
698
- }
699
- }
700
- static _setFieldPathChecklist(fieldPathChecklist, {
701
- data
702
- }, requestFieldPath, {
703
- dataTypename: dataTypeName,
704
- fieldTypename: fieldTypeName,
705
- fragmentKind,
706
- fragmentName
707
- }) {
708
- if (isUndefined(fieldTypeName) || fragmentKind === Kind.FRAGMENT_SPREAD) {
709
- if (fieldPathChecklist.has(requestFieldPath)) {
710
- return;
711
- }
712
- fieldPathChecklist.set(requestFieldPath, [{
713
- fragmentKind,
714
- fragmentName,
715
- hasData: !isUndefined(data)
716
- }]);
717
- return;
718
- }
719
- if (dataTypeName !== fieldTypeName) {
720
- return;
721
- }
722
- const entry = fieldPathChecklist.get(requestFieldPath);
723
- const checklistValues = entry ?? [];
724
- if (checklistValues.some(({
725
- typeName
726
- }) => typeName === dataTypeName)) {
727
- return;
728
- }
729
- fieldPathChecklist.set(requestFieldPath, [...checklistValues, {
730
- fragmentKind,
731
- fragmentName,
732
- hasData: !isUndefined(data),
733
- typeName: dataTypeName
734
- }]);
735
- }
736
- constructor(options) {
737
- _defineProperty(this, "_cache", void 0);
738
- _defineProperty(this, "_cascadeCacheControl", void 0);
739
- _defineProperty(this, "_fallbackOperationCacheability", void 0);
740
- _defineProperty(this, "_partialQueryResponses", new Map());
741
- _defineProperty(this, "_responseChunksAwaitingCaching", new Map());
742
- _defineProperty(this, "_typeCacheDirectives", void 0);
743
- _defineProperty(this, "_typeIDKey", void 0);
744
- const errors = [];
745
- if (!('cache' in options)) {
746
- errors.push(new ArgsError('@graphql-box/cache-manager expected cache to be in options.'));
747
- }
748
- if (!!options.typeCacheDirectives && !isPlainObject(options.typeCacheDirectives)) {
749
- const message = '@graphql-box/cache-manager expected options.typeCacheDirectives to be a plain object.';
750
- errors.push(new ArgsError(message));
751
- }
752
- if (errors.length > 0) {
753
- throw new GroupedError('@graphql-box/cache-manager argument validation errors.', errors);
754
- }
755
- this._cache = options.cache;
756
- this._cascadeCacheControl = options.cascadeCacheControl ?? false;
757
- this._fallbackOperationCacheability = options.fallbackOperationCacheability ?? NO_CACHE;
758
- this._typeCacheDirectives = options.typeCacheDirectives ?? {};
759
- this._typeIDKey = options.typeIDKey ?? DEFAULT_TYPE_ID_KEY;
760
- }
761
- async analyzeQuery(requestData, options, context) {
762
- const {
763
- ast,
764
- hash
765
- } = requestData;
766
- const cacheManagerContext = {
767
- ...context,
768
- fragmentDefinitions: getFragmentDefinitions(ast),
769
- typeIDKey: this._typeIDKey
770
- };
771
- const cachedResponseData = await this._retrieveCachedResponseData(requestData, options, cacheManagerContext);
772
- const {
773
- cacheMetadata,
774
- data,
775
- fieldCount
776
- } = cachedResponseData;
777
- if (fieldCount.missing === fieldCount.total || areOnlyPopulatedFieldsTypeIdKeys(data, this._typeIDKey)) {
778
- return {
779
- updated: requestData
780
- };
781
- }
782
- if (!fieldCount.missing) {
783
- const dataCaching = this._setQueryResponseCacheEntry(hash, {
784
- cacheMetadata,
785
- data
786
- }, options, cacheManagerContext);
787
- if (options.awaitDataCaching) {
788
- await dataCaching;
789
- }
790
- return {
791
- response: {
792
- cacheMetadata,
793
- data
794
- }
795
- };
796
- }
797
- const filteredAST = filterQuery(requestData, cachedResponseData, cacheManagerContext);
798
- const filteredRequest = print(filteredAST);
799
- const {
800
- fragmentDefinitions,
801
- typeIDKey,
802
- ...rest
803
- } = cacheManagerContext;
804
- assign(context, {
805
- ...rest,
806
- filteredRequest
807
- });
808
- this._setPartialQueryResponse(hash, {
809
- cacheMetadata,
810
- data
811
- }, options, context);
812
- return {
813
- updated: {
814
- ast: filteredAST,
815
- hash: hashRequest(filteredRequest),
816
- request: filteredRequest
817
- }
818
- };
819
- }
820
- get cache() {
821
- return this._cache;
822
- }
823
- async cacheQuery(requestData, updatedRequestData, rawResponseData, options, context) {
824
- const cacheManagerContext = {
825
- ...context,
826
- fragmentDefinitions: getFragmentDefinitions((updatedRequestData ?? requestData).ast),
827
- typeIDKey: this._typeIDKey
828
- };
829
- return this._cacheResponse(requestData, updatedRequestData, rawResponseData, options, cacheManagerContext);
830
- }
831
- async cacheResponse(requestData, rawResponseData, options, context) {
832
- const cacheManagerContext = {
833
- ...context,
834
- fragmentDefinitions: getFragmentDefinitions(requestData.ast),
835
- typeIDKey: this._typeIDKey
836
- };
837
- return this._cacheResponse(requestData, undefined, rawResponseData, options, cacheManagerContext);
838
- }
839
- async checkCacheEntry(cacheType, hash, options, context) {
840
- return this._checkCacheEntry(cacheType, hash, options, context);
841
- }
842
- async checkQueryResponseCacheEntry(hash, options, context) {
843
- const result = await this._checkCacheEntry(QUERY_RESPONSES, hash, options, context);
844
- if (!result) {
845
- return false;
846
- }
847
- const {
848
- cacheMetadata,
849
- data
850
- } = result.entry;
851
- return {
852
- cacheMetadata: rehydrateCacheMetadata(cacheMetadata),
853
- data
854
- };
855
- }
856
- deletePartialQueryResponse(hash) {
857
- this._partialQueryResponses.delete(hash);
858
- }
859
- async setQueryResponseCacheEntry(requestData, responseData, options, context) {
860
- return this._setQueryResponseCacheEntry(requestData.hash, responseData, options, context);
861
- }
862
- async _analyzeFieldNode(fieldNode, cachedAncestorFieldData, cachedResponseData, options, context) {
863
- await (hasChildFields(fieldNode, {
864
- fragmentDefinitions: context.fragmentDefinitions
865
- }) ? this._analyzeParentFieldNode(fieldNode, cachedAncestorFieldData, cachedResponseData, options, context) : this._analyzeLeafFieldNode(fieldNode, cachedAncestorFieldData, cachedResponseData, options, context));
866
- }
867
- async _analyzeLeafFieldNode(fieldNode, cachedAncestorFieldData, cachedResponseData, options, context) {
868
- const keysAndPaths = buildFieldKeysAndPaths(fieldNode, cachedAncestorFieldData, context);
869
- const {
870
- hashedRequestFieldCacheKey,
871
- propNameOrIndex,
872
- requestFieldCacheKey,
873
- requestFieldPath
874
- } = keysAndPaths;
875
- const fieldTypeInfo = context.fieldTypeMap.get(requestFieldPath);
876
- const {
877
- entityData,
878
- fragmentKind,
879
- fragmentName,
880
- requestFieldPathData,
881
- typeName
882
- } = cachedAncestorFieldData;
883
- const dataTypename = hasTypename(entityData) ? entityData.__typename : hasTypename(requestFieldPathData) ? requestFieldPathData.__typename : undefined;
884
- const typenamesAndKind = {
885
- dataTypename,
886
- fieldTypename: typeName,
887
- fragmentKind,
888
- fragmentName
889
- };
890
- if (CacheManager._isNodeRequestFieldPath(fieldTypeInfo)) {
891
- const {
892
- cacheability,
893
- entry
894
- } = await this._retrieveCachedRequestFieldPathData(hashedRequestFieldCacheKey, requestFieldCacheKey, options, context);
895
- CacheManager._setCachedResponseData({
896
- cacheability,
897
- data: entry
898
- }, cachedResponseData, keysAndPaths, typenamesAndKind, options, context);
899
- } else {
900
- const cachedFieldData = CacheManager._getFieldDataFromAncestor(entityData, propNameOrIndex) ?? CacheManager._getFieldDataFromAncestor(requestFieldPathData, propNameOrIndex);
901
- CacheManager._setFieldPathChecklist(cachedResponseData.fieldPathChecklist, {
902
- data: cachedFieldData
903
- }, requestFieldPath, typenamesAndKind);
904
- CacheManager._setCachedData(cachedResponseData.data, {
905
- data: cachedFieldData
906
- }, propNameOrIndex);
907
- }
908
- }
909
- async _analyzeParentFieldNode(fieldNode, cachedAncestorFieldData, cachedResponseData, options, context) {
910
- const keysAndPaths = buildFieldKeysAndPaths(fieldNode, cachedAncestorFieldData, context);
911
- const {
912
- propNameOrIndex,
913
- requestFieldCacheKey,
914
- requestFieldPath
915
- } = keysAndPaths;
916
- const fieldTypeInfo = context.fieldTypeMap.get(requestFieldPath);
917
- const {
918
- cacheability,
919
- data,
920
- entityData,
921
- requestFieldPathData
922
- } = await this._retrieveCachedParentNodeData(cachedAncestorFieldData, keysAndPaths, fieldTypeInfo, options, context);
923
- const {
924
- fragmentKind,
925
- fragmentName,
926
- typeName
927
- } = cachedAncestorFieldData;
928
- CacheManager._setCachedResponseData({
929
- cacheability,
930
- data
931
- }, cachedResponseData, keysAndPaths, {
932
- dataTypename: get(data, TYPE_NAME_KEY),
933
- fieldTypename: typeName,
934
- fragmentKind,
935
- fragmentName
936
- }, options, context);
937
- if (!isObjectLike(data)) {
938
- return;
939
- }
940
- const promises = [];
941
- iterateChildFields(fieldNode, data, context.fragmentDefinitions, (childField, childTypeName, childFragmentKind, childFragmentName, childIndex) => {
942
- promises.push(this._analyzeFieldNode(childField, {
943
- cacheability,
944
- entityData,
945
- fragmentKind: childFragmentKind,
946
- fragmentName: childFragmentName,
947
- index: childIndex,
948
- requestFieldCacheKey,
949
- requestFieldPath,
950
- requestFieldPathData,
951
- typeName: childTypeName
952
- }, {
953
- ...cachedResponseData,
954
- data: getDataValue(cachedResponseData.data, propNameOrIndex)
955
- }, options, context));
956
- });
957
- await Promise.all(promises);
958
- }
959
- _buildCacheMetadata({
960
- ast
961
- }, {
962
- data,
963
- ...otherProps
964
- }, options, context) {
965
- const cacheMetadata = this._createCacheMetadata({
966
- data,
967
- ...otherProps
968
- }, context);
969
- const queryNode = getOperationDefinitions(ast, context.operation)[0];
970
- if (!queryNode) {
971
- return cacheMetadata;
972
- }
973
- const fieldsAndTypeNames = getChildFields(queryNode);
974
- if (!fieldsAndTypeNames) {
975
- return cacheMetadata;
976
- }
977
- for (const {
978
- fieldNode
979
- } of fieldsAndTypeNames) this._setFieldCacheability(fieldNode, {
980
- requestFieldPath: context.operation
981
- }, {
982
- cacheMetadata,
983
- data
984
- }, options, context);
985
- return cacheMetadata;
986
- }
987
- async _cacheResponse(requestData, updatedRequestData, rawResponseData, options, context) {
988
- const normalizedResponseData = normalizePatchResponseData(rawResponseData, context);
989
- let responseDataForCaching = normalizedResponseData;
990
- if (isNotLastResponseChunk(rawResponseData, context)) {
991
- this._setResponseChunksAwaitingCaching(normalizedResponseData, context);
992
- responseDataForCaching = undefined;
993
- }
994
- if (isLastResponseChunk(rawResponseData, context)) {
995
- responseDataForCaching = this._retrieveResponseDataForCaching(normalizedResponseData, context);
996
- }
997
- const dataCaching = [];
998
- if (responseDataForCaching) {
999
- const {
1000
- data
1001
- } = responseDataForCaching;
1002
- const cacheMetadata = this._buildCacheMetadata(requestData, responseDataForCaching, options, context);
1003
- dataCaching.push(this._setEntityAndRequestFieldPathCacheEntries(requestData, {
1004
- cacheMetadata,
1005
- entityData: cloneDeep(data),
1006
- requestFieldPathData: cloneDeep(data)
1007
- }, options, context));
1008
- let queryCacheMetadata;
1009
- let queryData;
1010
- if (context.operation === OperationTypeNode.QUERY) {
1011
- let partialQueryResponse;
1012
- if (context.queryFiltered && updatedRequestData) {
1013
- dataCaching.push(this._setQueryResponseCacheEntry(updatedRequestData.hash, {
1014
- cacheMetadata,
1015
- data
1016
- }, options, context));
1017
- partialQueryResponse = this._getPartialQueryResponse(requestData.hash);
1018
- }
1019
- queryCacheMetadata = CacheManager._mergeResponseCacheMetadata(cacheMetadata, partialQueryResponse);
1020
- queryData = this._mergeResponseData(data, partialQueryResponse);
1021
- dataCaching.push(this._setQueryResponseCacheEntry(requestData.hash, {
1022
- cacheMetadata: queryCacheMetadata,
1023
- data: queryData
1024
- }, options, context));
1025
- }
1026
- if (options.awaitDataCaching) {
1027
- await Promise.all(dataCaching);
1028
- }
1029
- if (isNotResponseChunk(normalizedResponseData, context) && queryCacheMetadata && queryData) {
1030
- return {
1031
- cacheMetadata: queryCacheMetadata,
1032
- data: queryData
1033
- };
1034
- }
1035
- }
1036
- const {
1037
- data,
1038
- hasNext,
1039
- paths
1040
- } = normalizedResponseData;
1041
- return {
1042
- cacheMetadata: this._buildCacheMetadata(requestData, normalizedResponseData, options, context),
1043
- data,
1044
- hasNext,
1045
- paths
1046
- };
1047
- }
1048
- async _checkCacheEntry(cacheType, hash, options, context) {
1049
- try {
1050
- const cacheability = await this._hasCacheEntry(cacheType, hash);
1051
- if (!cacheability || !CacheManager._isValid(cacheability)) {
1052
- return false;
1053
- }
1054
- const entry = await this._getCacheEntry(cacheType, hash, options, context);
1055
- if (isUndefined(entry)) {
1056
- return false;
1057
- }
1058
- return {
1059
- cacheability,
1060
- entry
1061
- };
1062
- } catch {
1063
- return false;
1064
- }
1065
- }
1066
- _createCacheMetadata({
1067
- _cacheMetadata,
1068
- headers
1069
- }, {
1070
- operation
1071
- }) {
1072
- const cacheMetadata = new Map();
1073
- const cacheability = deriveOpCacheability({
1074
- _cacheMetadata,
1075
- fallback: this._fallbackOperationCacheability,
1076
- headers
1077
- });
1078
- cacheMetadata.set(operation, cacheability);
1079
- if (_cacheMetadata) {
1080
- rehydrateCacheMetadata(_cacheMetadata, cacheMetadata);
1081
- }
1082
- return cacheMetadata;
1083
- }
1084
- async _getCacheEntry(cacheType, hash, _options, _context) {
1085
- return this._cache.get(`${cacheType}::${hash}`);
1086
- }
1087
- _getPartialQueryResponse(hash) {
1088
- const partialQueryResponse = this._partialQueryResponses.get(hash);
1089
- this._partialQueryResponses.delete(hash);
1090
- return partialQueryResponse;
1091
- }
1092
- async _hasCacheEntry(cacheType, hash) {
1093
- try {
1094
- return await this._cache.has(`${cacheType}::${hash}`);
1095
- } catch {
1096
- return false;
1097
- }
1098
- }
1099
- _isFieldEntity(fieldData, {
1100
- isEntity,
1101
- possibleTypes
1102
- }) {
1103
- if (!isPlainObject(fieldData) || !(this._typeIDKey in fieldData)) {
1104
- return false;
1105
- }
1106
- if (isEntity) {
1107
- return true;
1108
- }
1109
- if (possibleTypes.length === 0) {
1110
- return false;
1111
- }
1112
- return possibleTypes.some(type => type.typeName === fieldData.__typename);
1113
- }
1114
- _mergeResponseData(responseData, partialQueryResponse) {
1115
- if (!partialQueryResponse) {
1116
- return responseData;
1117
- }
1118
- return mergeDataSets(partialQueryResponse.data, responseData, this._typeIDKey);
1119
- }
1120
- async _parseEntityAndRequestFieldPathCacheEntryData(field, ancestorKeysAndPaths, {
1121
- cacheMetadata,
1122
- entityData,
1123
- requestFieldPathData
1124
- }, options, context) {
1125
- const keysAndPaths = buildFieldKeysAndPaths(field, ancestorKeysAndPaths, context);
1126
- const {
1127
- requestFieldCacheKey,
1128
- requestFieldPath,
1129
- responseDataPath
1130
- } = keysAndPaths;
1131
- const fieldData = get(requestFieldPathData, responseDataPath);
1132
- const fieldTypeInfo = context.fieldTypeMap.get(requestFieldPath);
1133
- if (!isObjectLike(fieldData) && !fieldTypeInfo?.hasDirectives) {
1134
- return;
1135
- }
1136
- if (isObjectLike(fieldData)) {
1137
- const promises = [];
1138
- iterateChildFields(field, fieldData, context.fragmentDefinitions, (childField, _typeName, _fragmentKind, _fragmentName, childIndex) => {
1139
- promises.push(this._parseEntityAndRequestFieldPathCacheEntryData(childField, {
1140
- index: childIndex,
1141
- requestFieldCacheKey,
1142
- requestFieldPath,
1143
- responseDataPath
1144
- }, {
1145
- cacheMetadata,
1146
- entityData,
1147
- requestFieldPathData
1148
- }, options, context));
1149
- });
1150
- await Promise.all(promises);
1151
- }
1152
- await this._setEntityAndRequestFieldPathCacheEntry(field, keysAndPaths, {
1153
- cacheMetadata,
1154
- entityData,
1155
- requestFieldPathData
1156
- }, options, context);
1157
- }
1158
- async _retrieveCachedEntityData(validTypeIDValue, {
1159
- possibleTypes,
1160
- typeName
1161
- }, options, context) {
1162
- const typeNames = [...possibleTypes.map(type => type.typeName), typeName];
1163
- const checkResults = await Promise.all(typeNames.map(name => this._checkCacheEntry(DATA_ENTITIES, `${name}::${validTypeIDValue}`, options, context)));
1164
- const validResults = checkResults.filter(result => !!result);
1165
- let validResult;
1166
- if (validResults.length === 1) {
1167
- validResult = validResults[0];
1168
- } else if (validResults.length > 1) {
1169
- validResults.sort(({
1170
- cacheability: a
1171
- }, {
1172
- cacheability: b
1173
- }) => a.metadata.ttl - b.metadata.ttl);
1174
- validResult = {
1175
- cacheability: validResults[0].cacheability,
1176
- entry: validResults.reduce((obj, {
1177
- entry
1178
- }) => mergeDataSets(obj, entry, this._typeIDKey), {})
1179
- };
1180
- }
1181
- return validResult ?? {};
1182
- }
1183
- async _retrieveCachedParentNodeData({
1184
- entityData: ancestorEntityData,
1185
- requestFieldPathData: ancestorRequestFieldPathData
1186
- }, {
1187
- hashedRequestFieldCacheKey,
1188
- propNameOrIndex,
1189
- requestFieldCacheKey
1190
- }, fieldTypeInfo, options, context) {
1191
- let entityData = CacheManager._getFieldDataFromAncestor(ancestorEntityData, propNameOrIndex);
1192
- let requestFieldPathData = CacheManager._getFieldDataFromAncestor(ancestorRequestFieldPathData, propNameOrIndex);
1193
- let cacheability;
1194
- if (CacheManager._isNodeRequestFieldPath(fieldTypeInfo)) {
1195
- const {
1196
- cacheability: entryCacheability,
1197
- entry
1198
- } = await this._retrieveCachedRequestFieldPathData(hashedRequestFieldCacheKey, requestFieldCacheKey, options, context);
1199
- requestFieldPathData = combineDataSets(requestFieldPathData, entry, this._typeIDKey);
1200
- if (entryCacheability) {
1201
- cacheability = entryCacheability;
1202
- }
1203
- }
1204
- const validTypeIDValue = getValidTypeIdValue(requestFieldPathData, fieldTypeInfo, this._typeIDKey);
1205
- if (CacheManager._isNodeEntity(fieldTypeInfo) && validTypeIDValue) {
1206
- const {
1207
- cacheability: entryCacheability,
1208
- entry
1209
- } = await this._retrieveCachedEntityData(validTypeIDValue, fieldTypeInfo, options, context);
1210
- entityData = combineDataSets(entityData, entry, this._typeIDKey);
1211
- if (entryCacheability && (!cacheability || entryCacheability.metadata.ttl > cacheability.metadata.ttl)) {
1212
- cacheability = entryCacheability;
1213
- }
1214
- }
1215
- const data = isEqual(entityData, requestFieldPathData) ? entityData : combineDataSets(entityData, requestFieldPathData, this._typeIDKey);
1216
- return {
1217
- cacheability,
1218
- data,
1219
- entityData,
1220
- requestFieldPathData
1221
- };
1222
- }
1223
- async _retrieveCachedRequestFieldPathData(hash, requestFieldCacheKey, options, context) {
1224
- return (await this._checkCacheEntry(REQUEST_FIELD_PATHS, hash, options, {
1225
- ...context,
1226
- requestFieldCacheKey
1227
- })) || {};
1228
- }
1229
- async _retrieveCachedResponseData({
1230
- ast
1231
- }, options, context) {
1232
- const cachedResponseData = {
1233
- cacheMetadata: new Map(),
1234
- data: {},
1235
- fieldCount: {
1236
- missing: 0,
1237
- total: 0
1238
- },
1239
- fieldPathChecklist: new Map()
1240
- };
1241
- const queryNode = getOperationDefinitions(ast, context.operation)[0];
1242
- if (!queryNode) {
1243
- return cachedResponseData;
1244
- }
1245
- const fieldsAndTypeNames = getChildFields(queryNode);
1246
- if (!fieldsAndTypeNames) {
1247
- return cachedResponseData;
1248
- }
1249
- await Promise.all(fieldsAndTypeNames.map(({
1250
- fieldNode
1251
- }) => this._analyzeFieldNode(fieldNode, {
1252
- requestFieldPath: context.operation
1253
- }, cachedResponseData, options, context)));
1254
- cachedResponseData.fieldCount = CacheManager._countFieldPathChecklist(cachedResponseData.fieldPathChecklist);
1255
- return cachedResponseData;
1256
- }
1257
- _retrieveResponseDataForCaching(normalizedResponseData, context) {
1258
- const responseChunks = this._responseChunksAwaitingCaching.get(context.requestID);
1259
- this._responseChunksAwaitingCaching.delete(context.requestID);
1260
- return mergeResponseDataSets([...responseChunks, normalizedResponseData]);
1261
- }
1262
- async _setCacheEntry(cacheType, hash, value, cachemapOptions, _options, _context) {
1263
- try {
1264
- await this._cache.set(`${cacheType}::${hash}`, cloneDeep(value), cachemapOptions);
1265
- } catch {}
1266
- }
1267
- async _setEntityAndRequestFieldPathCacheEntries(requestData, responseData, options, context) {
1268
- const operationNode = getOperationDefinitions(requestData.ast, context.operation)[0];
1269
- if (!operationNode) {
1270
- return;
1271
- }
1272
- const fieldsAndTypeNames = getChildFields(operationNode);
1273
- if (!fieldsAndTypeNames) {
1274
- return;
1275
- }
1276
- await Promise.all(fieldsAndTypeNames.map(({
1277
- fieldNode
1278
- }) => {
1279
- return this._parseEntityAndRequestFieldPathCacheEntryData(fieldNode, {
1280
- requestFieldPath: context.operation
1281
- }, responseData, options, context);
1282
- }));
1283
- }
1284
- async _setEntityAndRequestFieldPathCacheEntry(field, keysAndPaths, {
1285
- cacheMetadata,
1286
- entityData,
1287
- requestFieldPathData
1288
- }, options, context) {
1289
- const {
1290
- requestFieldPath,
1291
- responseDataPath
1292
- } = keysAndPaths;
1293
- const fieldData = get(entityData, responseDataPath);
1294
- const fieldTypeInfo = context.fieldTypeMap.get(requestFieldPath);
1295
- const cacheability = cacheMetadata.get(requestFieldPath);
1296
- if (isUndefined(fieldData) || !fieldTypeInfo || !cacheability) {
1297
- return;
1298
- }
1299
- const promises = [];
1300
- promises.push(this._setRequestFieldPathCacheEntry(field, keysAndPaths, {
1301
- cacheability,
1302
- data: requestFieldPathData,
1303
- fieldTypeInfo
1304
- }, options, context));
1305
- const isEntity = this._isFieldEntity(fieldData, fieldTypeInfo);
1306
- if (!isEntity && fieldTypeInfo.hasArguments) {
1307
- unset(entityData, responseDataPath);
1308
- }
1309
- if (isEntity) {
1310
- promises.push(this._setEntityCacheEntry(keysAndPaths, {
1311
- cacheability,
1312
- data: entityData,
1313
- fieldTypeInfo
1314
- }, options, context));
1315
- }
1316
- await Promise.all(promises);
1317
- }
1318
- async _setEntityCacheEntry({
1319
- responseDataPath
1320
- }, {
1321
- cacheability,
1322
- data,
1323
- fieldTypeInfo
1324
- }, options, context) {
1325
- let fieldData = get(data, responseDataPath);
1326
- const fieldTypeName = fieldTypeInfo.isEntity ? fieldTypeInfo.typeName : fieldData.__typename;
1327
- const entityDataKey = `${fieldTypeName}::${String(fieldData[this._typeIDKey])}`;
1328
- const result = await this._checkCacheEntry(DATA_ENTITIES, entityDataKey, options, context);
1329
- if (result) {
1330
- fieldData = mergeDataSets(result.entry, fieldData, this._typeIDKey);
1331
- }
1332
- await this._setCacheEntry(DATA_ENTITIES, entityDataKey, fieldData, {
1333
- cacheHeaders: {
1334
- cacheControl: cacheability.printCacheControl()
1335
- },
1336
- tag: options.tag
1337
- }, options, context);
1338
- set(data, responseDataPath, {
1339
- __cacheKey: `${DATA_ENTITIES}::${entityDataKey}`
1340
- });
1341
- }
1342
- _setFieldCacheability(field, ancestorKeysAndPaths, {
1343
- cacheMetadata,
1344
- data
1345
- }, options, context) {
1346
- const {
1347
- requestFieldPath: ancestorRequestFieldPath
1348
- } = ancestorKeysAndPaths;
1349
- const keysAndPaths = buildFieldKeysAndPaths(field, ancestorKeysAndPaths, context);
1350
- const {
1351
- requestFieldPath,
1352
- responseDataPath
1353
- } = keysAndPaths;
1354
- if (!isObjectLike(data)) {
1355
- return;
1356
- }
1357
- const fieldData = get(data, responseDataPath);
1358
- const fieldTypeInfo = context.fieldTypeMap.get(requestFieldPath);
1359
- if (!isObjectLike(fieldData) && !fieldTypeInfo?.hasDirectives) {
1360
- return;
1361
- }
1362
- this._setFieldTypeCacheDirective(cacheMetadata, {
1363
- ancestorRequestFieldPath,
1364
- requestFieldPath
1365
- }, context);
1366
- if (isObjectLike(fieldData)) {
1367
- iterateChildFields(field, fieldData, context.fragmentDefinitions, (childField, _typeName, _fragmentKind, _fragmentName, childIndex) => {
1368
- this._setFieldCacheability(childField, {
1369
- index: childIndex,
1370
- requestFieldPath,
1371
- responseDataPath
1372
- }, {
1373
- cacheMetadata,
1374
- data
1375
- }, options, context);
1376
- });
1377
- }
1378
- }
1379
- _setFieldTypeCacheDirective(cacheMetadata, {
1380
- ancestorRequestFieldPath,
1381
- requestFieldPath
1382
- }, {
1383
- fieldTypeMap,
1384
- operation
1385
- }) {
1386
- if (cacheMetadata.has(requestFieldPath)) {
1387
- return;
1388
- }
1389
- const fieldTypeInfo = fieldTypeMap.get(requestFieldPath);
1390
- if (fieldTypeInfo && this._typeCacheDirectives[fieldTypeInfo.typeName]) {
1391
- const cacheability = new Cacheability({
1392
- cacheControl: this._typeCacheDirectives[fieldTypeInfo.typeName]
1393
- });
1394
- CacheManager._setCacheMetadata(cacheMetadata, cacheability, requestFieldPath, operation);
1395
- } else if (this._cascadeCacheControl && ancestorRequestFieldPath) {
1396
- CacheManager._setCacheMetadata(cacheMetadata, cacheMetadata.get(ancestorRequestFieldPath), requestFieldPath, operation);
1397
- }
1398
- }
1399
- _setPartialQueryResponse(hash, partialQueryResponse, _options, _context) {
1400
- this._partialQueryResponses.set(hash, partialQueryResponse);
1401
- }
1402
- async _setQueryResponseCacheEntry(hash, {
1403
- cacheMetadata,
1404
- data
1405
- }, options, context) {
1406
- const dehydratedCacheMetadata = dehydrateCacheMetadata(cacheMetadata);
1407
- const cacheControl = CacheManager._getOperationCacheControl(cacheMetadata, context.operation);
1408
- await this._setCacheEntry(QUERY_RESPONSES, hash, {
1409
- cacheMetadata: dehydratedCacheMetadata,
1410
- data
1411
- }, {
1412
- cacheHeaders: {
1413
- cacheControl
1414
- },
1415
- tag: options.tag
1416
- }, options, context);
1417
- }
1418
- async _setRequestFieldPathCacheEntry(field, keysAndPaths, {
1419
- cacheability,
1420
- data,
1421
- fieldTypeInfo
1422
- }, options, context) {
1423
- const {
1424
- hashedRequestFieldCacheKey,
1425
- requestFieldCacheKey,
1426
- responseDataPath
1427
- } = keysAndPaths;
1428
- let fieldData = get(data, responseDataPath);
1429
- const isEntity = this._isFieldEntity(fieldData, fieldTypeInfo);
1430
- const hasArgsOrDirectives = fieldTypeInfo.hasArguments || fieldTypeInfo.hasDirectives;
1431
- if (context.operation === OperationTypeNode.QUERY && (isEntity || hasArgsOrDirectives)) {
1432
- if (isPlainObject(fieldData) && field.selectionSet?.selections) {
1433
- fieldData = filterOutPropsWithArgsOrDirectives(fieldData, field.selectionSet.selections, keysAndPaths, context);
1434
- }
1435
- const result = await this._checkCacheEntry(REQUEST_FIELD_PATHS, hashedRequestFieldCacheKey, options, {
1436
- ...context,
1437
- requestFieldCacheKey
1438
- });
1439
- if (result && isObjectLike(result.entry) && isObjectLike(fieldData)) {
1440
- fieldData = mergeDataSets(result.entry, fieldData, this._typeIDKey);
1441
- }
1442
- await this._setCacheEntry(REQUEST_FIELD_PATHS, hashedRequestFieldCacheKey, fieldData, {
1443
- cacheHeaders: {
1444
- cacheControl: cacheability.printCacheControl()
1445
- },
1446
- tag: options.tag
1447
- }, options, {
1448
- ...context,
1449
- requestFieldCacheKey
1450
- });
1451
- if (hasChildFields(field, {
1452
- fragmentDefinitions: context.fragmentDefinitions
1453
- })) {
1454
- if (isEntity) {
1455
- set(data, responseDataPath, {
1456
- __cacheKey: `${REQUEST_FIELD_PATHS}::${hashedRequestFieldCacheKey}`
1457
- });
1458
- } else {
1459
- unset(data, responseDataPath);
1460
- }
1461
- }
1462
- }
1463
- }
1464
- _setResponseChunksAwaitingCaching(normalizedResponseData, context) {
1465
- const responseChunks = this._responseChunksAwaitingCaching.get(context.requestID);
1466
- if (responseChunks) {
1467
- this._responseChunksAwaitingCaching.set(context.requestID, [...responseChunks, normalizedResponseData]);
1468
- } else {
1469
- this._responseChunksAwaitingCaching.set(context.requestID, [normalizedResponseData]);
1470
- }
1471
- }
1472
- }, (_applyDecoratedDescriptor(_class.prototype, "_getCacheEntry", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "_getCacheEntry"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "_setCacheEntry", [_dec2], Object.getOwnPropertyDescriptor(_class.prototype, "_setCacheEntry"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "_setPartialQueryResponse", [_dec3], Object.getOwnPropertyDescriptor(_class.prototype, "_setPartialQueryResponse"), _class.prototype)), _class));
1473
-
1474
- export { CacheManager };
1
+ import e from"@babel/runtime/helpers/defineProperty";import t from"@babel/runtime/helpers/applyDecoratedDescriptor";import"core-js/modules/es.array.push.js";import{CACHE_ENTRY_ADDED as a,CACHE_ENTRY_QUERIED as s,PARTIAL_QUERY_COMPILED as i,TYPE_NAME_KEY as n,DEFAULT_TYPE_ID_KEY as r,QUERY_RESPONSES as c,DATA_ENTITIES as h,REQUEST_FIELD_PATHS as o}from"@graphql-box/core";import{isPlainObject as d,isArray as l,mergeObjects as y,isObjectLike as p,resolveFragments as u,getName as f,buildFieldKeysAndPaths as _,deleteFragmentSpreads as m,getChildFields as g,deleteChildFields as C,getInlineFragments as D,deleteInlineFragments as F,hasChildFields as P,deleteFragmentDefinitions as q,getOperationDefinitions as E,ArgsError as R,GroupedError as w,getFragmentDefinitions as N,hashRequest as M,rehydrateCacheMetadata as b,iterateChildFields as v,dehydrateCacheMetadata as K}from"@graphql-box/helpers";import{Cacheability as I}from"cacheability";import{Kind as k,print as T,OperationTypeNode as A}from"graphql";import{isNumber as x,isString as O,isEmpty as Q,keys as $,merge as j,set as z,cloneDeep as S,get as H,isUndefined as U,assign as G,isEqual as L,unset as V}from"lodash-es";const Y="noCache",B=(e,t)=>l(e)?e.reduce(((e,a)=>!!e&&B(a,t)),!0):!!d(e)&&J(e,t),J=(e,t)=>{const a=d(e)?Object.keys(e):[...e.keys()];return!(1!==a.length||!d(e)||!e[t])||a.reduce(((a,s)=>!!a&&(x(s)&&l(e)||O(s)&&d(e)?B(e[s],t):a)),!0)},W=(e,t,a)=>y(e,t,((e,t)=>d(t)&&t[a]?t[a]:void 0)),X=(e,t,a)=>!e&&t?t:p(e)&&p(t)?W(e,t,a):e,Z=(e,t)=>{if(!e||0===e.length)return{hasData:!1,typeUnused:!!t};const[a]=e;if(a){const{hasData:e,typeName:s}=a;return{hasData:e,typeUnused:s?s!==t:void 0}}return{hasData:e.some((({hasData:e,typeName:a})=>a===t&&e)),typeUnused:!e.every((({typeName:e})=>e===t))}},ee=(e,t,a,s,i)=>{const{fragmentDefinitions:r,typeIDKey:c}=i,h=g(e,{fragmentDefinitions:r});if(!h)return!1;const o={};for(let d=h.length-1;d>=0;d-=1){const l=h[d];if(!l)continue;const{fieldNode:y,fragmentKind:p,fragmentName:u,typeName:m}=l;p===k.FRAGMENT_SPREAD&&u&&!o[u]&&(o[u]={hasData:0,total:r?.[u]?g(r[u],{fragmentDefinitions:r})?.length??0:0});const D=f(y);if(D===c||D===n)continue;const{requestFieldPath:F}=_(y,{requestFieldPath:s},i),{hasData:q,typeUnused:E}=Z(t.get(F),m);if(q||E)if(p===k.FRAGMENT_SPREAD&&u){const e=o[u];e&&(e.hasData+=1)}else P(y,{fragmentDefinitions:r})?ee(y,t,a,F,i)&&C(e,y):C(e,y)}return((e,t,a,s)=>{if(!Q(t))for(const i of Object.keys(t)){const n=a[i];if(!n)continue;n.paths.push(s);const{hasData:r,total:c}=t[i];r===c&&(m(e,i),n.deleted+=1)}})(e,o,a,s),((e,{fragmentDefinitions:t,typeIDKey:a})=>{const s=D(e);let i=!1;for(const n of s){const s=g(n,{fragmentDefinitions:t});if(!s||0===s.length){F(e,n),i=!0;continue}const[r]=s;if(r){const{fieldNode:t}=r;f(t)===a&&(F(e,n),i=!0)}}})(e,i),((e,{fragmentDefinitions:t,typeIDKey:a})=>{const s=g(e,{fragmentDefinitions:t});if(!s||s.length>3)return!1;const i=s.map((({fieldNode:e})=>f(e)));if(2===i.length&&i.every((e=>e===a||e===n)))return C(e,s.map((({fieldNode:e})=>e))),!0;if(1===i.length&&i[0]===a||i[0]===n){const[t]=s;if(t){const{fieldNode:a}=t;return C(e,a),!0}}})(e,i),!P(e,{fragmentDefinitions:r})},te=(e,{fieldPathChecklist:t},a)=>{const{ast:s}=e,i=E(s,a.operation)[0];if(!i)return s;const{fragmentDefinitions:n,operation:r}=a,c=g(i,{fragmentDefinitions:n});if(!c)return s;const h=(({request:e},{fragmentDefinitions:t})=>$(t??{}).reduce(((t,a)=>(t[a]={deleted:0,paths:[],total:(e.match(new RegExp(`\\.\\.\\.${a}`,"g"))??[]).length},t)),{}))(e,a);for(let e=c.length-1;e>=0;e-=1){const{fieldNode:s}=c[e],{requestFieldPath:n}=_(s,{requestFieldPath:r},a);ee(s,t,h,n,a)&&C(i,s)}return a.queryFiltered=!0,((e,t,a,s)=>{const i=$(a).reduce(((e,t)=>{const s=a[t];if(!s)return e;const{deleted:i,paths:n,total:r}=s;return 0===i&&1===r?[...e,{name:t,path:n[0]}]:e}),[]),{fragmentDefinitions:n={}}=s;for(const{name:e,path:r}of i){const i=n[e];i&&ee(i,t,a,r,s)}const r=$(a).reduce(((e,t)=>{const s=a[t];if(!s)return e;const{deleted:i,total:n}=s;return i>0&&i===n?[...e,t]:e}),[]);return 0===r.length?e:q(e,{include:r})})(s,t,h,a)},ae=(e,t)=>l(e)&&x(t)||d(e)&&O(t)?e[t]:void 0,se=e=>!!p(e)&&(n in e&&O(e[n]));var ie,ne,re,ce;let he=(ie=(e,t,a)=>{const i=a.value;i&&(a.value=async function(...e){return new Promise((t=>{(async()=>{const{debugManager:a,requestFieldCacheKey:n,...r}=e[3];if(!a)return void t(await i.apply(this,e));const c=a.now(),h=await i.apply(this,e),o=a.now(),d=o-c;t(h);const l={cacheType:e[0],context:r,options:e[2],requestHash:e[1],result:h,stats:{duration:d,endTime:o,startTime:c},...n?{decryptedCacheKey:n}:{}};a.log(s,l)})()}))})},ne=(e,t,s)=>{const i=s.value;i&&(s.value=async function(...e){return new Promise((t=>{(async()=>{const{debugManager:s,requestFieldCacheKey:n,...r}=e[5];if(!s)return await i.apply(this,e),void t();const c=s.now();await i.apply(this,e);const h=s.now(),o=h-c;t();const d={cacheType:e[0],cachemapOptions:e[3],context:r,options:e[4],requestHash:e[1],stats:{duration:o,endTime:h,startTime:c},value:e[2],...n?{decryptedCacheKey:n}:{}};s.log(a,d)})()}))})},re=(e,t,a)=>{const s=a.value;s&&(a.value=function(...e){const{debugManager:t,...a}=e[3];if(!t)return void s.apply(this,e);const n=t.now();s.apply(this,e);const r=t.now(),c=r-n;t.log(i,{context:a,options:e[2],requestHash:e[0],result:e[1],stats:{duration:c,endTime:r,startTime:n}})})},ce=class t{static _countFieldPathChecklist(e){const t={missing:0,total:0};for(const[,a]of e){t.total+=a.length;const e=a.filter((({hasData:e})=>!e));t.missing+=e.length}return t}static _getFieldDataFromAncestor(e,t){const a=ae(e,t);return p(a)?S(a):a}static _getOperationCacheControl(e,t){const a="no-cache";if(!e)return a;const s=e.get(t);return s?s.printCacheControl():a}static _isNodeEntity(e){if(!e)return!1;const{isEntity:t,possibleTypes:a}=e;return t||a.some((e=>!!e.isEntity))}static _isNodeRequestFieldPath(e){return!!e&&(this._isNodeEntity(e)||e.hasArguments||e.hasDirectives)}static _isValid(e){return!H(e,["metadata","cacheControl",Y],!1)&&e.checkTTL()}static _mergeResponseCacheMetadata(e,t){return t?new Map([...t.cacheMetadata,...e]):e}static _setCachedData(e,{data:t},a){const s=t=>{(l(e)&&x(a)||d(e))&&(e[a]=t)};p(t)||U(t)?l(t)?s([]):d(t)&&s({}):s(t)}static _setCachedResponseData(e,{cacheMetadata:a,data:s,fieldPathChecklist:i},{propNameOrIndex:n,requestFieldPath:r},c,h,{operation:o}){t._setCacheMetadata(a,e.cacheability,r,o),t._setFieldPathChecklist(i,e,r,c),t._setCachedData(s,e,n)}static _setCacheMetadata(e,t,a,s){if(!t)return;e.set(a,t);const i=e.get(s);(!i||i.metadata.ttl>t.metadata.ttl)&&e.set(s,t)}static _setFieldPathChecklist(e,{data:t},a,{dataTypename:s,fieldTypename:i,fragmentKind:n,fragmentName:r}){if(U(i)||n===k.FRAGMENT_SPREAD){if(e.has(a))return;return void e.set(a,[{fragmentKind:n,fragmentName:r,hasData:!U(t)}])}if(s!==i)return;const c=e.get(a)??[];c.some((({typeName:e})=>e===s))||e.set(a,[...c,{fragmentKind:n,fragmentName:r,hasData:!U(t),typeName:s}])}constructor(t){e(this,"_cache",void 0),e(this,"_cascadeCacheControl",void 0),e(this,"_fallbackOperationCacheability",void 0),e(this,"_partialQueryResponses",new Map),e(this,"_responseChunksAwaitingCaching",new Map),e(this,"_typeCacheDirectives",void 0),e(this,"_typeIDKey",void 0);const a=[];if("cache"in t||a.push(new R("@graphql-box/cache-manager expected cache to be in options.")),t.typeCacheDirectives&&!d(t.typeCacheDirectives)){const e="@graphql-box/cache-manager expected options.typeCacheDirectives to be a plain object.";a.push(new R(e))}if(a.length>0)throw new w("@graphql-box/cache-manager argument validation errors.",a);this._cache=t.cache,this._cascadeCacheControl=t.cascadeCacheControl??!1,this._fallbackOperationCacheability=t.fallbackOperationCacheability??Y,this._typeCacheDirectives=t.typeCacheDirectives??{},this._typeIDKey=t.typeIDKey??r}async analyzeQuery(e,t,a){const{ast:s,hash:i}=e,n={...a,fragmentDefinitions:N(s),typeIDKey:this._typeIDKey},r=await this._retrieveCachedResponseData(e,t,n),{cacheMetadata:c,data:h,fieldCount:o}=r;if(o.missing===o.total||((e,t)=>J(e,t))(h,this._typeIDKey))return{updated:e};if(!o.missing){const e=this._setQueryResponseCacheEntry(i,{cacheMetadata:c,data:h},t,n);return t.awaitDataCaching&&await e,{response:{cacheMetadata:c,data:h}}}const d=te(e,r,n),l=T(d),{fragmentDefinitions:y,typeIDKey:p,...u}=n;return G(a,{...u,filteredRequest:l}),this._setPartialQueryResponse(i,{cacheMetadata:c,data:h},t,a),{updated:{ast:d,hash:M(l),request:l}}}get cache(){return this._cache}async cacheQuery(e,t,a,s,i){const n={...i,fragmentDefinitions:N((t??e).ast),typeIDKey:this._typeIDKey};return this._cacheResponse(e,t,a,s,n)}async cacheResponse(e,t,a,s){const i={...s,fragmentDefinitions:N(e.ast),typeIDKey:this._typeIDKey};return this._cacheResponse(e,void 0,t,a,i)}async checkCacheEntry(e,t,a,s){return this._checkCacheEntry(e,t,a,s)}async checkQueryResponseCacheEntry(e,t,a){const s=await this._checkCacheEntry(c,e,t,a);if(!s)return!1;const{cacheMetadata:i,data:n}=s.entry;return{cacheMetadata:b(i),data:n}}deletePartialQueryResponse(e){this._partialQueryResponses.delete(e)}async setQueryResponseCacheEntry(e,t,a,s){return this._setQueryResponseCacheEntry(e.hash,t,a,s)}async _analyzeFieldNode(e,t,a,s,i){await(P(e,{fragmentDefinitions:i.fragmentDefinitions})?this._analyzeParentFieldNode(e,t,a,s,i):this._analyzeLeafFieldNode(e,t,a,s,i))}async _analyzeLeafFieldNode(e,a,s,i,n){const r=_(e,a,n),{hashedRequestFieldCacheKey:c,propNameOrIndex:h,requestFieldCacheKey:o,requestFieldPath:d}=r,l=n.fieldTypeMap.get(d),{entityData:y,fragmentKind:p,fragmentName:u,requestFieldPathData:f,typeName:m}=a,g={dataTypename:se(y)?y.__typename:se(f)?f.__typename:void 0,fieldTypename:m,fragmentKind:p,fragmentName:u};if(t._isNodeRequestFieldPath(l)){const{cacheability:e,entry:a}=await this._retrieveCachedRequestFieldPathData(c,o,i,n);t._setCachedResponseData({cacheability:e,data:a},s,r,g,i,n)}else{const e=t._getFieldDataFromAncestor(y,h)??t._getFieldDataFromAncestor(f,h);t._setFieldPathChecklist(s.fieldPathChecklist,{data:e},d,g),t._setCachedData(s.data,{data:e},h)}}async _analyzeParentFieldNode(e,a,s,i,r){const c=_(e,a,r),{propNameOrIndex:h,requestFieldCacheKey:o,requestFieldPath:d}=c,l=r.fieldTypeMap.get(d),{cacheability:y,data:u,entityData:f,requestFieldPathData:m}=await this._retrieveCachedParentNodeData(a,c,l,i,r),{fragmentKind:g,fragmentName:C,typeName:D}=a;if(t._setCachedResponseData({cacheability:y,data:u},s,c,{dataTypename:H(u,n),fieldTypename:D,fragmentKind:g,fragmentName:C},i,r),!p(u))return;const F=[];v(e,u,r.fragmentDefinitions,((e,t,a,n,c)=>{F.push(this._analyzeFieldNode(e,{cacheability:y,entityData:f,fragmentKind:a,fragmentName:n,index:c,requestFieldCacheKey:o,requestFieldPath:d,requestFieldPathData:m,typeName:t},{...s,data:ae(s.data,h)},i,r))})),await Promise.all(F)}_buildCacheMetadata({ast:e},{data:t,...a},s,i){const n=this._createCacheMetadata({data:t,...a},i),r=E(e,i.operation)[0];if(!r)return n;const c=g(r);if(!c)return n;for(const{fieldNode:e}of c)this._setFieldCacheability(e,{requestFieldPath:i.operation},{cacheMetadata:n,data:t},s,i);return n}async _cacheResponse(e,a,s,i,n){const r=((e,t)=>{if(!t.normalizePatchResponseData)return e;const{data:a,paths:s,...i}=e;return s?.length&&O(s[0])?{...i,data:z({},s[0],a),paths:s}:e})(s,n);let c=r;((e,t)=>t.hasDeferOrStream&&e.hasNext)(s,n)&&(this._setResponseChunksAwaitingCaching(r,n),c=void 0),((e,t)=>t.hasDeferOrStream&&!e.hasNext&&e.paths)(s,n)&&(c=this._retrieveResponseDataForCaching(r,n));const h=[];if(c){const{data:s}=c,o=this._buildCacheMetadata(e,c,i,n);let d,l;if(h.push(this._setEntityAndRequestFieldPathCacheEntries(e,{cacheMetadata:o,entityData:S(s),requestFieldPathData:S(s)},i,n)),n.operation===A.QUERY){let r;n.queryFiltered&&a&&(h.push(this._setQueryResponseCacheEntry(a.hash,{cacheMetadata:o,data:s},i,n)),r=this._getPartialQueryResponse(e.hash)),d=t._mergeResponseCacheMetadata(o,r),l=this._mergeResponseData(s,r),h.push(this._setQueryResponseCacheEntry(e.hash,{cacheMetadata:d,data:l},i,n))}if(i.awaitDataCaching&&await Promise.all(h),((e,t)=>!t.hasDeferOrStream&&!e.hasNext&&!e.paths)(r,n)&&d&&l)return{cacheMetadata:d,data:l}}const{data:o,hasNext:d,paths:l}=r;return{cacheMetadata:this._buildCacheMetadata(e,r,i,n),data:o,hasNext:d,paths:l}}async _checkCacheEntry(e,a,s,i){try{const n=await this._hasCacheEntry(e,a);if(!n||!t._isValid(n))return!1;const r=await this._getCacheEntry(e,a,s,i);return!U(r)&&{cacheability:n,entry:r}}catch{return!1}}_createCacheMetadata({_cacheMetadata:e,headers:t},{operation:a}){const s=new Map,i=(({_cacheMetadata:e,fallback:t,headers:a})=>{if(e&&!Q(e)){const[t,...a]=Object.values(e);return new I({metadata:a.reduce(((e,t)=>e?t.ttl<e.ttl?t:e:t),t)})}return a?.has("cache-control")?new I({headers:a}):new I({cacheControl:t})})({_cacheMetadata:e,fallback:this._fallbackOperationCacheability,headers:t});return s.set(a,i),e&&b(e,s),s}async _getCacheEntry(e,t,a,s){return this._cache.get(`${e}::${t}`)}_getPartialQueryResponse(e){const t=this._partialQueryResponses.get(e);return this._partialQueryResponses.delete(e),t}async _hasCacheEntry(e,t){try{return await this._cache.has(`${e}::${t}`)}catch{return!1}}_isFieldEntity(e,{isEntity:t,possibleTypes:a}){return!(!d(e)||!(this._typeIDKey in e))&&(!!t||0!==a.length&&a.some((t=>t.typeName===e.__typename)))}_mergeResponseData(e,t){return t?W(t.data,e,this._typeIDKey):e}async _parseEntityAndRequestFieldPathCacheEntryData(e,t,{cacheMetadata:a,entityData:s,requestFieldPathData:i},n,r){const c=_(e,t,r),{requestFieldCacheKey:h,requestFieldPath:o,responseDataPath:d}=c,l=H(i,d),y=r.fieldTypeMap.get(o);if(p(l)||y?.hasDirectives){if(p(l)){const t=[];v(e,l,r.fragmentDefinitions,((e,c,l,y,p)=>{t.push(this._parseEntityAndRequestFieldPathCacheEntryData(e,{index:p,requestFieldCacheKey:h,requestFieldPath:o,responseDataPath:d},{cacheMetadata:a,entityData:s,requestFieldPathData:i},n,r))})),await Promise.all(t)}await this._setEntityAndRequestFieldPathCacheEntry(e,c,{cacheMetadata:a,entityData:s,requestFieldPathData:i},n,r)}}async _retrieveCachedEntityData(e,{possibleTypes:t,typeName:a},s,i){const n=[...t.map((e=>e.typeName)),a],r=(await Promise.all(n.map((t=>this._checkCacheEntry(h,`${t}::${e}`,s,i))))).filter((e=>!!e));let c;return 1===r.length?c=r[0]:r.length>1&&(r.sort((({cacheability:e},{cacheability:t})=>e.metadata.ttl-t.metadata.ttl)),c={cacheability:r[0].cacheability,entry:r.reduce(((e,{entry:t})=>W(e,t,this._typeIDKey)),{})}),c??{}}async _retrieveCachedParentNodeData({entityData:e,requestFieldPathData:a},{hashedRequestFieldCacheKey:s,propNameOrIndex:i,requestFieldCacheKey:n},r,c,h){let o,l=t._getFieldDataFromAncestor(e,i),y=t._getFieldDataFromAncestor(a,i);if(t._isNodeRequestFieldPath(r)){const{cacheability:e,entry:t}=await this._retrieveCachedRequestFieldPathData(s,n,c,h);y=X(y,t,this._typeIDKey),e&&(o=e)}const p=((e,{typeIDValue:t},a)=>t||(d(e)?e[a]:void 0))(y,r,this._typeIDKey);if(t._isNodeEntity(r)&&p){const{cacheability:e,entry:t}=await this._retrieveCachedEntityData(p,r,c,h);l=X(l,t,this._typeIDKey),e&&(!o||e.metadata.ttl>o.metadata.ttl)&&(o=e)}return{cacheability:o,data:L(l,y)?l:X(l,y,this._typeIDKey),entityData:l,requestFieldPathData:y}}async _retrieveCachedRequestFieldPathData(e,t,a,s){return await this._checkCacheEntry(o,e,a,{...s,requestFieldCacheKey:t})||{}}async _retrieveCachedResponseData({ast:e},a,s){const i={cacheMetadata:new Map,data:{},fieldCount:{missing:0,total:0},fieldPathChecklist:new Map},n=E(e,s.operation)[0];if(!n)return i;const r=g(n);return r?(await Promise.all(r.map((({fieldNode:e})=>this._analyzeFieldNode(e,{requestFieldPath:s.operation},i,a,s)))),i.fieldCount=t._countFieldPathChecklist(i.fieldPathChecklist),i):i}_retrieveResponseDataForCaching(e,t){const a=this._responseChunksAwaitingCaching.get(t.requestID);return this._responseChunksAwaitingCaching.delete(t.requestID),(s=[...a,e]).reduce(((e,t,a)=>{const{_cacheMetadata:i,data:n,hasNext:r,headers:c,paths:h}=t;return i&&(e._cacheMetadata=e._cacheMetadata?{...e._cacheMetadata,...i}:i),e.data=j(e.data,n),0===a&&(e.headers=c),a===s.length-1&&(e.hasNext=r),h&&(e.paths||(e.paths=[]),e.paths.push(...h)),e}),{data:{}});var s}async _setCacheEntry(e,t,a,s,i,n){try{await this._cache.set(`${e}::${t}`,S(a),s)}catch{}}async _setEntityAndRequestFieldPathCacheEntries(e,t,a,s){const i=E(e.ast,s.operation)[0];if(!i)return;const n=g(i);n&&await Promise.all(n.map((({fieldNode:e})=>this._parseEntityAndRequestFieldPathCacheEntryData(e,{requestFieldPath:s.operation},t,a,s))))}async _setEntityAndRequestFieldPathCacheEntry(e,t,{cacheMetadata:a,entityData:s,requestFieldPathData:i},n,r){const{requestFieldPath:c,responseDataPath:h}=t,o=H(s,h),d=r.fieldTypeMap.get(c),l=a.get(c);if(U(o)||!d||!l)return;const y=[];y.push(this._setRequestFieldPathCacheEntry(e,t,{cacheability:l,data:i,fieldTypeInfo:d},n,r));const p=this._isFieldEntity(o,d);!p&&d.hasArguments&&V(s,h),p&&y.push(this._setEntityCacheEntry(t,{cacheability:l,data:s,fieldTypeInfo:d},n,r)),await Promise.all(y)}async _setEntityCacheEntry({responseDataPath:e},{cacheability:t,data:a,fieldTypeInfo:s},i,n){let r=H(a,e);const c=`${s.isEntity?s.typeName:r.__typename}::${String(r[this._typeIDKey])}`,o=await this._checkCacheEntry(h,c,i,n);o&&(r=W(o.entry,r,this._typeIDKey)),await this._setCacheEntry(h,c,r,{cacheHeaders:{cacheControl:t.printCacheControl()},tag:i.tag},i,n),z(a,e,{__cacheKey:`${h}::${c}`})}_setFieldCacheability(e,t,{cacheMetadata:a,data:s},i,n){const{requestFieldPath:r}=t,c=_(e,t,n),{requestFieldPath:h,responseDataPath:o}=c;if(!p(s))return;const d=H(s,o),l=n.fieldTypeMap.get(h);(p(d)||l?.hasDirectives)&&(this._setFieldTypeCacheDirective(a,{ancestorRequestFieldPath:r,requestFieldPath:h},n),p(d)&&v(e,d,n.fragmentDefinitions,((e,t,r,c,d)=>{this._setFieldCacheability(e,{index:d,requestFieldPath:h,responseDataPath:o},{cacheMetadata:a,data:s},i,n)})))}_setFieldTypeCacheDirective(e,{ancestorRequestFieldPath:a,requestFieldPath:s},{fieldTypeMap:i,operation:n}){if(e.has(s))return;const r=i.get(s);if(r&&this._typeCacheDirectives[r.typeName]){const a=new I({cacheControl:this._typeCacheDirectives[r.typeName]});t._setCacheMetadata(e,a,s,n)}else this._cascadeCacheControl&&a&&t._setCacheMetadata(e,e.get(a),s,n)}_setPartialQueryResponse(e,t,a,s){this._partialQueryResponses.set(e,t)}async _setQueryResponseCacheEntry(e,{cacheMetadata:a,data:s},i,n){const r=K(a),h=t._getOperationCacheControl(a,n.operation);await this._setCacheEntry(c,e,{cacheMetadata:r,data:s},{cacheHeaders:{cacheControl:h},tag:i.tag},i,n)}async _setRequestFieldPathCacheEntry(e,t,{cacheability:a,data:s,fieldTypeInfo:i},n,r){const{hashedRequestFieldCacheKey:c,requestFieldCacheKey:h,responseDataPath:l}=t;let y=H(s,l);const m=this._isFieldEntity(y,i),g=i.hasArguments||i.hasDirectives;if(r.operation===A.QUERY&&(m||g)){d(y)&&e.selectionSet?.selections&&(y=((e,t,a,s)=>{const i=u(t,s.fragmentDefinitions);return $(e).reduce(((t,n)=>{const r=i.find((({fieldNode:e})=>f(e)===n));if(r){const{requestFieldPath:i}=_(r.fieldNode,a,s),c=s.fieldTypeMap.get(i);c?.hasArguments||c?.hasDirectives||(t[n]=e[n])}return t}),{})})(y,e.selectionSet.selections,t,r));const i=await this._checkCacheEntry(o,c,n,{...r,requestFieldCacheKey:h});i&&p(i.entry)&&p(y)&&(y=W(i.entry,y,this._typeIDKey)),await this._setCacheEntry(o,c,y,{cacheHeaders:{cacheControl:a.printCacheControl()},tag:n.tag},n,{...r,requestFieldCacheKey:h}),P(e,{fragmentDefinitions:r.fragmentDefinitions})&&(m?z(s,l,{__cacheKey:`${o}::${c}`}):V(s,l))}}_setResponseChunksAwaitingCaching(e,t){const a=this._responseChunksAwaitingCaching.get(t.requestID);a?this._responseChunksAwaitingCaching.set(t.requestID,[...a,e]):this._responseChunksAwaitingCaching.set(t.requestID,[e])}},t(ce.prototype,"_getCacheEntry",[ie],Object.getOwnPropertyDescriptor(ce.prototype,"_getCacheEntry"),ce.prototype),t(ce.prototype,"_setCacheEntry",[ne],Object.getOwnPropertyDescriptor(ce.prototype,"_setCacheEntry"),ce.prototype),t(ce.prototype,"_setPartialQueryResponse",[re],Object.getOwnPropertyDescriptor(ce.prototype,"_setPartialQueryResponse"),ce.prototype),ce);export{he as CacheManager};
1475
2
  //# sourceMappingURL=index.mjs.map