react-relay 0.0.0-main-c3ad9027 → 0.0.0-main-74926b6f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Relay v0.0.0-main-c3ad9027
2
+ * Relay v0.0.0-main-74926b6f
3
3
  *
4
4
  * Copyright (c) Facebook, Inc. and its affiliates.
5
5
  *
package/hooks.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Relay v0.0.0-main-c3ad9027
2
+ * Relay v0.0.0-main-74926b6f
3
3
  *
4
4
  * Copyright (c) Facebook, Inc. and its affiliates.
5
5
  *
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Relay v0.0.0-main-c3ad9027
2
+ * Relay v0.0.0-main-74926b6f
3
3
  *
4
4
  * Copyright (c) Facebook, Inc. and its affiliates.
5
5
  *
package/legacy.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Relay v0.0.0-main-c3ad9027
2
+ * Relay v0.0.0-main-74926b6f
3
3
  *
4
4
  * Copyright (c) Facebook, Inc. and its affiliates.
5
5
  *
@@ -15,19 +15,32 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
15
15
 
16
16
  var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
17
17
 
18
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
19
+
18
20
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
19
21
 
20
22
  var LRUCache = require('./LRUCache');
21
23
 
24
+ var _require = require('./QueryResource'),
25
+ getQueryResourceForEnvironment = _require.getQueryResourceForEnvironment;
26
+
27
+ var SuspenseResource = require('./SuspenseResource');
28
+
22
29
  var invariant = require('invariant');
23
30
 
24
- var _require = require('relay-runtime'),
25
- getFragmentIdentifier = _require.getFragmentIdentifier,
26
- getPendingOperationsForFragment = _require.getPendingOperationsForFragment,
27
- getSelector = _require.getSelector,
28
- isPromise = _require.isPromise,
29
- recycleNodesInto = _require.recycleNodesInto,
30
- reportMissingRequiredFields = _require.reportMissingRequiredFields;
31
+ var _require2 = require('relay-runtime'),
32
+ RelayFeatureFlags = _require2.RelayFeatureFlags,
33
+ _require2$__internal = _require2.__internal,
34
+ fetchQuery = _require2$__internal.fetchQuery,
35
+ getPromiseForActiveRequest = _require2$__internal.getPromiseForActiveRequest,
36
+ createOperationDescriptor = _require2.createOperationDescriptor,
37
+ getFragmentIdentifier = _require2.getFragmentIdentifier,
38
+ getPendingOperationsForFragment = _require2.getPendingOperationsForFragment,
39
+ getSelector = _require2.getSelector,
40
+ getVariablesFromFragment = _require2.getVariablesFromFragment,
41
+ isPromise = _require2.isPromise,
42
+ recycleNodesInto = _require2.recycleNodesInto,
43
+ reportMissingRequiredFields = _require2.reportMissingRequiredFields;
31
44
 
32
45
  var WEAKMAP_SUPPORTED = typeof WeakMap === 'function';
33
46
  // TODO: Fix to not rely on LRU. If the number of active fragments exceeds this
@@ -47,6 +60,28 @@ function isMissingData(snapshot) {
47
60
  return snapshot.isMissingData;
48
61
  }
49
62
 
63
+ function hasMissingClientEdges(snapshot) {
64
+ var _snapshot$missingClie, _snapshot$missingClie2;
65
+
66
+ if (Array.isArray(snapshot)) {
67
+ return snapshot.some(function (s) {
68
+ var _s$missingClientEdges, _s$missingClientEdges2;
69
+
70
+ return ((_s$missingClientEdges = (_s$missingClientEdges2 = s.missingClientEdges) === null || _s$missingClientEdges2 === void 0 ? void 0 : _s$missingClientEdges2.length) !== null && _s$missingClientEdges !== void 0 ? _s$missingClientEdges : 0) > 0;
71
+ });
72
+ }
73
+
74
+ return ((_snapshot$missingClie = (_snapshot$missingClie2 = snapshot.missingClientEdges) === null || _snapshot$missingClie2 === void 0 ? void 0 : _snapshot$missingClie2.length) !== null && _snapshot$missingClie !== void 0 ? _snapshot$missingClie : 0) > 0;
75
+ }
76
+
77
+ function singularOrPluralForEach(snapshot, f) {
78
+ if (Array.isArray(snapshot)) {
79
+ snapshot.forEach(f);
80
+ } else {
81
+ f(snapshot);
82
+ }
83
+ }
84
+
50
85
  function getFragmentResult(cacheKey, snapshot, storeEpoch) {
51
86
  if (Array.isArray(snapshot)) {
52
87
  return {
@@ -68,11 +103,90 @@ function getFragmentResult(cacheKey, snapshot, storeEpoch) {
68
103
  storeEpoch: storeEpoch
69
104
  };
70
105
  }
106
+ /**
107
+ * The purpose of this cache is to allow information to be passed from an
108
+ * initial read which suspends through to the commit that follows a subsequent
109
+ * successful read. Specifically, the QueryResource result for the data fetch
110
+ * is passed through so that that query can be retained on commit.
111
+ */
112
+
113
+
114
+ var ClientEdgeQueryResultsCache = /*#__PURE__*/function () {
115
+ function ClientEdgeQueryResultsCache(environment) {
116
+ (0, _defineProperty2["default"])(this, "_cache", new Map());
117
+ (0, _defineProperty2["default"])(this, "_retainCounts", new Map());
118
+ this._environment = environment;
119
+ }
120
+
121
+ var _proto = ClientEdgeQueryResultsCache.prototype;
122
+
123
+ _proto.get = function get(fragmentIdentifier) {
124
+ var _this$_cache$get$, _this$_cache$get;
125
+
126
+ return (_this$_cache$get$ = (_this$_cache$get = this._cache.get(fragmentIdentifier)) === null || _this$_cache$get === void 0 ? void 0 : _this$_cache$get[0]) !== null && _this$_cache$get$ !== void 0 ? _this$_cache$get$ : undefined;
127
+ };
128
+
129
+ _proto.recordQueryResults = function recordQueryResults(fragmentIdentifier, value) {
130
+ var _this = this;
131
+
132
+ var existing = this._cache.get(fragmentIdentifier);
133
+
134
+ if (!existing) {
135
+ var suspenseResource = new SuspenseResource(function () {
136
+ return _this._retain(fragmentIdentifier);
137
+ });
138
+
139
+ this._cache.set(fragmentIdentifier, [value, suspenseResource]);
140
+
141
+ suspenseResource.temporaryRetain(this._environment);
142
+ } else {
143
+ var existingResults = existing[0],
144
+ _suspenseResource = existing[1];
145
+ value.forEach(function (queryResult) {
146
+ existingResults.push(queryResult);
147
+ });
148
+
149
+ _suspenseResource.temporaryRetain(this._environment);
150
+ }
151
+ };
152
+
153
+ _proto._retain = function _retain(id) {
154
+ var _this2 = this;
155
+
156
+ var _this$_retainCounts$g;
157
+
158
+ var retainCount = ((_this$_retainCounts$g = this._retainCounts.get(id)) !== null && _this$_retainCounts$g !== void 0 ? _this$_retainCounts$g : 0) + 1;
159
+
160
+ this._retainCounts.set(id, retainCount);
161
+
162
+ return {
163
+ dispose: function dispose() {
164
+ var _this$_retainCounts$g2;
165
+
166
+ var newRetainCount = ((_this$_retainCounts$g2 = _this2._retainCounts.get(id)) !== null && _this$_retainCounts$g2 !== void 0 ? _this$_retainCounts$g2 : 0) - 1;
167
+
168
+ if (newRetainCount > 0) {
169
+ _this2._retainCounts.set(id, newRetainCount);
170
+ } else {
171
+ _this2._retainCounts["delete"](id);
172
+
173
+ _this2._cache["delete"](id);
174
+ }
175
+ }
176
+ };
177
+ };
178
+
179
+ return ClientEdgeQueryResultsCache;
180
+ }();
71
181
 
72
182
  var FragmentResourceImpl = /*#__PURE__*/function () {
73
183
  function FragmentResourceImpl(environment) {
74
184
  this._environment = environment;
75
185
  this._cache = LRUCache.create(CACHE_CAPACITY);
186
+
187
+ if (RelayFeatureFlags.ENABLE_CLIENT_EDGES) {
188
+ this._clientEdgeQueryResultsCache = new ClientEdgeQueryResultsCache(environment);
189
+ }
76
190
  }
77
191
  /**
78
192
  * This function should be called during a Component's render function,
@@ -81,9 +195,9 @@ var FragmentResourceImpl = /*#__PURE__*/function () {
81
195
  */
82
196
 
83
197
 
84
- var _proto = FragmentResourceImpl.prototype;
198
+ var _proto2 = FragmentResourceImpl.prototype;
85
199
 
86
- _proto.read = function read(fragmentNode, fragmentRef, componentDisplayName, fragmentKey) {
200
+ _proto2.read = function read(fragmentNode, fragmentRef, componentDisplayName, fragmentKey) {
87
201
  return this.readWithIdentifier(fragmentNode, fragmentRef, getFragmentIdentifier(fragmentNode, fragmentRef), componentDisplayName, fragmentKey);
88
202
  }
89
203
  /**
@@ -93,8 +207,10 @@ var FragmentResourceImpl = /*#__PURE__*/function () {
93
207
  */
94
208
  ;
95
209
 
96
- _proto.readWithIdentifier = function readWithIdentifier(fragmentNode, fragmentRef, fragmentIdentifier, componentDisplayName, fragmentKey) {
97
- var _fragmentNode$metadat;
210
+ _proto2.readWithIdentifier = function readWithIdentifier(fragmentNode, fragmentRef, fragmentIdentifier, componentDisplayName, fragmentKey) {
211
+ var _this3 = this;
212
+
213
+ var _fragmentNode$metadat, _clientEdgePromises;
98
214
 
99
215
  var environment = this._environment; // If fragmentRef is null or undefined, pass it directly through.
100
216
  // This is a convenience when consuming fragments via a HOC API, when the
@@ -171,18 +287,67 @@ var FragmentResourceImpl = /*#__PURE__*/function () {
171
287
  });
172
288
 
173
289
  return fragmentResult;
174
- } // 3. If we don't have data in the store, check if a request is in
175
- // flight for the fragment's parent query, or for another operation
176
- // that may affect the parent's query data, such as a mutation
177
- // or subscription. If a promise exists, cache the promise and use it
178
- // to suspend.
290
+ } // 3. If we don't have data in the store, there's two cases where we should
291
+ // suspend to await the data: First if any client edges were traversed where
292
+ // the destination record was missing data; in that case we initiate a query
293
+ // here to fetch the missing data. Second, there may already be a request
294
+ // in flight for the fragment's parent query, or for another operation that
295
+ // may affect the parent's query data, such as a mutation or subscription.
296
+ // For any of these cases we can get a promise, which we will cache and
297
+ // suspend on.
298
+ // First, initiate a query for any client edges that were missing data:
299
+
300
+
301
+ var clientEdgeRequests = null;
302
+
303
+ if (RelayFeatureFlags.ENABLE_CLIENT_EDGES && hasMissingClientEdges(snapshot)) {
304
+ clientEdgeRequests = [];
305
+ var queryResource = getQueryResourceForEnvironment(this._environment);
306
+ var queryResults = [];
307
+ singularOrPluralForEach(snapshot, function (snap) {
308
+ var _snap$missingClientEd;
309
+
310
+ (_snap$missingClientEd = snap.missingClientEdges) === null || _snap$missingClientEd === void 0 ? void 0 : _snap$missingClientEd.forEach(function (_ref) {
311
+ var _clientEdgeRequests;
312
+
313
+ var request = _ref.request,
314
+ clientEdgeDestinationID = _ref.clientEdgeDestinationID;
315
+
316
+ var _this3$_performClient = _this3._performClientEdgeQuery(queryResource, fragmentNode, fragmentRef, request, clientEdgeDestinationID),
317
+ queryResult = _this3$_performClient.queryResult,
318
+ requestDescriptor = _this3$_performClient.requestDescriptor;
319
+
320
+ queryResults.push(queryResult);
321
+ (_clientEdgeRequests = clientEdgeRequests) === null || _clientEdgeRequests === void 0 ? void 0 : _clientEdgeRequests.push(requestDescriptor);
322
+ });
323
+ }); // Store the query so that it can be retained when our own fragment is
324
+ // subscribed to. This merges with any existing query results:
325
+
326
+ !(this._clientEdgeQueryResultsCache != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Client edge query result cache should exist when ENABLE_CLIENT_EDGES is on.') : invariant(false) : void 0;
327
+
328
+ this._clientEdgeQueryResultsCache.recordQueryResults(fragmentIdentifier, queryResults);
329
+ }
330
+
331
+ var clientEdgePromises = null;
332
+
333
+ if (RelayFeatureFlags.ENABLE_CLIENT_EDGES && clientEdgeRequests) {
334
+ clientEdgePromises = clientEdgeRequests.map(function (request) {
335
+ return getPromiseForActiveRequest(_this3._environment, request);
336
+ }).filter(function (p) {
337
+ return p != null;
338
+ });
339
+ } // Finally look for operations in flight for our parent query:
179
340
 
180
341
 
181
342
  var fragmentOwner = fragmentSelector.kind === 'PluralReaderSelector' ? fragmentSelector.selectors[0].owner : fragmentSelector.owner;
182
343
 
183
- var networkPromiseResult = this._getAndSavePromiseForFragmentRequestInFlight(fragmentIdentifier, fragmentNode, fragmentOwner, fragmentResult);
344
+ var parentQueryPromiseResult = this._getAndSavePromiseForFragmentRequestInFlight(fragmentIdentifier, fragmentNode, fragmentOwner, fragmentResult);
345
+
346
+ var parentQueryPromiseResultPromise = parentQueryPromiseResult === null || parentQueryPromiseResult === void 0 ? void 0 : parentQueryPromiseResult.promise; // for refinement
347
+
348
+ if (((_clientEdgePromises = clientEdgePromises) === null || _clientEdgePromises === void 0 ? void 0 : _clientEdgePromises.length) || isPromise(parentQueryPromiseResultPromise)) {
349
+ var _parentQueryPromiseRe, _clientEdgeRequests2, _clientEdgePromises2;
184
350
 
185
- if (networkPromiseResult != null && isPromise(networkPromiseResult.promise)) {
186
351
  environment.__log({
187
352
  name: 'suspense.fragment',
188
353
  data: fragmentResult.data,
@@ -190,10 +355,10 @@ var FragmentResourceImpl = /*#__PURE__*/function () {
190
355
  isRelayHooks: true,
191
356
  isPromiseCached: false,
192
357
  isMissingData: fragmentResult.isMissingData,
193
- pendingOperations: networkPromiseResult.pendingOperations
358
+ pendingOperations: [].concat((0, _toConsumableArray2["default"])((_parentQueryPromiseRe = parentQueryPromiseResult === null || parentQueryPromiseResult === void 0 ? void 0 : parentQueryPromiseResult.pendingOperations) !== null && _parentQueryPromiseRe !== void 0 ? _parentQueryPromiseRe : []), (0, _toConsumableArray2["default"])((_clientEdgeRequests2 = clientEdgeRequests) !== null && _clientEdgeRequests2 !== void 0 ? _clientEdgeRequests2 : []))
194
359
  });
195
360
 
196
- throw networkPromiseResult.promise;
361
+ throw ((_clientEdgePromises2 = clientEdgePromises) === null || _clientEdgePromises2 === void 0 ? void 0 : _clientEdgePromises2.length) ? Promise.all([parentQueryPromiseResultPromise].concat((0, _toConsumableArray2["default"])(clientEdgePromises))) : parentQueryPromiseResultPromise;
197
362
  }
198
363
 
199
364
  this._reportMissingRequiredFieldsInSnapshot(snapshot);
@@ -201,13 +366,30 @@ var FragmentResourceImpl = /*#__PURE__*/function () {
201
366
  return getFragmentResult(fragmentIdentifier, snapshot, storeEpoch);
202
367
  };
203
368
 
204
- _proto._reportMissingRequiredFieldsInSnapshot = function _reportMissingRequiredFieldsInSnapshot(snapshot) {
205
- var _this = this;
369
+ _proto2._performClientEdgeQuery = function _performClientEdgeQuery(queryResource, fragmentNode, fragmentRef, request, clientEdgeDestinationID) {
370
+ var originalVariables = getVariablesFromFragment(fragmentNode, fragmentRef);
371
+ var variables = (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, originalVariables), {}, {
372
+ id: clientEdgeDestinationID // TODO should be a reserved name
373
+
374
+ });
375
+ var operation = createOperationDescriptor(request, variables, {} // TODO cacheConfig should probably inherent from parent operation
376
+ );
377
+ var fetchObservable = fetchQuery(this._environment, operation);
378
+ var queryResult = queryResource.prepare(operation, fetchObservable // TODO should inherent render policy etc. from parent operation
379
+ );
380
+ return {
381
+ requestDescriptor: operation.request,
382
+ queryResult: queryResult
383
+ };
384
+ };
385
+
386
+ _proto2._reportMissingRequiredFieldsInSnapshot = function _reportMissingRequiredFieldsInSnapshot(snapshot) {
387
+ var _this4 = this;
206
388
 
207
389
  if (Array.isArray(snapshot)) {
208
390
  snapshot.forEach(function (s) {
209
391
  if (s.missingRequiredFields != null) {
210
- reportMissingRequiredFields(_this._environment, s.missingRequiredFields);
392
+ reportMissingRequiredFields(_this4._environment, s.missingRequiredFields);
211
393
  }
212
394
  });
213
395
  } else {
@@ -217,7 +399,7 @@ var FragmentResourceImpl = /*#__PURE__*/function () {
217
399
  }
218
400
  };
219
401
 
220
- _proto.readSpec = function readSpec(fragmentNodes, fragmentRefs, componentDisplayName) {
402
+ _proto2.readSpec = function readSpec(fragmentNodes, fragmentRefs, componentDisplayName) {
221
403
  var result = {};
222
404
 
223
405
  for (var _key in fragmentNodes) {
@@ -227,8 +409,8 @@ var FragmentResourceImpl = /*#__PURE__*/function () {
227
409
  return result;
228
410
  };
229
411
 
230
- _proto.subscribe = function subscribe(fragmentResult, callback) {
231
- var _this2 = this;
412
+ _proto2.subscribe = function subscribe(fragmentResult, callback) {
413
+ var _this5 = this;
232
414
 
233
415
  var environment = this._environment;
234
416
  var cacheKey = fragmentResult.cacheKey;
@@ -253,25 +435,25 @@ var FragmentResourceImpl = /*#__PURE__*/function () {
253
435
  } // 3. Establish subscriptions on the snapshot(s)
254
436
 
255
437
 
256
- var dataSubscriptions = [];
438
+ var disposables = [];
257
439
 
258
440
  if (Array.isArray(renderedSnapshot)) {
259
441
  !Array.isArray(currentSnapshot) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Relay: Expected snapshots to be plural. ' + "If you're seeing this, this is likely a bug in Relay.") : invariant(false) : void 0;
260
442
  currentSnapshot.forEach(function (snapshot, idx) {
261
- dataSubscriptions.push(environment.subscribe(snapshot, function (latestSnapshot) {
443
+ disposables.push(environment.subscribe(snapshot, function (latestSnapshot) {
262
444
  var storeEpoch = environment.getStore().getEpoch();
263
445
 
264
- _this2._updatePluralSnapshot(cacheKey, currentSnapshot, latestSnapshot, idx, storeEpoch);
446
+ _this5._updatePluralSnapshot(cacheKey, currentSnapshot, latestSnapshot, idx, storeEpoch);
265
447
 
266
448
  callback();
267
449
  }));
268
450
  });
269
451
  } else {
270
452
  !(currentSnapshot != null && !Array.isArray(currentSnapshot)) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Relay: Expected snapshot to be singular. ' + "If you're seeing this, this is likely a bug in Relay.") : invariant(false) : void 0;
271
- dataSubscriptions.push(environment.subscribe(currentSnapshot, function (latestSnapshot) {
453
+ disposables.push(environment.subscribe(currentSnapshot, function (latestSnapshot) {
272
454
  var storeEpoch = environment.getStore().getEpoch();
273
455
 
274
- _this2._cache.set(cacheKey, {
456
+ _this5._cache.set(cacheKey, {
275
457
  kind: 'done',
276
458
  result: getFragmentResult(cacheKey, latestSnapshot, storeEpoch)
277
459
  });
@@ -280,22 +462,35 @@ var FragmentResourceImpl = /*#__PURE__*/function () {
280
462
  }));
281
463
  }
282
464
 
465
+ if (RelayFeatureFlags.ENABLE_CLIENT_EDGES) {
466
+ var _this$_clientEdgeQuer, _this$_clientEdgeQuer2;
467
+
468
+ var clientEdgeQueryResults = (_this$_clientEdgeQuer = (_this$_clientEdgeQuer2 = this._clientEdgeQueryResultsCache) === null || _this$_clientEdgeQuer2 === void 0 ? void 0 : _this$_clientEdgeQuer2.get(cacheKey)) !== null && _this$_clientEdgeQuer !== void 0 ? _this$_clientEdgeQuer : undefined;
469
+
470
+ if (clientEdgeQueryResults === null || clientEdgeQueryResults === void 0 ? void 0 : clientEdgeQueryResults.length) {
471
+ var queryResource = getQueryResourceForEnvironment(this._environment);
472
+ clientEdgeQueryResults.forEach(function (queryResult) {
473
+ disposables.push(queryResource.retain(queryResult));
474
+ });
475
+ }
476
+ }
477
+
283
478
  return {
284
479
  dispose: function dispose() {
285
- dataSubscriptions.map(function (s) {
480
+ disposables.forEach(function (s) {
286
481
  return s.dispose();
287
482
  });
288
483
 
289
- _this2._cache["delete"](cacheKey);
484
+ _this5._cache["delete"](cacheKey);
290
485
  }
291
486
  };
292
487
  };
293
488
 
294
- _proto.subscribeSpec = function subscribeSpec(fragmentResults, callback) {
295
- var _this3 = this;
489
+ _proto2.subscribeSpec = function subscribeSpec(fragmentResults, callback) {
490
+ var _this6 = this;
296
491
 
297
492
  var disposables = Object.keys(fragmentResults).map(function (key) {
298
- return _this3.subscribe(fragmentResults[key], callback);
493
+ return _this6.subscribe(fragmentResults[key], callback);
299
494
  });
300
495
  return {
301
496
  dispose: function dispose() {
@@ -306,7 +501,7 @@ var FragmentResourceImpl = /*#__PURE__*/function () {
306
501
  };
307
502
  };
308
503
 
309
- _proto.checkMissedUpdates = function checkMissedUpdates(fragmentResult) {
504
+ _proto2.checkMissedUpdates = function checkMissedUpdates(fragmentResult) {
310
505
  var environment = this._environment;
311
506
  var renderedSnapshot = fragmentResult.snapshot;
312
507
 
@@ -361,6 +556,7 @@ var FragmentResourceImpl = /*#__PURE__*/function () {
361
556
  var updatedCurrentSnapshot = {
362
557
  data: updatedData,
363
558
  isMissingData: currentSnapshot.isMissingData,
559
+ missingClientEdges: currentSnapshot.missingClientEdges,
364
560
  seenRecords: currentSnapshot.seenRecords,
365
561
  selector: currentSnapshot.selector,
366
562
  missingRequiredFields: currentSnapshot.missingRequiredFields
@@ -376,16 +572,16 @@ var FragmentResourceImpl = /*#__PURE__*/function () {
376
572
  return [updatedData !== renderData, updatedCurrentSnapshot];
377
573
  };
378
574
 
379
- _proto.checkMissedUpdatesSpec = function checkMissedUpdatesSpec(fragmentResults) {
380
- var _this4 = this;
575
+ _proto2.checkMissedUpdatesSpec = function checkMissedUpdatesSpec(fragmentResults) {
576
+ var _this7 = this;
381
577
 
382
578
  return Object.keys(fragmentResults).some(function (key) {
383
- return _this4.checkMissedUpdates(fragmentResults[key])[0];
579
+ return _this7.checkMissedUpdates(fragmentResults[key])[0];
384
580
  });
385
581
  };
386
582
 
387
- _proto._getAndSavePromiseForFragmentRequestInFlight = function _getAndSavePromiseForFragmentRequestInFlight(cacheKey, fragmentNode, fragmentOwner, fragmentResult) {
388
- var _this5 = this;
583
+ _proto2._getAndSavePromiseForFragmentRequestInFlight = function _getAndSavePromiseForFragmentRequestInFlight(cacheKey, fragmentNode, fragmentOwner, fragmentResult) {
584
+ var _this8 = this;
389
585
 
390
586
  var pendingOperationsResult = getPendingOperationsForFragment(this._environment, fragmentNode, fragmentOwner);
391
587
 
@@ -399,9 +595,9 @@ var FragmentResourceImpl = /*#__PURE__*/function () {
399
595
  var networkPromise = pendingOperationsResult.promise;
400
596
  var pendingOperations = pendingOperationsResult.pendingOperations;
401
597
  var promise = networkPromise.then(function () {
402
- _this5._cache["delete"](cacheKey);
598
+ _this8._cache["delete"](cacheKey);
403
599
  })["catch"](function (error) {
404
- _this5._cache["delete"](cacheKey);
600
+ _this8._cache["delete"](cacheKey);
405
601
  }); // $FlowExpectedError[prop-missing] Expando to annotate Promises.
406
602
 
407
603
  promise.displayName = networkPromise.displayName;
@@ -419,7 +615,7 @@ var FragmentResourceImpl = /*#__PURE__*/function () {
419
615
  };
420
616
  };
421
617
 
422
- _proto._updatePluralSnapshot = function _updatePluralSnapshot(cacheKey, baseSnapshots, latestSnapshot, idx, storeEpoch) {
618
+ _proto2._updatePluralSnapshot = function _updatePluralSnapshot(cacheKey, baseSnapshots, latestSnapshot, idx, storeEpoch) {
423
619
  var _currentFragmentResul;
424
620
 
425
621
  var currentFragmentResult = this._cache.get(cacheKey);
@@ -19,16 +19,18 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
19
19
 
20
20
  var LRUCache = require('./LRUCache');
21
21
 
22
+ var SuspenseResource = require('./SuspenseResource');
23
+
22
24
  var invariant = require('invariant');
23
25
 
24
26
  var _require = require('relay-runtime'),
27
+ RelayFeatureFlags = _require.RelayFeatureFlags,
25
28
  isPromise = _require.isPromise;
26
29
 
27
30
  var warning = require("fbjs/lib/warning");
28
31
 
29
32
  var CACHE_CAPACITY = 1000;
30
33
  var DEFAULT_FETCH_POLICY = 'store-or-network';
31
- var DATA_RETENTION_TIMEOUT = 5 * 60 * 1000;
32
34
  var WEAKMAP_SUPPORTED = typeof WeakMap === 'function';
33
35
 
34
36
  function operationIsLiveQuery(operation) {
@@ -64,6 +66,77 @@ function getQueryResult(operation, cacheIdentifier) {
64
66
  var nextID = 200000;
65
67
 
66
68
  function createCacheEntry(cacheIdentifier, operation, operationAvailability, value, networkSubscription, onDispose) {
69
+ // There should be no behavior difference between createCacheEntry_new and
70
+ // createCacheEntry_old, and it doesn't directly relate to Client Edges.
71
+ // It was just a refactoring that was needed for Client Edges but that
72
+ // is behind the feature flag just in case there is any accidental breakage.
73
+ if (RelayFeatureFlags.REFACTOR_SUSPENSE_RESOURCE) {
74
+ return createCacheEntry_new(cacheIdentifier, operation, operationAvailability, value, networkSubscription, onDispose);
75
+ } else {
76
+ return createCacheEntry_old(cacheIdentifier, operation, operationAvailability, value, networkSubscription, onDispose);
77
+ }
78
+ }
79
+
80
+ function createCacheEntry_new(cacheIdentifier, operation, operationAvailability, value, networkSubscription, onDispose) {
81
+ var isLiveQuery = operationIsLiveQuery(operation);
82
+ var currentValue = value;
83
+ var currentNetworkSubscription = networkSubscription;
84
+ var suspenseResource = new SuspenseResource(function (environment) {
85
+ var retention = environment.retain(operation);
86
+ return {
87
+ dispose: function dispose() {
88
+ // Normally if this entry never commits, the request would've ended by the
89
+ // time this timeout expires and the temporary retain is released. However,
90
+ // we need to do this for live queries which remain open indefinitely.
91
+ if (isLiveQuery && currentNetworkSubscription != null) {
92
+ currentNetworkSubscription.unsubscribe();
93
+ }
94
+
95
+ retention.dispose();
96
+ onDispose(cacheEntry);
97
+ }
98
+ };
99
+ });
100
+ var cacheEntry = {
101
+ cacheIdentifier: cacheIdentifier,
102
+ id: nextID++,
103
+ processedPayloadsCount: 0,
104
+ operationAvailability: operationAvailability,
105
+ getValue: function getValue() {
106
+ return currentValue;
107
+ },
108
+ setValue: function setValue(val) {
109
+ currentValue = val;
110
+ },
111
+ getRetainCount: function getRetainCount() {
112
+ return suspenseResource.getRetainCount();
113
+ },
114
+ getNetworkSubscription: function getNetworkSubscription() {
115
+ return currentNetworkSubscription;
116
+ },
117
+ setNetworkSubscription: function setNetworkSubscription(subscription) {
118
+ if (isLiveQuery && currentNetworkSubscription != null) {
119
+ currentNetworkSubscription.unsubscribe();
120
+ }
121
+
122
+ currentNetworkSubscription = subscription;
123
+ },
124
+ temporaryRetain: function temporaryRetain(environment) {
125
+ return suspenseResource.temporaryRetain(environment);
126
+ },
127
+ permanentRetain: function permanentRetain(environment) {
128
+ return suspenseResource.permanentRetain(environment);
129
+ },
130
+ releaseTemporaryRetain: function releaseTemporaryRetain() {
131
+ suspenseResource.releaseTemporaryRetain();
132
+ }
133
+ };
134
+ return cacheEntry;
135
+ }
136
+
137
+ var DATA_RETENTION_TIMEOUT = 5 * 60 * 1000;
138
+
139
+ function createCacheEntry_old(cacheIdentifier, operation, operationAvailability, value, networkSubscription, onDispose) {
67
140
  var isLiveQuery = operationIsLiveQuery(operation);
68
141
  var currentValue = value;
69
142
  var retainCount = 0;
@@ -202,8 +275,14 @@ var QueryResourceImpl = /*#__PURE__*/function () {
202
275
  var _this = this;
203
276
 
204
277
  (0, _defineProperty2["default"])(this, "_clearCacheEntry", function (cacheEntry) {
205
- if (cacheEntry.getRetainCount() <= 0) {
278
+ // The new code does this retainCount <= 0 check within SuspenseResource
279
+ // before calling _clearCacheEntry, whereas with the old code we do it here.
280
+ if (RelayFeatureFlags.REFACTOR_SUSPENSE_RESOURCE) {
206
281
  _this._cache["delete"](cacheEntry.cacheIdentifier);
282
+ } else {
283
+ if (cacheEntry.getRetainCount() <= 0) {
284
+ _this._cache["delete"](cacheEntry.cacheIdentifier);
285
+ }
207
286
  }
208
287
  });
209
288
  this._environment = environment;