1 | import { __assign } from "tslib";
|
2 | import { invariant, newInvariantError } from "../../utilities/globals/index.js";
|
3 | import { Kind } from "graphql";
|
4 | import { wrap } from "optimism";
|
5 | import { isField, resultKeyNameFromField, isReference, makeReference, shouldInclude, addTypenameToDocument, getDefaultValues, getMainDefinition, getQueryDefinition, getFragmentFromSelection, maybeDeepFreeze, mergeDeepArray, DeepMerger, isNonNullObject, canUseWeakMap, compact, canonicalStringify, cacheSizes, } from "../../utilities/index.js";
|
6 | import { maybeDependOnExistenceOfEntity, supportsResultCaching, } from "./entityStore.js";
|
7 | import { isArray, extractFragmentContext, getTypenameFromStoreObject, shouldCanonizeResults, } from "./helpers.js";
|
8 | import { MissingFieldError } from "../core/types/common.js";
|
9 | import { ObjectCanon } from "./object-canon.js";
|
10 | function execSelectionSetKeyArgs(options) {
|
11 | return [
|
12 | options.selectionSet,
|
13 | options.objectOrReference,
|
14 | options.context,
|
15 |
|
16 |
|
17 | options.context.canonizeResults,
|
18 | ];
|
19 | }
|
20 | var StoreReader = (function () {
|
21 | function StoreReader(config) {
|
22 | var _this = this;
|
23 | this.knownResults = new (canUseWeakMap ? WeakMap : Map)();
|
24 | this.config = compact(config, {
|
25 | addTypename: config.addTypename !== false,
|
26 | canonizeResults: shouldCanonizeResults(config),
|
27 | });
|
28 | this.canon = config.canon || new ObjectCanon();
|
29 |
|
30 |
|
31 |
|
32 |
|
33 | this.executeSelectionSet = wrap(function (options) {
|
34 | var _a;
|
35 | var canonizeResults = options.context.canonizeResults;
|
36 | var peekArgs = execSelectionSetKeyArgs(options);
|
37 |
|
38 |
|
39 | peekArgs[3] = !canonizeResults;
|
40 | var other = (_a = _this.executeSelectionSet).peek.apply(_a, peekArgs);
|
41 | if (other) {
|
42 | if (canonizeResults) {
|
43 | return __assign(__assign({}, other), {
|
44 |
|
45 |
|
46 | result: _this.canon.admit(other.result) });
|
47 | }
|
48 |
|
49 |
|
50 | return other;
|
51 | }
|
52 | maybeDependOnExistenceOfEntity(options.context.store, options.enclosingRef.__ref);
|
53 |
|
54 |
|
55 | return _this.execSelectionSetImpl(options);
|
56 | }, {
|
57 | max: this.config.resultCacheMaxSize ||
|
58 | cacheSizes["inMemoryCache.executeSelectionSet"] ||
|
59 | 50000 ,
|
60 | keyArgs: execSelectionSetKeyArgs,
|
61 |
|
62 |
|
63 | makeCacheKey: function (selectionSet, parent, context, canonizeResults) {
|
64 | if (supportsResultCaching(context.store)) {
|
65 | return context.store.makeCacheKey(selectionSet, isReference(parent) ? parent.__ref : parent, context.varString, canonizeResults);
|
66 | }
|
67 | },
|
68 | });
|
69 | this.executeSubSelectedArray = wrap(function (options) {
|
70 | maybeDependOnExistenceOfEntity(options.context.store, options.enclosingRef.__ref);
|
71 | return _this.execSubSelectedArrayImpl(options);
|
72 | }, {
|
73 | max: this.config.resultCacheMaxSize ||
|
74 | cacheSizes["inMemoryCache.executeSubSelectedArray"] ||
|
75 | 10000 ,
|
76 | makeCacheKey: function (_a) {
|
77 | var field = _a.field, array = _a.array, context = _a.context;
|
78 | if (supportsResultCaching(context.store)) {
|
79 | return context.store.makeCacheKey(field, array, context.varString);
|
80 | }
|
81 | },
|
82 | });
|
83 | }
|
84 | StoreReader.prototype.resetCanon = function () {
|
85 | this.canon = new ObjectCanon();
|
86 | };
|
87 | |
88 |
|
89 |
|
90 |
|
91 | StoreReader.prototype.diffQueryAgainstStore = function (_a) {
|
92 | var store = _a.store, query = _a.query, _b = _a.rootId, rootId = _b === void 0 ? "ROOT_QUERY" : _b, variables = _a.variables, _c = _a.returnPartialData, returnPartialData = _c === void 0 ? true : _c, _d = _a.canonizeResults, canonizeResults = _d === void 0 ? this.config.canonizeResults : _d;
|
93 | var policies = this.config.cache.policies;
|
94 | variables = __assign(__assign({}, getDefaultValues(getQueryDefinition(query))), variables);
|
95 | var rootRef = makeReference(rootId);
|
96 | var execResult = this.executeSelectionSet({
|
97 | selectionSet: getMainDefinition(query).selectionSet,
|
98 | objectOrReference: rootRef,
|
99 | enclosingRef: rootRef,
|
100 | context: __assign({ store: store, query: query, policies: policies, variables: variables, varString: canonicalStringify(variables), canonizeResults: canonizeResults }, extractFragmentContext(query, this.config.fragments)),
|
101 | });
|
102 | var missing;
|
103 | if (execResult.missing) {
|
104 |
|
105 |
|
106 |
|
107 |
|
108 | missing = [
|
109 | new MissingFieldError(firstMissing(execResult.missing), execResult.missing, query, variables),
|
110 | ];
|
111 | if (!returnPartialData) {
|
112 | throw missing[0];
|
113 | }
|
114 | }
|
115 | return {
|
116 | result: execResult.result,
|
117 | complete: !missing,
|
118 | missing: missing,
|
119 | };
|
120 | };
|
121 | StoreReader.prototype.isFresh = function (result, parent, selectionSet, context) {
|
122 | if (supportsResultCaching(context.store) &&
|
123 | this.knownResults.get(result) === selectionSet) {
|
124 | var latest = this.executeSelectionSet.peek(selectionSet, parent, context,
|
125 |
|
126 |
|
127 |
|
128 | this.canon.isKnown(result));
|
129 | if (latest && result === latest.result) {
|
130 | return true;
|
131 | }
|
132 | }
|
133 | return false;
|
134 | };
|
135 |
|
136 | StoreReader.prototype.execSelectionSetImpl = function (_a) {
|
137 | var _this = this;
|
138 | var selectionSet = _a.selectionSet, objectOrReference = _a.objectOrReference, enclosingRef = _a.enclosingRef, context = _a.context;
|
139 | if (isReference(objectOrReference) &&
|
140 | !context.policies.rootTypenamesById[objectOrReference.__ref] &&
|
141 | !context.store.has(objectOrReference.__ref)) {
|
142 | return {
|
143 | result: this.canon.empty,
|
144 | missing: "Dangling reference to missing ".concat(objectOrReference.__ref, " object"),
|
145 | };
|
146 | }
|
147 | var variables = context.variables, policies = context.policies, store = context.store;
|
148 | var typename = store.getFieldValue(objectOrReference, "__typename");
|
149 | var objectsToMerge = [];
|
150 | var missing;
|
151 | var missingMerger = new DeepMerger();
|
152 | if (this.config.addTypename &&
|
153 | typeof typename === "string" &&
|
154 | !policies.rootIdsByTypename[typename]) {
|
155 |
|
156 |
|
157 |
|
158 | objectsToMerge.push({ __typename: typename });
|
159 | }
|
160 | function handleMissing(result, resultName) {
|
161 | var _a;
|
162 | if (result.missing) {
|
163 | missing = missingMerger.merge(missing, (_a = {},
|
164 | _a[resultName] = result.missing,
|
165 | _a));
|
166 | }
|
167 | return result.result;
|
168 | }
|
169 | var workSet = new Set(selectionSet.selections);
|
170 | workSet.forEach(function (selection) {
|
171 | var _a, _b;
|
172 |
|
173 |
|
174 | if (!shouldInclude(selection, variables))
|
175 | return;
|
176 | if (isField(selection)) {
|
177 | var fieldValue = policies.readField({
|
178 | fieldName: selection.name.value,
|
179 | field: selection,
|
180 | variables: context.variables,
|
181 | from: objectOrReference,
|
182 | }, context);
|
183 | var resultName = resultKeyNameFromField(selection);
|
184 | if (fieldValue === void 0) {
|
185 | if (!addTypenameToDocument.added(selection)) {
|
186 | missing = missingMerger.merge(missing, (_a = {},
|
187 | _a[resultName] = "Can't find field '".concat(selection.name.value, "' on ").concat(isReference(objectOrReference) ?
|
188 | objectOrReference.__ref + " object"
|
189 | : "object " + JSON.stringify(objectOrReference, null, 2)),
|
190 | _a));
|
191 | }
|
192 | }
|
193 | else if (isArray(fieldValue)) {
|
194 | if (fieldValue.length > 0) {
|
195 | fieldValue = handleMissing(_this.executeSubSelectedArray({
|
196 | field: selection,
|
197 | array: fieldValue,
|
198 | enclosingRef: enclosingRef,
|
199 | context: context,
|
200 | }), resultName);
|
201 | }
|
202 | }
|
203 | else if (!selection.selectionSet) {
|
204 |
|
205 |
|
206 |
|
207 |
|
208 | if (context.canonizeResults) {
|
209 | fieldValue = _this.canon.pass(fieldValue);
|
210 | }
|
211 | }
|
212 | else if (fieldValue != null) {
|
213 |
|
214 |
|
215 |
|
216 | fieldValue = handleMissing(_this.executeSelectionSet({
|
217 | selectionSet: selection.selectionSet,
|
218 | objectOrReference: fieldValue,
|
219 | enclosingRef: isReference(fieldValue) ? fieldValue : enclosingRef,
|
220 | context: context,
|
221 | }), resultName);
|
222 | }
|
223 | if (fieldValue !== void 0) {
|
224 | objectsToMerge.push((_b = {}, _b[resultName] = fieldValue, _b));
|
225 | }
|
226 | }
|
227 | else {
|
228 | var fragment = getFragmentFromSelection(selection, context.lookupFragment);
|
229 | if (!fragment && selection.kind === Kind.FRAGMENT_SPREAD) {
|
230 | throw newInvariantError(9, selection.name.value);
|
231 | }
|
232 | if (fragment && policies.fragmentMatches(fragment, typename)) {
|
233 | fragment.selectionSet.selections.forEach(workSet.add, workSet);
|
234 | }
|
235 | }
|
236 | });
|
237 | var result = mergeDeepArray(objectsToMerge);
|
238 | var finalResult = { result: result, missing: missing };
|
239 | var frozen = context.canonizeResults ?
|
240 | this.canon.admit(finalResult)
|
241 |
|
242 |
|
243 | : maybeDeepFreeze(finalResult);
|
244 |
|
245 |
|
246 | if (frozen.result) {
|
247 | this.knownResults.set(frozen.result, selectionSet);
|
248 | }
|
249 | return frozen;
|
250 | };
|
251 |
|
252 | StoreReader.prototype.execSubSelectedArrayImpl = function (_a) {
|
253 | var _this = this;
|
254 | var field = _a.field, array = _a.array, enclosingRef = _a.enclosingRef, context = _a.context;
|
255 | var missing;
|
256 | var missingMerger = new DeepMerger();
|
257 | function handleMissing(childResult, i) {
|
258 | var _a;
|
259 | if (childResult.missing) {
|
260 | missing = missingMerger.merge(missing, (_a = {}, _a[i] = childResult.missing, _a));
|
261 | }
|
262 | return childResult.result;
|
263 | }
|
264 | if (field.selectionSet) {
|
265 | array = array.filter(context.store.canRead);
|
266 | }
|
267 | array = array.map(function (item, i) {
|
268 |
|
269 | if (item === null) {
|
270 | return null;
|
271 | }
|
272 |
|
273 | if (isArray(item)) {
|
274 | return handleMissing(_this.executeSubSelectedArray({
|
275 | field: field,
|
276 | array: item,
|
277 | enclosingRef: enclosingRef,
|
278 | context: context,
|
279 | }), i);
|
280 | }
|
281 |
|
282 | if (field.selectionSet) {
|
283 | return handleMissing(_this.executeSelectionSet({
|
284 | selectionSet: field.selectionSet,
|
285 | objectOrReference: item,
|
286 | enclosingRef: isReference(item) ? item : enclosingRef,
|
287 | context: context,
|
288 | }), i);
|
289 | }
|
290 | if (globalThis.__DEV__ !== false) {
|
291 | assertSelectionSetForIdValue(context.store, field, item);
|
292 | }
|
293 | return item;
|
294 | });
|
295 | return {
|
296 | result: context.canonizeResults ? this.canon.admit(array) : array,
|
297 | missing: missing,
|
298 | };
|
299 | };
|
300 | return StoreReader;
|
301 | }());
|
302 | export { StoreReader };
|
303 | function firstMissing(tree) {
|
304 | try {
|
305 | JSON.stringify(tree, function (_, value) {
|
306 | if (typeof value === "string")
|
307 | throw value;
|
308 | return value;
|
309 | });
|
310 | }
|
311 | catch (result) {
|
312 | return result;
|
313 | }
|
314 | }
|
315 | function assertSelectionSetForIdValue(store, field, fieldValue) {
|
316 | if (!field.selectionSet) {
|
317 | var workSet_1 = new Set([fieldValue]);
|
318 | workSet_1.forEach(function (value) {
|
319 | if (isNonNullObject(value)) {
|
320 | invariant(
|
321 | !isReference(value),
|
322 | 10,
|
323 | getTypenameFromStoreObject(store, value),
|
324 | field.name.value
|
325 | );
|
326 | Object.values(value).forEach(workSet_1.add, workSet_1);
|
327 | }
|
328 | });
|
329 | }
|
330 | }
|
331 |
|
\ | No newline at end of file |