relay-runtime 11.0.1 → 13.0.0-rc.1

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.
Files changed (169) hide show
  1. package/handlers/RelayDefaultHandlerProvider.js.flow +2 -2
  2. package/handlers/connection/ConnectionHandler.js.flow +8 -17
  3. package/handlers/connection/MutationHandlers.js.flow +7 -11
  4. package/index.js +1 -1
  5. package/index.js.flow +60 -36
  6. package/lib/handlers/RelayDefaultHandlerProvider.js +1 -1
  7. package/lib/handlers/connection/ConnectionHandler.js +13 -19
  8. package/lib/handlers/connection/MutationHandlers.js +4 -7
  9. package/lib/index.js +58 -43
  10. package/lib/multi-actor-environment/ActorIdentifier.js +33 -0
  11. package/lib/multi-actor-environment/ActorSpecificEnvironment.js +152 -0
  12. package/lib/multi-actor-environment/ActorUtils.js +27 -0
  13. package/lib/multi-actor-environment/MultiActorEnvironment.js +419 -0
  14. package/lib/multi-actor-environment/MultiActorEnvironmentTypes.js +11 -0
  15. package/lib/multi-actor-environment/index.js +21 -0
  16. package/lib/mutations/RelayDeclarativeMutationConfig.js +4 -1
  17. package/lib/mutations/RelayRecordProxy.js +3 -2
  18. package/lib/mutations/RelayRecordSourceMutator.js +3 -2
  19. package/lib/mutations/RelayRecordSourceProxy.js +12 -4
  20. package/lib/mutations/RelayRecordSourceSelectorProxy.js +18 -5
  21. package/lib/mutations/applyOptimisticMutation.js +6 -6
  22. package/lib/mutations/commitMutation.js +14 -10
  23. package/lib/mutations/readUpdatableQuery_EXPERIMENTAL.js +238 -0
  24. package/lib/mutations/validateMutation.js +10 -5
  25. package/lib/network/ConvertToExecuteFunction.js +2 -1
  26. package/lib/network/RelayNetwork.js +3 -2
  27. package/lib/network/RelayQueryResponseCache.js +21 -5
  28. package/lib/network/wrapNetworkWithLogObserver.js +79 -0
  29. package/lib/query/GraphQLTag.js +3 -2
  30. package/lib/query/fetchQuery.js +6 -5
  31. package/lib/query/fetchQueryInternal.js +1 -1
  32. package/lib/query/fetchQuery_DEPRECATED.js +2 -1
  33. package/lib/store/ClientID.js +7 -1
  34. package/lib/store/DataChecker.js +123 -54
  35. package/lib/store/{RelayModernQueryExecutor.js → OperationExecutor.js} +518 -200
  36. package/lib/store/RelayConcreteVariables.js +26 -8
  37. package/lib/store/RelayExperimentalGraphResponseHandler.js +153 -0
  38. package/lib/store/RelayExperimentalGraphResponseTransform.js +391 -0
  39. package/lib/store/RelayModernEnvironment.js +175 -240
  40. package/lib/store/RelayModernFragmentSpecResolver.js +52 -26
  41. package/lib/store/RelayModernOperationDescriptor.js +2 -1
  42. package/lib/store/RelayModernRecord.js +47 -12
  43. package/lib/store/RelayModernSelector.js +14 -8
  44. package/lib/store/RelayModernStore.js +56 -28
  45. package/lib/store/RelayOperationTracker.js +34 -24
  46. package/lib/store/RelayPublishQueue.js +41 -13
  47. package/lib/store/RelayReader.js +288 -48
  48. package/lib/store/RelayRecordSource.js +87 -3
  49. package/lib/store/RelayReferenceMarker.js +34 -22
  50. package/lib/store/RelayResponseNormalizer.js +211 -110
  51. package/lib/store/RelayStoreReactFlightUtils.js +4 -10
  52. package/lib/store/RelayStoreSubscriptions.js +14 -9
  53. package/lib/store/RelayStoreUtils.js +12 -7
  54. package/lib/store/ResolverCache.js +213 -0
  55. package/lib/store/ResolverFragments.js +61 -0
  56. package/lib/store/cloneRelayHandleSourceField.js +5 -4
  57. package/lib/store/cloneRelayScalarHandleSourceField.js +5 -4
  58. package/lib/store/createRelayContext.js +4 -2
  59. package/lib/store/readInlineData.js +6 -2
  60. package/lib/subscription/requestSubscription.js +34 -25
  61. package/lib/util/RelayConcreteNode.js +3 -0
  62. package/lib/util/RelayFeatureFlags.js +10 -4
  63. package/lib/util/RelayProfiler.js +17 -187
  64. package/lib/util/RelayReplaySubject.js +22 -7
  65. package/lib/util/RelayRuntimeTypes.js +0 -6
  66. package/lib/util/StringInterner.js +71 -0
  67. package/lib/util/getFragmentIdentifier.js +15 -7
  68. package/lib/util/getOperation.js +2 -1
  69. package/lib/util/getPaginationMetadata.js +41 -0
  70. package/lib/util/getPaginationVariables.js +66 -0
  71. package/lib/util/getPendingOperationsForFragment.js +55 -0
  72. package/lib/util/getRefetchMetadata.js +36 -0
  73. package/lib/util/getRelayHandleKey.js +2 -2
  74. package/lib/util/getRequestIdentifier.js +2 -2
  75. package/lib/util/getValueAtPath.js +51 -0
  76. package/lib/util/isEmptyObject.js +1 -1
  77. package/lib/util/registerEnvironmentWithDevTools.js +26 -0
  78. package/lib/util/withDuration.js +31 -0
  79. package/multi-actor-environment/ActorIdentifier.js.flow +43 -0
  80. package/multi-actor-environment/ActorSpecificEnvironment.js.flow +225 -0
  81. package/multi-actor-environment/ActorUtils.js.flow +33 -0
  82. package/multi-actor-environment/MultiActorEnvironment.js.flow +506 -0
  83. package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +261 -0
  84. package/multi-actor-environment/index.js.flow +26 -0
  85. package/mutations/RelayDeclarativeMutationConfig.js.flow +32 -26
  86. package/mutations/RelayRecordProxy.js.flow +4 -5
  87. package/mutations/RelayRecordSourceMutator.js.flow +4 -6
  88. package/mutations/RelayRecordSourceProxy.js.flow +19 -10
  89. package/mutations/RelayRecordSourceSelectorProxy.js.flow +22 -7
  90. package/mutations/applyOptimisticMutation.js.flow +13 -14
  91. package/mutations/commitLocalUpdate.js.flow +1 -1
  92. package/mutations/commitMutation.js.flow +35 -46
  93. package/mutations/readUpdatableQuery_EXPERIMENTAL.js.flow +309 -0
  94. package/mutations/validateMutation.js.flow +26 -16
  95. package/network/ConvertToExecuteFunction.js.flow +2 -2
  96. package/network/RelayNetwork.js.flow +4 -5
  97. package/network/RelayNetworkTypes.js.flow +5 -4
  98. package/network/RelayObservable.js.flow +1 -1
  99. package/network/RelayQueryResponseCache.js.flow +34 -21
  100. package/network/wrapNetworkWithLogObserver.js.flow +100 -0
  101. package/package.json +3 -2
  102. package/query/GraphQLTag.js.flow +9 -9
  103. package/query/PreloadableQueryRegistry.js.flow +2 -1
  104. package/query/fetchQuery.js.flow +11 -13
  105. package/query/fetchQueryInternal.js.flow +6 -9
  106. package/query/fetchQuery_DEPRECATED.js.flow +6 -6
  107. package/relay-runtime.js +2 -2
  108. package/relay-runtime.min.js +2 -2
  109. package/store/ClientID.js.flow +14 -3
  110. package/store/DataChecker.js.flow +141 -59
  111. package/store/{RelayModernQueryExecutor.js.flow → OperationExecutor.js.flow} +605 -303
  112. package/store/RelayConcreteVariables.js.flow +27 -8
  113. package/store/RelayExperimentalGraphResponseHandler.js.flow +124 -0
  114. package/store/RelayExperimentalGraphResponseTransform.js.flow +475 -0
  115. package/store/RelayModernEnvironment.js.flow +173 -240
  116. package/store/RelayModernFragmentSpecResolver.js.flow +55 -31
  117. package/store/RelayModernOperationDescriptor.js.flow +12 -7
  118. package/store/RelayModernRecord.js.flow +67 -11
  119. package/store/RelayModernSelector.js.flow +24 -14
  120. package/store/RelayModernStore.js.flow +66 -36
  121. package/store/RelayOperationTracker.js.flow +59 -43
  122. package/store/RelayOptimisticRecordSource.js.flow +2 -2
  123. package/store/RelayPublishQueue.js.flow +79 -34
  124. package/store/RelayReader.js.flow +351 -73
  125. package/store/RelayRecordSource.js.flow +72 -6
  126. package/store/RelayReferenceMarker.js.flow +40 -26
  127. package/store/RelayResponseNormalizer.js.flow +258 -99
  128. package/store/RelayStoreReactFlightUtils.js.flow +4 -11
  129. package/store/RelayStoreSubscriptions.js.flow +19 -11
  130. package/store/RelayStoreTypes.js.flow +209 -43
  131. package/store/RelayStoreUtils.js.flow +24 -11
  132. package/store/ResolverCache.js.flow +249 -0
  133. package/store/ResolverFragments.js.flow +121 -0
  134. package/store/StoreInspector.js.flow +2 -2
  135. package/store/TypeID.js.flow +1 -1
  136. package/store/ViewerPattern.js.flow +2 -2
  137. package/store/cloneRelayHandleSourceField.js.flow +5 -6
  138. package/store/cloneRelayScalarHandleSourceField.js.flow +5 -6
  139. package/store/createFragmentSpecResolver.js.flow +3 -4
  140. package/store/createRelayContext.js.flow +3 -3
  141. package/store/normalizeRelayPayload.js.flow +6 -7
  142. package/store/readInlineData.js.flow +7 -8
  143. package/subscription/requestSubscription.js.flow +53 -41
  144. package/util/NormalizationNode.js.flow +10 -3
  145. package/util/ReaderNode.js.flow +38 -2
  146. package/util/RelayConcreteNode.js.flow +5 -0
  147. package/util/RelayFeatureFlags.js.flow +24 -10
  148. package/util/RelayProfiler.js.flow +22 -194
  149. package/util/RelayReplaySubject.js.flow +9 -9
  150. package/util/RelayRuntimeTypes.js.flow +72 -3
  151. package/util/StringInterner.js.flow +69 -0
  152. package/util/createPayloadFor3DField.js.flow +3 -3
  153. package/util/getFragmentIdentifier.js.flow +27 -15
  154. package/util/getOperation.js.flow +2 -2
  155. package/util/getPaginationMetadata.js.flow +72 -0
  156. package/util/getPaginationVariables.js.flow +108 -0
  157. package/util/getPendingOperationsForFragment.js.flow +62 -0
  158. package/util/getRefetchMetadata.js.flow +79 -0
  159. package/util/getRelayHandleKey.js.flow +1 -2
  160. package/util/getRequestIdentifier.js.flow +3 -3
  161. package/util/getValueAtPath.js.flow +46 -0
  162. package/util/isEmptyObject.js.flow +1 -0
  163. package/util/registerEnvironmentWithDevTools.js.flow +33 -0
  164. package/util/resolveImmediate.js.flow +1 -1
  165. package/util/withDuration.js.flow +32 -0
  166. package/lib/store/RelayRecordSourceMapImpl.js +0 -107
  167. package/lib/store/RelayStoreSubscriptionsUsingMapByID.js +0 -318
  168. package/store/RelayRecordSourceMapImpl.js.flow +0 -91
  169. package/store/RelayStoreSubscriptionsUsingMapByID.js.flow +0 -283
@@ -12,22 +12,26 @@
12
12
 
13
13
  'use strict';
14
14
 
15
- const invariant = require('invariant');
16
-
17
15
  import type {RequestDescriptor} from './RelayStoreTypes';
18
16
 
17
+ const invariant = require('invariant');
18
+
19
19
  class RelayOperationTracker {
20
- _ownersToPendingOperationsIdentifier: Map<string, Set<string>>;
21
- _pendingOperationsToOwnersIdentifier: Map<string, Set<string>>;
22
- _ownersIdentifierToPromise: Map<
20
+ _ownersToPendingOperations: Map<string, Map<string, RequestDescriptor>>;
21
+ _pendingOperationsToOwners: Map<string, Set<string>>;
22
+ _ownersToPendingPromise: Map<
23
23
  string,
24
- {|promise: Promise<void>, resolve: () => void|},
24
+ {|
25
+ promise: Promise<void>,
26
+ resolve: () => void,
27
+ pendingOperations: $ReadOnlyArray<RequestDescriptor>,
28
+ |},
25
29
  >;
26
30
 
27
31
  constructor() {
28
- this._ownersToPendingOperationsIdentifier = new Map();
29
- this._pendingOperationsToOwnersIdentifier = new Map();
30
- this._ownersIdentifierToPromise = new Map();
32
+ this._ownersToPendingOperations = new Map();
33
+ this._pendingOperationsToOwners = new Map();
34
+ this._ownersToPendingPromise = new Map();
31
35
  }
32
36
 
33
37
  /**
@@ -45,22 +49,24 @@ class RelayOperationTracker {
45
49
  const newlyAffectedOwnersIdentifier = new Set();
46
50
  for (const owner of affectedOwners) {
47
51
  const ownerIdentifier = owner.identifier;
48
- const pendingOperationsAffectingOwner = this._ownersToPendingOperationsIdentifier.get(
49
- ownerIdentifier,
50
- );
52
+ const pendingOperationsAffectingOwner =
53
+ this._ownersToPendingOperations.get(ownerIdentifier);
51
54
  if (pendingOperationsAffectingOwner != null) {
52
55
  // In this case the `ownerIdentifier` already affected by some operations
53
56
  // We just need to detect, is it the same operation that we already
54
57
  // have in the list, or it's a new operation
55
58
  if (!pendingOperationsAffectingOwner.has(pendingOperationIdentifier)) {
56
- pendingOperationsAffectingOwner.add(pendingOperationIdentifier);
59
+ pendingOperationsAffectingOwner.set(
60
+ pendingOperationIdentifier,
61
+ pendingOperation,
62
+ );
57
63
  newlyAffectedOwnersIdentifier.add(ownerIdentifier);
58
64
  }
59
65
  } else {
60
66
  // This is a new `ownerIdentifier` that is affected by the operation
61
- this._ownersToPendingOperationsIdentifier.set(
67
+ this._ownersToPendingOperations.set(
62
68
  ownerIdentifier,
63
- new Set([pendingOperationIdentifier]),
69
+ new Map([[pendingOperationIdentifier, pendingOperation]]),
64
70
  );
65
71
  newlyAffectedOwnersIdentifier.add(ownerIdentifier);
66
72
  }
@@ -72,19 +78,18 @@ class RelayOperationTracker {
72
78
  }
73
79
 
74
80
  // But, if some owners were affected we need to add them to
75
- // the `_pendingOperationsToOwnersIdentifier` set
76
- const ownersAffectedByOperationIdentifier =
77
- this._pendingOperationsToOwnersIdentifier.get(
78
- pendingOperationIdentifier,
79
- ) || new Set();
81
+ // the `_pendingOperationsToOwners` set
82
+ const ownersAffectedByPendingOperation =
83
+ this._pendingOperationsToOwners.get(pendingOperationIdentifier) ||
84
+ new Set();
80
85
 
81
86
  for (const ownerIdentifier of newlyAffectedOwnersIdentifier) {
82
87
  this._resolveOwnerResolvers(ownerIdentifier);
83
- ownersAffectedByOperationIdentifier.add(ownerIdentifier);
88
+ ownersAffectedByPendingOperation.add(ownerIdentifier);
84
89
  }
85
- this._pendingOperationsToOwnersIdentifier.set(
90
+ this._pendingOperationsToOwners.set(
86
91
  pendingOperationIdentifier,
87
- ownersAffectedByOperationIdentifier,
92
+ ownersAffectedByPendingOperation,
88
93
  );
89
94
  }
90
95
 
@@ -94,7 +99,7 @@ class RelayOperationTracker {
94
99
  */
95
100
  complete(pendingOperation: RequestDescriptor): void {
96
101
  const pendingOperationIdentifier = pendingOperation.identifier;
97
- const affectedOwnersIdentifier = this._pendingOperationsToOwnersIdentifier.get(
102
+ const affectedOwnersIdentifier = this._pendingOperationsToOwners.get(
98
103
  pendingOperationIdentifier,
99
104
  );
100
105
  if (affectedOwnersIdentifier == null) {
@@ -107,9 +112,8 @@ class RelayOperationTracker {
107
112
  // and some other operations
108
113
  const updatedOwnersIdentifier = new Set();
109
114
  for (const ownerIdentifier of affectedOwnersIdentifier) {
110
- const pendingOperationsAffectingOwner = this._ownersToPendingOperationsIdentifier.get(
111
- ownerIdentifier,
112
- );
115
+ const pendingOperationsAffectingOwner =
116
+ this._ownersToPendingOperations.get(ownerIdentifier);
113
117
  if (!pendingOperationsAffectingOwner) {
114
118
  continue;
115
119
  }
@@ -124,7 +128,7 @@ class RelayOperationTracker {
124
128
  // Complete subscriptions for all owners, affected by `pendingOperationIdentifier`
125
129
  for (const ownerIdentifier of completedOwnersIdentifier) {
126
130
  this._resolveOwnerResolvers(ownerIdentifier);
127
- this._ownersToPendingOperationsIdentifier.delete(ownerIdentifier);
131
+ this._ownersToPendingOperations.delete(ownerIdentifier);
128
132
  }
129
133
 
130
134
  // Update all ownerIdentifier that were updated by `pendingOperationIdentifier` but still
@@ -134,31 +138,38 @@ class RelayOperationTracker {
134
138
  }
135
139
 
136
140
  // Finally, remove pending operation identifier
137
- this._pendingOperationsToOwnersIdentifier.delete(
138
- pendingOperationIdentifier,
139
- );
141
+ this._pendingOperationsToOwners.delete(pendingOperationIdentifier);
140
142
  }
141
143
 
142
144
  _resolveOwnerResolvers(ownerIdentifier: string): void {
143
- const promiseEntry = this._ownersIdentifierToPromise.get(ownerIdentifier);
145
+ const promiseEntry = this._ownersToPendingPromise.get(ownerIdentifier);
144
146
  if (promiseEntry != null) {
145
147
  promiseEntry.resolve();
146
148
  }
147
- this._ownersIdentifierToPromise.delete(ownerIdentifier);
149
+ this._ownersToPendingPromise.delete(ownerIdentifier);
148
150
  }
149
151
 
150
- getPromiseForPendingOperationsAffectingOwner(
151
- owner: RequestDescriptor,
152
- ): Promise<void> | null {
152
+ getPendingOperationsAffectingOwner(owner: RequestDescriptor): {|
153
+ promise: Promise<void>,
154
+ pendingOperations: $ReadOnlyArray<RequestDescriptor>,
155
+ |} | null {
153
156
  const ownerIdentifier = owner.identifier;
154
- if (!this._ownersToPendingOperationsIdentifier.has(ownerIdentifier)) {
157
+ const pendingOperationsForOwner =
158
+ this._ownersToPendingOperations.get(ownerIdentifier);
159
+ if (
160
+ pendingOperationsForOwner == null ||
161
+ pendingOperationsForOwner.size === 0
162
+ ) {
155
163
  return null;
156
164
  }
157
- const cachedPromiseEntry = this._ownersIdentifierToPromise.get(
158
- ownerIdentifier,
159
- );
165
+
166
+ const cachedPromiseEntry =
167
+ this._ownersToPendingPromise.get(ownerIdentifier);
160
168
  if (cachedPromiseEntry != null) {
161
- return cachedPromiseEntry.promise;
169
+ return {
170
+ promise: cachedPromiseEntry.promise,
171
+ pendingOperations: cachedPromiseEntry.pendingOperations,
172
+ };
162
173
  }
163
174
  let resolve;
164
175
  const promise = new Promise(r => {
@@ -169,8 +180,13 @@ class RelayOperationTracker {
169
180
  'RelayOperationTracker: Expected resolver to be defined. If you' +
170
181
  'are seeing this, it is likely a bug in Relay.',
171
182
  );
172
- this._ownersIdentifierToPromise.set(ownerIdentifier, {promise, resolve});
173
- return promise;
183
+ const pendingOperations = Array.from(pendingOperationsForOwner.values());
184
+ this._ownersToPendingPromise.set(ownerIdentifier, {
185
+ promise,
186
+ resolve,
187
+ pendingOperations,
188
+ });
189
+ return {promise, pendingOperations};
174
190
  }
175
191
  }
176
192
 
@@ -12,8 +12,6 @@
12
12
 
13
13
  'use strict';
14
14
 
15
- const RelayRecordSource = require('./RelayRecordSource');
16
-
17
15
  import type {DataID} from '../util/RelayRuntimeTypes';
18
16
  import type {RecordState} from './RelayRecordState';
19
17
  import type {
@@ -22,6 +20,8 @@ import type {
22
20
  RecordSource,
23
21
  } from './RelayStoreTypes';
24
22
 
23
+ const RelayRecordSource = require('./RelayRecordSource');
24
+
25
25
  const UNPUBLISH_RECORD_SENTINEL = Object.freeze({
26
26
  __UNPUBLISH_RECORD_SENTINEL: true,
27
27
  });
@@ -12,20 +12,11 @@
12
12
 
13
13
  'use strict';
14
14
 
15
- const ErrorUtils = require('ErrorUtils');
16
- const RelayReader = require('./RelayReader');
17
- const RelayRecordSource = require('./RelayRecordSource');
18
- const RelayRecordSourceMutator = require('../mutations/RelayRecordSourceMutator');
19
- const RelayRecordSourceProxy = require('../mutations/RelayRecordSourceProxy');
20
- const RelayRecordSourceSelectorProxy = require('../mutations/RelayRecordSourceSelectorProxy');
21
-
22
- const invariant = require('invariant');
23
- const warning = require('warning');
24
-
25
15
  import type {HandlerProvider} from '../handlers/RelayDefaultHandlerProvider';
26
16
  import type {Disposable} from '../util/RelayRuntimeTypes';
27
17
  import type {GetDataID} from './RelayResponseNormalizer';
28
18
  import type {
19
+ MutationParameters,
29
20
  OperationDescriptor,
30
21
  OptimisticUpdate,
31
22
  PublishQueue,
@@ -39,12 +30,23 @@ import type {
39
30
  StoreUpdater,
40
31
  } from './RelayStoreTypes';
41
32
 
42
- type PendingCommit = PendingRelayPayload | PendingRecordSource | PendingUpdater;
43
- type PendingRelayPayload = {|
33
+ const RelayRecordSourceMutator = require('../mutations/RelayRecordSourceMutator');
34
+ const RelayRecordSourceProxy = require('../mutations/RelayRecordSourceProxy');
35
+ const RelayRecordSourceSelectorProxy = require('../mutations/RelayRecordSourceSelectorProxy');
36
+ const RelayReader = require('./RelayReader');
37
+ const RelayRecordSource = require('./RelayRecordSource');
38
+ const invariant = require('invariant');
39
+ const warning = require('warning');
40
+
41
+ type PendingCommit<TMutation: MutationParameters> =
42
+ | PendingRelayPayload<TMutation>
43
+ | PendingRecordSource
44
+ | PendingUpdater;
45
+ type PendingRelayPayload<TMutation: MutationParameters> = {|
44
46
  +kind: 'payload',
45
47
  +operation: OperationDescriptor,
46
48
  +payload: RelayResponsePayload,
47
- +updater: ?SelectorStoreUpdater,
49
+ +updater: ?SelectorStoreUpdater<TMutation['response']>,
48
50
  |};
49
51
  type PendingRecordSource = {|
50
52
  +kind: 'source',
@@ -55,6 +57,10 @@ type PendingUpdater = {|
55
57
  +updater: StoreUpdater,
56
58
  |};
57
59
 
60
+ const applyWithGuard =
61
+ global?.ErrorUtils?.applyWithGuard ??
62
+ ((callback, context, args, onError, name) => callback.apply(context, args));
63
+
58
64
  /**
59
65
  * Coordinates the concurrent modification of a `Store` due to optimistic and
60
66
  * non-revertable client updates and server payloads:
@@ -76,12 +82,19 @@ class RelayPublishQueue implements PublishQueue {
76
82
  // updates performing a rebase.
77
83
  _pendingBackupRebase: boolean;
78
84
  // Payloads to apply or Sources to publish to the store with the next `run()`.
79
- _pendingData: Set<PendingCommit>;
85
+ // $FlowFixMe[unclear-type] See explanation below.
86
+ _pendingData: Set<PendingCommit<any>>;
80
87
  // Optimistic updaters to add with the next `run()`.
81
- _pendingOptimisticUpdates: Set<OptimisticUpdate>;
88
+ // $FlowFixMe[unclear-type] See explanation below.
89
+ _pendingOptimisticUpdates: Set<OptimisticUpdate<any>>;
82
90
  // Optimistic updaters that are already added and might be rerun in order to
83
91
  // rebase them.
84
- _appliedOptimisticUpdates: Set<OptimisticUpdate>;
92
+ // $FlowFixMe[unclear-type] See explanation below.
93
+ _appliedOptimisticUpdates: Set<OptimisticUpdate<any>>;
94
+ // For _pendingOptimisticUpdates, _appliedOptimisticUpdates, and _pendingData,
95
+ // we want to parametrize by "any" since the type is effectively
96
+ // "the union of all T's that PublishQueue's methods were called with".
97
+
85
98
  // Garbage collection hold, should rerun gc on dispose
86
99
  _gcHold: ?Disposable;
87
100
  _isRunning: ?boolean;
@@ -105,7 +118,9 @@ class RelayPublishQueue implements PublishQueue {
105
118
  /**
106
119
  * Schedule applying an optimistic updates on the next `run()`.
107
120
  */
108
- applyUpdate(updater: OptimisticUpdate): void {
121
+ applyUpdate<TMutation: MutationParameters>(
122
+ updater: OptimisticUpdate<TMutation>,
123
+ ): void {
109
124
  invariant(
110
125
  !this._appliedOptimisticUpdates.has(updater) &&
111
126
  !this._pendingOptimisticUpdates.has(updater),
@@ -118,7 +133,9 @@ class RelayPublishQueue implements PublishQueue {
118
133
  /**
119
134
  * Schedule reverting an optimistic updates on the next `run()`.
120
135
  */
121
- revertUpdate(updater: OptimisticUpdate): void {
136
+ revertUpdate<TMutation: MutationParameters>(
137
+ updater: OptimisticUpdate<TMutation>,
138
+ ): void {
122
139
  if (this._pendingOptimisticUpdates.has(updater)) {
123
140
  // Reverted before it was applied
124
141
  this._pendingOptimisticUpdates.delete(updater);
@@ -140,10 +157,10 @@ class RelayPublishQueue implements PublishQueue {
140
157
  /**
141
158
  * Schedule applying a payload to the store on the next `run()`.
142
159
  */
143
- commitPayload(
160
+ commitPayload<TMutation: MutationParameters>(
144
161
  operation: OperationDescriptor,
145
162
  payload: RelayResponsePayload,
146
- updater?: ?SelectorStoreUpdater,
163
+ updater?: ?SelectorStoreUpdater<TMutation['response']>,
147
164
  ): void {
148
165
  this._pendingBackupRebase = true;
149
166
  this._pendingData.add({
@@ -182,7 +199,20 @@ class RelayPublishQueue implements PublishQueue {
182
199
  run(
183
200
  sourceOperation?: OperationDescriptor,
184
201
  ): $ReadOnlyArray<RequestDescriptor> {
202
+ const runWillClearGcHold =
203
+ this._appliedOptimisticUpdates === 0 && !!this._gcHold;
204
+ const runIsANoop =
205
+ // this._pendingBackupRebase is true if an applied optimistic
206
+ // update has potentially been reverted or if this._pendingData is not empty.
207
+ !this._pendingBackupRebase &&
208
+ this._pendingOptimisticUpdates.size === 0 &&
209
+ !runWillClearGcHold;
210
+
185
211
  if (__DEV__) {
212
+ warning(
213
+ !runIsANoop,
214
+ 'RelayPublishQueue.run was called, but the call would have been a noop.',
215
+ );
186
216
  warning(
187
217
  this._isRunning !== true,
188
218
  'A store update was detected within another store update. Please ' +
@@ -191,6 +221,14 @@ class RelayPublishQueue implements PublishQueue {
191
221
  );
192
222
  this._isRunning = true;
193
223
  }
224
+
225
+ if (runIsANoop) {
226
+ if (__DEV__) {
227
+ this._isRunning = false;
228
+ }
229
+ return [];
230
+ }
231
+
194
232
  if (this._pendingBackupRebase) {
195
233
  if (this._hasStoreSnapshot) {
196
234
  this._store.restore();
@@ -229,7 +267,9 @@ class RelayPublishQueue implements PublishQueue {
229
267
  * _publishSourceFromPayload will return a boolean indicating if the
230
268
  * publish caused the store to be globally invalidated.
231
269
  */
232
- _publishSourceFromPayload(pendingPayload: PendingRelayPayload): boolean {
270
+ _publishSourceFromPayload<TMutation: MutationParameters>(
271
+ pendingPayload: PendingRelayPayload<TMutation>,
272
+ ): boolean {
233
273
  const {payload, operation, updater} = pendingPayload;
234
274
  const {source, fieldPayloads} = payload;
235
275
  const mutator = new RelayRecordSourceMutator(
@@ -267,7 +307,8 @@ class RelayPublishQueue implements PublishQueue {
267
307
  const selectorData = lookupSelector(source, selector);
268
308
  updater(recordSourceSelectorProxy, selectorData);
269
309
  }
270
- const idsMarkedForInvalidation = recordSourceProxy.getIDsMarkedForInvalidation();
310
+ const idsMarkedForInvalidation =
311
+ recordSourceProxy.getIDsMarkedForInvalidation();
271
312
  this._store.publish(source, idsMarkedForInvalidation);
272
313
  return recordSourceProxy.isStoreMarkedForInvalidation();
273
314
  }
@@ -299,7 +340,7 @@ class RelayPublishQueue implements PublishQueue {
299
340
  mutator,
300
341
  this._getDataID,
301
342
  );
302
- ErrorUtils.applyWithGuard(
343
+ applyWithGuard(
303
344
  updater,
304
345
  null,
305
346
  [recordSourceProxy],
@@ -308,7 +349,8 @@ class RelayPublishQueue implements PublishQueue {
308
349
  );
309
350
  invalidatedStore =
310
351
  invalidatedStore || recordSourceProxy.isStoreMarkedForInvalidation();
311
- const idsMarkedForInvalidation = recordSourceProxy.getIDsMarkedForInvalidation();
352
+ const idsMarkedForInvalidation =
353
+ recordSourceProxy.getIDsMarkedForInvalidation();
312
354
 
313
355
  this._store.publish(sink, idsMarkedForInvalidation);
314
356
  }
@@ -331,10 +373,11 @@ class RelayPublishQueue implements PublishQueue {
331
373
  this._handlerProvider,
332
374
  );
333
375
 
334
- const processUpdate = optimisticUpdate => {
376
+ // $FlowFixMe[unclear-type] see explanation above.
377
+ const processUpdate = (optimisticUpdate: OptimisticUpdate<any>) => {
335
378
  if (optimisticUpdate.storeUpdater) {
336
379
  const {storeUpdater} = optimisticUpdate;
337
- ErrorUtils.applyWithGuard(
380
+ applyWithGuard(
338
381
  storeUpdater,
339
382
  null,
340
383
  [recordSourceProxy],
@@ -344,18 +387,20 @@ class RelayPublishQueue implements PublishQueue {
344
387
  } else {
345
388
  const {operation, payload, updater} = optimisticUpdate;
346
389
  const {source, fieldPayloads} = payload;
347
- const recordSourceSelectorProxy = new RelayRecordSourceSelectorProxy(
348
- mutator,
349
- recordSourceProxy,
350
- operation.fragment,
351
- );
352
- let selectorData;
353
390
  if (source) {
354
391
  recordSourceProxy.publishSource(source, fieldPayloads);
355
- selectorData = lookupSelector(source, operation.fragment);
356
392
  }
357
393
  if (updater) {
358
- ErrorUtils.applyWithGuard(
394
+ let selectorData;
395
+ if (source) {
396
+ selectorData = lookupSelector(source, operation.fragment);
397
+ }
398
+ const recordSourceSelectorProxy = new RelayRecordSourceSelectorProxy(
399
+ mutator,
400
+ recordSourceProxy,
401
+ operation.fragment,
402
+ );
403
+ applyWithGuard(
359
404
  updater,
360
405
  null,
361
406
  [recordSourceSelectorProxy, selectorData],