@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.
- package/dist/cjs/index.cjs +1 -1476
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.mjs +1 -1474
- package/dist/esm/index.mjs.map +1 -1
- package/dist/production.analysis.txt +250 -0
- package/dist/types/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +17 -15
- package/tsconfig.build.json +2 -2
- package/tsconfig.json +1 -1
package/dist/esm/index.mjs
CHANGED
|
@@ -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
|