1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 | 'use strict';
|
12 |
|
13 | var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
14 |
|
15 | var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread"));
|
16 |
|
17 | var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
18 |
|
19 | var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment');
|
20 |
|
21 | var LRUCache = require('./LRUCache');
|
22 |
|
23 | var invariant = require("fbjs/lib/invariant");
|
24 |
|
25 | var _require = require('relay-runtime'),
|
26 | isPromise = _require.isPromise,
|
27 | RelayFeatureFlags = _require.RelayFeatureFlags;
|
28 |
|
29 | var CACHE_CAPACITY = 1000;
|
30 | var DEFAULT_FETCH_POLICY = 'store-or-network';
|
31 | var DEFAULT_RENDER_POLICY = RelayFeatureFlags.ENABLE_PARTIAL_RENDERING_DEFAULT === true ? 'partial' : 'full';
|
32 | var DATA_RETENTION_TIMEOUT = 30 * 1000;
|
33 |
|
34 | function getQueryCacheKey(operation, fetchPolicy, renderPolicy) {
|
35 | return "".concat(fetchPolicy, "-").concat(renderPolicy, "-").concat(operation.request.identifier);
|
36 | }
|
37 |
|
38 | function getQueryResult(operation, cacheKey) {
|
39 | var rootFragmentRef = {
|
40 | __id: operation.fragment.dataID,
|
41 | __fragments: (0, _defineProperty2["default"])({}, operation.fragment.node.name, operation.request.variables),
|
42 | __fragmentOwner: operation.request
|
43 | };
|
44 | return {
|
45 | cacheKey: cacheKey,
|
46 | fragmentNode: operation.request.node.fragment,
|
47 | fragmentRef: rootFragmentRef,
|
48 | operation: operation
|
49 | };
|
50 | }
|
51 |
|
52 | function createCacheEntry(cacheKey, operation, value, networkSubscription, onDispose) {
|
53 | var currentValue = value;
|
54 | var retainCount = 0;
|
55 | var permanentlyRetained = false;
|
56 | var retainDisposable = null;
|
57 | var releaseTemporaryRetain = null;
|
58 | var currentNetworkSubscription = networkSubscription;
|
59 |
|
60 | var retain = function retain(environment) {
|
61 | retainCount++;
|
62 |
|
63 | if (retainCount === 1) {
|
64 | retainDisposable = environment.retain(operation.root);
|
65 | }
|
66 |
|
67 | return {
|
68 | dispose: function dispose() {
|
69 | retainCount = Math.max(0, retainCount - 1);
|
70 |
|
71 | if (retainCount === 0) {
|
72 | !(retainDisposable != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Relay: Expected disposable to release query to be defined.' + "If you're seeing this, this is likely a bug in Relay.") : invariant(false) : void 0;
|
73 | retainDisposable.dispose();
|
74 | retainDisposable = null;
|
75 | }
|
76 |
|
77 | onDispose(cacheEntry);
|
78 | }
|
79 | };
|
80 | };
|
81 |
|
82 | var cacheEntry = {
|
83 | cacheKey: cacheKey,
|
84 | getValue: function getValue() {
|
85 | return currentValue;
|
86 | },
|
87 | setValue: function setValue(val) {
|
88 | currentValue = val;
|
89 | },
|
90 | getRetainCount: function getRetainCount() {
|
91 | return retainCount;
|
92 | },
|
93 | getNetworkSubscription: function getNetworkSubscription() {
|
94 | return currentNetworkSubscription;
|
95 | },
|
96 | setNetworkSubscription: function setNetworkSubscription(subscription) {
|
97 | if (currentNetworkSubscription != null) {
|
98 | currentNetworkSubscription.unsubscribe();
|
99 | }
|
100 |
|
101 | currentNetworkSubscription = subscription;
|
102 | },
|
103 | temporaryRetain: function temporaryRetain(environment) {
|
104 |
|
105 |
|
106 | if (!ExecutionEnvironment.canUseDOM) {
|
107 | return {
|
108 | dispose: function dispose() {}
|
109 | };
|
110 | }
|
111 |
|
112 | if (permanentlyRetained === true) {
|
113 | return {
|
114 | dispose: function dispose() {}
|
115 | };
|
116 | }
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 | var disposable = retain(environment);
|
125 | var releaseQueryTimeout = null;
|
126 |
|
127 | var localReleaseTemporaryRetain = function localReleaseTemporaryRetain() {
|
128 | clearTimeout(releaseQueryTimeout);
|
129 | releaseQueryTimeout = null;
|
130 | releaseTemporaryRetain = null;
|
131 | disposable.dispose();
|
132 | };
|
133 |
|
134 | releaseQueryTimeout = setTimeout(localReleaseTemporaryRetain, DATA_RETENTION_TIMEOUT);
|
135 |
|
136 |
|
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 | if (releaseTemporaryRetain != null) {
|
143 | releaseTemporaryRetain();
|
144 | }
|
145 |
|
146 | releaseTemporaryRetain = localReleaseTemporaryRetain;
|
147 | return {
|
148 | dispose: function dispose() {
|
149 | if (permanentlyRetained === true) {
|
150 | return;
|
151 | }
|
152 |
|
153 | releaseTemporaryRetain && releaseTemporaryRetain();
|
154 | }
|
155 | };
|
156 | },
|
157 | permanentRetain: function permanentRetain(environment) {
|
158 | var disposable = retain(environment);
|
159 |
|
160 | if (releaseTemporaryRetain != null) {
|
161 | releaseTemporaryRetain();
|
162 | releaseTemporaryRetain = null;
|
163 | }
|
164 |
|
165 | permanentlyRetained = true;
|
166 | return {
|
167 | dispose: function dispose() {
|
168 | disposable.dispose();
|
169 |
|
170 | if (retainCount <= 0 && currentNetworkSubscription != null) {
|
171 | currentNetworkSubscription.unsubscribe();
|
172 | }
|
173 |
|
174 | permanentlyRetained = false;
|
175 | }
|
176 | };
|
177 | }
|
178 | };
|
179 | return cacheEntry;
|
180 | }
|
181 |
|
182 | var QueryResourceImpl =
|
183 |
|
184 | function () {
|
185 | function QueryResourceImpl(environment) {
|
186 | var _this = this;
|
187 |
|
188 | (0, _defineProperty2["default"])(this, "_clearCacheEntry", function (cacheEntry) {
|
189 | if (cacheEntry.getRetainCount() <= 0) {
|
190 | _this._cache["delete"](cacheEntry.cacheKey);
|
191 | }
|
192 | });
|
193 | this._environment = environment;
|
194 | this._cache = LRUCache.create(CACHE_CAPACITY);
|
195 | }
|
196 | |
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 | var _proto = QueryResourceImpl.prototype;
|
204 |
|
205 | _proto.prepare = function prepare(operation, fetchObservable, maybeFetchPolicy, maybeRenderPolicy, observer, cacheKeyBuster) {
|
206 | var _maybeFetchPolicy, _maybeRenderPolicy;
|
207 |
|
208 | var environment = this._environment;
|
209 | var fetchPolicy = (_maybeFetchPolicy = maybeFetchPolicy) !== null && _maybeFetchPolicy !== void 0 ? _maybeFetchPolicy : DEFAULT_FETCH_POLICY;
|
210 | var renderPolicy = (_maybeRenderPolicy = maybeRenderPolicy) !== null && _maybeRenderPolicy !== void 0 ? _maybeRenderPolicy : DEFAULT_RENDER_POLICY;
|
211 | var cacheKey = getQueryCacheKey(operation, fetchPolicy, renderPolicy);
|
212 |
|
213 | if (cacheKeyBuster != null) {
|
214 | cacheKey += "-".concat(cacheKeyBuster);
|
215 | }
|
216 |
|
217 |
|
218 |
|
219 | var cacheEntry = this._cache.get(cacheKey);
|
220 |
|
221 | var temporaryRetainDisposable = null;
|
222 |
|
223 | if (cacheEntry == null) {
|
224 |
|
225 |
|
226 |
|
227 | cacheEntry = this._fetchAndSaveQuery(cacheKey, operation, fetchObservable, fetchPolicy, renderPolicy, (0, _objectSpread2["default"])({}, observer, {
|
228 | unsubscribe: function unsubscribe(subscription) {
|
229 |
|
230 |
|
231 |
|
232 |
|
233 |
|
234 | if (temporaryRetainDisposable != null) {
|
235 | temporaryRetainDisposable.dispose();
|
236 | }
|
237 |
|
238 | var observerUnsubscribe = observer === null || observer === void 0 ? void 0 : observer.unsubscribe;
|
239 | observerUnsubscribe && observerUnsubscribe(subscription);
|
240 | }
|
241 | }));
|
242 | }
|
243 |
|
244 |
|
245 |
|
246 |
|
247 |
|
248 |
|
249 | temporaryRetainDisposable = cacheEntry.temporaryRetain(environment);
|
250 | var cachedValue = cacheEntry.getValue();
|
251 |
|
252 | if (isPromise(cachedValue) || cachedValue instanceof Error) {
|
253 | throw cachedValue;
|
254 | }
|
255 |
|
256 | return cachedValue;
|
257 | }
|
258 | |
259 |
|
260 |
|
261 |
|
262 |
|
263 | ;
|
264 |
|
265 | _proto.retain = function retain(queryResult) {
|
266 | var environment = this._environment;
|
267 | var cacheKey = queryResult.cacheKey,
|
268 | operation = queryResult.operation;
|
269 |
|
270 | var cacheEntry = this._getOrCreateCacheEntry(cacheKey, operation, queryResult, null);
|
271 |
|
272 | var disposable = cacheEntry.permanentRetain(environment);
|
273 | return {
|
274 | dispose: function dispose() {
|
275 | disposable.dispose();
|
276 | }
|
277 | };
|
278 | };
|
279 |
|
280 | _proto.getCacheEntry = function getCacheEntry(operation, fetchPolicy, maybeRenderPolicy) {
|
281 | var _maybeRenderPolicy2;
|
282 |
|
283 | var renderPolicy = (_maybeRenderPolicy2 = maybeRenderPolicy) !== null && _maybeRenderPolicy2 !== void 0 ? _maybeRenderPolicy2 : DEFAULT_RENDER_POLICY;
|
284 | var cacheKey = getQueryCacheKey(operation, fetchPolicy, renderPolicy);
|
285 | return this._cache.get(cacheKey);
|
286 | };
|
287 |
|
288 | _proto._getOrCreateCacheEntry = function _getOrCreateCacheEntry(cacheKey, operation, value, networkSubscription) {
|
289 | var cacheEntry = this._cache.get(cacheKey);
|
290 |
|
291 | if (cacheEntry == null) {
|
292 | cacheEntry = createCacheEntry(cacheKey, operation, value, networkSubscription, this._clearCacheEntry);
|
293 |
|
294 | this._cache.set(cacheKey, cacheEntry);
|
295 | }
|
296 |
|
297 | return cacheEntry;
|
298 | };
|
299 |
|
300 | _proto._fetchAndSaveQuery = function _fetchAndSaveQuery(cacheKey, operation, fetchObservable, fetchPolicy, renderPolicy, observer) {
|
301 | var _this2 = this;
|
302 |
|
303 | var environment = this._environment;
|
304 |
|
305 |
|
306 |
|
307 |
|
308 | var hasFullQuery = environment.check(operation.root);
|
309 | var canPartialRender = hasFullQuery || renderPolicy === 'partial';
|
310 | var shouldFetch;
|
311 | var shouldAllowRender;
|
312 |
|
313 | var resolveNetworkPromise = function resolveNetworkPromise() {};
|
314 |
|
315 | switch (fetchPolicy) {
|
316 | case 'store-only':
|
317 | {
|
318 | shouldFetch = false;
|
319 | shouldAllowRender = true;
|
320 | break;
|
321 | }
|
322 |
|
323 | case 'store-or-network':
|
324 | {
|
325 | shouldFetch = !hasFullQuery;
|
326 | shouldAllowRender = canPartialRender;
|
327 | break;
|
328 | }
|
329 |
|
330 | case 'store-and-network':
|
331 | {
|
332 | shouldFetch = true;
|
333 | shouldAllowRender = canPartialRender;
|
334 | break;
|
335 | }
|
336 |
|
337 | case 'network-only':
|
338 | default:
|
339 | {
|
340 | shouldFetch = true;
|
341 | shouldAllowRender = false;
|
342 | break;
|
343 | }
|
344 | }
|
345 |
|
346 |
|
347 |
|
348 |
|
349 |
|
350 | if (shouldAllowRender) {
|
351 | var queryResult = getQueryResult(operation, cacheKey);
|
352 |
|
353 | var _cacheEntry = createCacheEntry(cacheKey, operation, queryResult, null, this._clearCacheEntry);
|
354 |
|
355 | this._cache.set(cacheKey, _cacheEntry);
|
356 | }
|
357 |
|
358 | environment.__log({
|
359 | name: 'queryresource.fetch',
|
360 | operation: operation,
|
361 | fetchPolicy: fetchPolicy,
|
362 | renderPolicy: renderPolicy,
|
363 | hasFullQuery: hasFullQuery,
|
364 | shouldFetch: shouldFetch
|
365 | });
|
366 |
|
367 | if (shouldFetch) {
|
368 | var _queryResult = getQueryResult(operation, cacheKey);
|
369 |
|
370 | var networkSubscription;
|
371 | fetchObservable.subscribe({
|
372 | start: function start(subscription) {
|
373 | networkSubscription = subscription;
|
374 |
|
375 | var cacheEntry = _this2._cache.get(cacheKey);
|
376 |
|
377 | if (cacheEntry) {
|
378 | cacheEntry.setNetworkSubscription(networkSubscription);
|
379 | }
|
380 |
|
381 | var observerStart = observer === null || observer === void 0 ? void 0 : observer.start;
|
382 | observerStart && observerStart(subscription);
|
383 | },
|
384 | next: function next() {
|
385 | var snapshot = environment.lookup(operation.fragment);
|
386 |
|
387 | var cacheEntry = _this2._getOrCreateCacheEntry(cacheKey, operation, _queryResult, networkSubscription);
|
388 |
|
389 | cacheEntry.setValue(_queryResult);
|
390 | resolveNetworkPromise();
|
391 | var observerNext = observer === null || observer === void 0 ? void 0 : observer.next;
|
392 | observerNext && observerNext(snapshot);
|
393 | },
|
394 | error: function error(_error) {
|
395 | var cacheEntry = _this2._getOrCreateCacheEntry(cacheKey, operation, _error, networkSubscription);
|
396 |
|
397 | cacheEntry.setValue(_error);
|
398 | resolveNetworkPromise();
|
399 | networkSubscription = null;
|
400 | cacheEntry.setNetworkSubscription(null);
|
401 | var observerError = observer === null || observer === void 0 ? void 0 : observer.error;
|
402 | observerError && observerError(_error);
|
403 | },
|
404 | complete: function complete() {
|
405 | resolveNetworkPromise();
|
406 | networkSubscription = null;
|
407 |
|
408 | var cacheEntry = _this2._cache.get(cacheKey);
|
409 |
|
410 | if (cacheEntry) {
|
411 | cacheEntry.setNetworkSubscription(null);
|
412 | }
|
413 |
|
414 | var observerComplete = observer === null || observer === void 0 ? void 0 : observer.complete;
|
415 | observerComplete && observerComplete();
|
416 | },
|
417 | unsubscribe: observer === null || observer === void 0 ? void 0 : observer.unsubscribe
|
418 | });
|
419 |
|
420 | var _cacheEntry2 = this._cache.get(cacheKey);
|
421 |
|
422 | if (!_cacheEntry2) {
|
423 | var networkPromise = new Promise(function (resolve) {
|
424 | resolveNetworkPromise = resolve;
|
425 | });
|
426 |
|
427 | networkPromise.displayName = 'Relay(' + operation.fragment.node.name + ')';
|
428 | _cacheEntry2 = createCacheEntry(cacheKey, operation, networkPromise, networkSubscription, this._clearCacheEntry);
|
429 |
|
430 | this._cache.set(cacheKey, _cacheEntry2);
|
431 | }
|
432 | } else {
|
433 | var observerComplete = observer === null || observer === void 0 ? void 0 : observer.complete;
|
434 | observerComplete && observerComplete();
|
435 | }
|
436 |
|
437 | var cacheEntry = this._cache.get(cacheKey);
|
438 |
|
439 | !(cacheEntry != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Relay: Expected to have cached a result when attempting to fetch query.' + "If you're seeing this, this is likely a bug in Relay.") : invariant(false) : void 0;
|
440 | return cacheEntry;
|
441 | };
|
442 |
|
443 | return QueryResourceImpl;
|
444 | }();
|
445 |
|
446 | function createQueryResource(environment) {
|
447 | return new QueryResourceImpl(environment);
|
448 | }
|
449 |
|
450 | var dataResources = new Map();
|
451 |
|
452 | function getQueryResourceForEnvironment(environment) {
|
453 | var cached = dataResources.get(environment);
|
454 |
|
455 | if (cached) {
|
456 | return cached;
|
457 | }
|
458 |
|
459 | var newDataResource = createQueryResource(environment);
|
460 | dataResources.set(environment, newDataResource);
|
461 | return newDataResource;
|
462 | }
|
463 |
|
464 | module.exports = {
|
465 | createQueryResource: createQueryResource,
|
466 | getQueryResourceForEnvironment: getQueryResourceForEnvironment
|
467 | }; |
\ | No newline at end of file |