relay-runtime 7.0.0 → 9.1.0

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 (157) hide show
  1. package/handlers/RelayDefaultHandlerProvider.js.flow +34 -0
  2. package/handlers/connection/ConnectionHandler.js.flow +549 -0
  3. package/handlers/connection/ConnectionInterface.js.flow +92 -0
  4. package/index.js +1 -1
  5. package/index.js.flow +314 -0
  6. package/lib/handlers/RelayDefaultHandlerProvider.js +3 -2
  7. package/lib/handlers/connection/{RelayConnectionHandler.js → ConnectionHandler.js} +34 -35
  8. package/lib/handlers/connection/{RelayConnectionInterface.js → ConnectionInterface.js} +3 -30
  9. package/lib/index.js +29 -27
  10. package/lib/mutations/RelayDeclarativeMutationConfig.js +30 -52
  11. package/lib/mutations/RelayRecordProxy.js +6 -3
  12. package/lib/mutations/RelayRecordSourceMutator.js +3 -9
  13. package/lib/mutations/RelayRecordSourceProxy.js +21 -24
  14. package/lib/mutations/RelayRecordSourceSelectorProxy.js +18 -14
  15. package/lib/mutations/applyOptimisticMutation.js +2 -1
  16. package/lib/mutations/commitLocalUpdate.js +1 -0
  17. package/lib/mutations/commitMutation.js +26 -8
  18. package/lib/mutations/validateMutation.js +21 -11
  19. package/lib/network/ConvertToExecuteFunction.js +1 -0
  20. package/lib/network/RelayNetwork.js +1 -0
  21. package/lib/network/RelayNetworkTypes.js +1 -0
  22. package/lib/network/RelayObservable.js +10 -9
  23. package/lib/network/RelayQueryResponseCache.js +9 -7
  24. package/lib/query/{RelayModernGraphQLTag.js → GraphQLTag.js} +15 -8
  25. package/lib/query/fetchQuery.js +2 -1
  26. package/lib/query/fetchQueryInternal.js +30 -20
  27. package/lib/store/ClientID.js +1 -0
  28. package/lib/store/DataChecker.js +47 -97
  29. package/lib/store/RelayConcreteVariables.js +7 -2
  30. package/lib/store/RelayModernEnvironment.js +82 -41
  31. package/lib/store/RelayModernFragmentSpecResolver.js +61 -21
  32. package/lib/store/RelayModernOperationDescriptor.js +2 -1
  33. package/lib/store/RelayModernQueryExecutor.js +476 -333
  34. package/lib/store/RelayModernRecord.js +39 -9
  35. package/lib/store/RelayModernSelector.js +2 -1
  36. package/lib/store/RelayModernStore.js +359 -371
  37. package/lib/store/RelayOperationTracker.js +36 -78
  38. package/lib/store/RelayOptimisticRecordSource.js +8 -5
  39. package/lib/store/RelayPublishQueue.js +66 -53
  40. package/lib/store/RelayReader.js +2 -24
  41. package/lib/store/RelayRecordSource.js +3 -9
  42. package/lib/store/RelayRecordSourceMapImpl.js +14 -18
  43. package/lib/store/RelayRecordState.js +1 -0
  44. package/lib/store/RelayReferenceMarker.js +8 -58
  45. package/lib/store/RelayResponseNormalizer.js +15 -144
  46. package/lib/store/RelayStoreTypes.js +1 -0
  47. package/lib/store/RelayStoreUtils.js +34 -10
  48. package/lib/store/StoreInspector.js +11 -5
  49. package/lib/store/ViewerPattern.js +1 -0
  50. package/lib/store/cloneRelayHandleSourceField.js +1 -0
  51. package/lib/store/createFragmentSpecResolver.js +1 -0
  52. package/lib/store/createRelayContext.js +1 -0
  53. package/lib/store/defaultGetDataID.js +1 -0
  54. package/lib/store/hasOverlappingIDs.js +1 -0
  55. package/lib/store/isRelayModernEnvironment.js +1 -0
  56. package/lib/store/normalizeRelayPayload.js +8 -4
  57. package/lib/store/readInlineData.js +2 -1
  58. package/lib/subscription/requestSubscription.js +6 -3
  59. package/lib/util/JSResourceTypes.flow.js +12 -0
  60. package/lib/util/NormalizationNode.js +1 -0
  61. package/lib/util/ReaderNode.js +1 -0
  62. package/lib/util/RelayConcreteNode.js +3 -0
  63. package/lib/util/RelayDefaultHandleKey.js +1 -0
  64. package/lib/util/RelayError.js +2 -1
  65. package/lib/util/RelayFeatureFlags.js +3 -2
  66. package/lib/util/RelayProfiler.js +1 -0
  67. package/lib/util/RelayReplaySubject.js +2 -3
  68. package/lib/util/RelayRuntimeTypes.js +1 -0
  69. package/lib/util/createPayloadFor3DField.js +34 -0
  70. package/lib/util/deepFreeze.js +1 -0
  71. package/lib/util/generateID.js +1 -0
  72. package/lib/util/getFragmentIdentifier.js +1 -0
  73. package/lib/util/getRelayHandleKey.js +1 -0
  74. package/lib/util/getRequestIdentifier.js +1 -0
  75. package/lib/util/isPromise.js +1 -0
  76. package/lib/util/isScalarAndEqual.js +1 -0
  77. package/lib/util/recycleNodesInto.js +1 -0
  78. package/lib/util/resolveImmediate.js +1 -0
  79. package/lib/util/stableCopy.js +1 -0
  80. package/mutations/RelayDeclarativeMutationConfig.js.flow +380 -0
  81. package/mutations/RelayRecordProxy.js.flow +165 -0
  82. package/mutations/RelayRecordSourceMutator.js.flow +238 -0
  83. package/mutations/RelayRecordSourceProxy.js.flow +164 -0
  84. package/mutations/RelayRecordSourceSelectorProxy.js.flow +119 -0
  85. package/mutations/applyOptimisticMutation.js.flow +76 -0
  86. package/mutations/commitLocalUpdate.js.flow +24 -0
  87. package/mutations/commitMutation.js.flow +184 -0
  88. package/mutations/validateMutation.js.flow +211 -0
  89. package/network/ConvertToExecuteFunction.js.flow +49 -0
  90. package/network/RelayNetwork.js.flow +84 -0
  91. package/network/RelayNetworkTypes.js.flow +123 -0
  92. package/network/RelayObservable.js.flow +634 -0
  93. package/network/RelayQueryResponseCache.js.flow +111 -0
  94. package/package.json +1 -1
  95. package/query/GraphQLTag.js.flow +166 -0
  96. package/query/fetchQuery.js.flow +47 -0
  97. package/query/fetchQueryInternal.js.flow +349 -0
  98. package/relay-runtime.js +2 -2
  99. package/relay-runtime.min.js +2 -2
  100. package/store/ClientID.js.flow +43 -0
  101. package/store/DataChecker.js.flow +426 -0
  102. package/store/RelayConcreteVariables.js.flow +96 -0
  103. package/store/RelayModernEnvironment.js.flow +526 -0
  104. package/store/RelayModernFragmentSpecResolver.js.flow +426 -0
  105. package/store/RelayModernOperationDescriptor.js.flow +88 -0
  106. package/store/RelayModernQueryExecutor.js.flow +1327 -0
  107. package/store/RelayModernRecord.js.flow +403 -0
  108. package/store/RelayModernSelector.js.flow +444 -0
  109. package/store/RelayModernStore.js.flow +757 -0
  110. package/store/RelayOperationTracker.js.flow +164 -0
  111. package/store/RelayOptimisticRecordSource.js.flow +119 -0
  112. package/store/RelayPublishQueue.js.flow +401 -0
  113. package/store/RelayReader.js.flow +376 -0
  114. package/store/RelayRecordSource.js.flow +29 -0
  115. package/store/RelayRecordSourceMapImpl.js.flow +87 -0
  116. package/store/RelayRecordState.js.flow +37 -0
  117. package/store/RelayReferenceMarker.js.flow +236 -0
  118. package/store/RelayResponseNormalizer.js.flow +556 -0
  119. package/store/RelayStoreTypes.js.flow +873 -0
  120. package/store/RelayStoreUtils.js.flow +218 -0
  121. package/store/StoreInspector.js.flow +173 -0
  122. package/store/ViewerPattern.js.flow +26 -0
  123. package/store/cloneRelayHandleSourceField.js.flow +66 -0
  124. package/store/createFragmentSpecResolver.js.flow +55 -0
  125. package/store/createRelayContext.js.flow +44 -0
  126. package/store/defaultGetDataID.js.flow +27 -0
  127. package/store/hasOverlappingIDs.js.flow +34 -0
  128. package/store/isRelayModernEnvironment.js.flow +27 -0
  129. package/store/normalizeRelayPayload.js.flow +51 -0
  130. package/store/readInlineData.js.flow +75 -0
  131. package/subscription/requestSubscription.js.flow +100 -0
  132. package/util/JSResourceTypes.flow.js.flow +20 -0
  133. package/util/NormalizationNode.js.flow +191 -0
  134. package/util/ReaderNode.js.flow +208 -0
  135. package/util/RelayConcreteNode.js.flow +80 -0
  136. package/util/RelayDefaultHandleKey.js.flow +17 -0
  137. package/util/RelayError.js.flow +33 -0
  138. package/util/RelayFeatureFlags.js.flow +30 -0
  139. package/util/RelayProfiler.js.flow +284 -0
  140. package/util/RelayReplaySubject.js.flow +134 -0
  141. package/util/RelayRuntimeTypes.js.flow +70 -0
  142. package/util/createPayloadFor3DField.js.flow +43 -0
  143. package/util/deepFreeze.js.flow +36 -0
  144. package/util/generateID.js.flow +21 -0
  145. package/util/getFragmentIdentifier.js.flow +52 -0
  146. package/util/getRelayHandleKey.js.flow +41 -0
  147. package/util/getRequestIdentifier.js.flow +41 -0
  148. package/util/isPromise.js.flow +21 -0
  149. package/util/isScalarAndEqual.js.flow +26 -0
  150. package/util/recycleNodesInto.js.flow +80 -0
  151. package/util/resolveImmediate.js.flow +30 -0
  152. package/util/stableCopy.js.flow +35 -0
  153. package/lib/handlers/RelayDefaultMissingFieldHandlers.js +0 -26
  154. package/lib/store/RelayConnection.js +0 -36
  155. package/lib/store/RelayConnectionResolver.js +0 -177
  156. package/lib/store/RelayRecordSourceObjectImpl.js +0 -78
  157. package/lib/util/getFragmentSpecIdentifier.js +0 -26
@@ -0,0 +1,426 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+
13
+ 'use strict';
14
+
15
+ const RelayFeatureFlags = require('../util/RelayFeatureFlags');
16
+
17
+ const areEqual = require('areEqual');
18
+ const invariant = require('invariant');
19
+ const isScalarAndEqual = require('../util/isScalarAndEqual');
20
+ const warning = require('warning');
21
+
22
+ const {getPromiseForActiveRequest} = require('../query/fetchQueryInternal');
23
+ const {createRequestDescriptor} = require('./RelayModernOperationDescriptor');
24
+ const {
25
+ areEqualSelectors,
26
+ createReaderSelector,
27
+ getSelectorsFromObject,
28
+ } = require('./RelayModernSelector');
29
+
30
+ import type {ConcreteRequest} from '../util/RelayConcreteNode';
31
+ import type {Disposable, Variables} from '../util/RelayRuntimeTypes';
32
+ import type {
33
+ IEnvironment,
34
+ FragmentMap,
35
+ FragmentSpecResolver,
36
+ FragmentSpecResults,
37
+ PluralReaderSelector,
38
+ RelayContext,
39
+ SelectorData,
40
+ SingularReaderSelector,
41
+ Snapshot,
42
+ } from './RelayStoreTypes';
43
+
44
+ type Props = {[key: string]: mixed, ...};
45
+ type Resolvers = {
46
+ [key: string]: ?(SelectorListResolver | SelectorResolver),
47
+ ...,
48
+ };
49
+
50
+ /**
51
+ * A utility for resolving and subscribing to the results of a fragment spec
52
+ * (key -> fragment mapping) given some "props" that determine the root ID
53
+ * and variables to use when reading each fragment. When props are changed via
54
+ * `setProps()`, the resolver will update its results and subscriptions
55
+ * accordingly. Internally, the resolver:
56
+ * - Converts the fragment map & props map into a map of `Selector`s.
57
+ * - Removes any resolvers for any props that became null.
58
+ * - Creates resolvers for any props that became non-null.
59
+ * - Updates resolvers with the latest props.
60
+ *
61
+ * This utility is implemented as an imperative, stateful API for performance
62
+ * reasons: reusing previous resolvers, callback functions, and subscriptions
63
+ * all helps to reduce object allocation and thereby decrease GC time.
64
+ *
65
+ * The `resolve()` function is also lazy and memoized: changes in the store mark
66
+ * the resolver as stale and notify the caller, and the actual results are
67
+ * recomputed the first time `resolve()` is called.
68
+ */
69
+ class RelayModernFragmentSpecResolver implements FragmentSpecResolver {
70
+ _callback: ?() => void;
71
+ _context: RelayContext;
72
+ _data: Object;
73
+ _fragments: FragmentMap;
74
+ _props: Props;
75
+ _resolvers: Resolvers;
76
+ _stale: boolean;
77
+
78
+ constructor(
79
+ context: RelayContext,
80
+ fragments: FragmentMap,
81
+ props: Props,
82
+ callback?: () => void,
83
+ ) {
84
+ this._callback = callback;
85
+ this._context = context;
86
+ this._data = {};
87
+ this._fragments = fragments;
88
+ this._props = {};
89
+ this._resolvers = {};
90
+ this._stale = false;
91
+
92
+ this.setProps(props);
93
+ }
94
+
95
+ dispose(): void {
96
+ for (const key in this._resolvers) {
97
+ if (this._resolvers.hasOwnProperty(key)) {
98
+ disposeCallback(this._resolvers[key]);
99
+ }
100
+ }
101
+ }
102
+
103
+ resolve(): FragmentSpecResults {
104
+ if (this._stale) {
105
+ // Avoid mapping the object multiple times, which could occur if data for
106
+ // multiple keys changes in the same event loop.
107
+ const prevData = this._data;
108
+ let nextData;
109
+ for (const key in this._resolvers) {
110
+ if (this._resolvers.hasOwnProperty(key)) {
111
+ const resolver = this._resolvers[key];
112
+ const prevItem = prevData[key];
113
+ if (resolver) {
114
+ const nextItem = resolver.resolve();
115
+ if (nextData || nextItem !== prevItem) {
116
+ nextData = nextData || {...prevData};
117
+ nextData[key] = nextItem;
118
+ }
119
+ } else {
120
+ const prop = this._props[key];
121
+ const nextItem = prop !== undefined ? prop : null;
122
+ if (nextData || !isScalarAndEqual(nextItem, prevItem)) {
123
+ nextData = nextData || {...prevData};
124
+ nextData[key] = nextItem;
125
+ }
126
+ }
127
+ }
128
+ }
129
+ this._data = nextData || prevData;
130
+ this._stale = false;
131
+ }
132
+ return this._data;
133
+ }
134
+
135
+ setCallback(callback: () => void): void {
136
+ this._callback = callback;
137
+ }
138
+
139
+ setProps(props: Props): void {
140
+ const ownedSelectors = getSelectorsFromObject(this._fragments, props);
141
+ this._props = {};
142
+
143
+ for (const key in ownedSelectors) {
144
+ if (ownedSelectors.hasOwnProperty(key)) {
145
+ const ownedSelector = ownedSelectors[key];
146
+ let resolver = this._resolvers[key];
147
+ if (ownedSelector == null) {
148
+ if (resolver != null) {
149
+ resolver.dispose();
150
+ }
151
+ resolver = null;
152
+ } else if (ownedSelector.kind === 'PluralReaderSelector') {
153
+ if (resolver == null) {
154
+ resolver = new SelectorListResolver(
155
+ this._context.environment,
156
+ ownedSelector,
157
+ this._onChange,
158
+ );
159
+ } else {
160
+ invariant(
161
+ resolver instanceof SelectorListResolver,
162
+ 'RelayModernFragmentSpecResolver: Expected prop `%s` to always be an array.',
163
+ key,
164
+ );
165
+ resolver.setSelector(ownedSelector);
166
+ }
167
+ } else {
168
+ if (resolver == null) {
169
+ resolver = new SelectorResolver(
170
+ this._context.environment,
171
+ ownedSelector,
172
+ this._onChange,
173
+ );
174
+ } else {
175
+ invariant(
176
+ resolver instanceof SelectorResolver,
177
+ 'RelayModernFragmentSpecResolver: Expected prop `%s` to always be an object.',
178
+ key,
179
+ );
180
+ resolver.setSelector(ownedSelector);
181
+ }
182
+ }
183
+ this._props[key] = props[key];
184
+ this._resolvers[key] = resolver;
185
+ }
186
+ }
187
+ this._stale = true;
188
+ }
189
+
190
+ setVariables(variables: Variables, request: ConcreteRequest): void {
191
+ for (const key in this._resolvers) {
192
+ if (this._resolvers.hasOwnProperty(key)) {
193
+ const resolver = this._resolvers[key];
194
+ if (resolver) {
195
+ resolver.setVariables(variables, request);
196
+ }
197
+ }
198
+ }
199
+ this._stale = true;
200
+ }
201
+
202
+ _onChange = (): void => {
203
+ this._stale = true;
204
+
205
+ if (typeof this._callback === 'function') {
206
+ this._callback();
207
+ }
208
+ };
209
+ }
210
+
211
+ /**
212
+ * A resolver for a single Selector.
213
+ */
214
+ class SelectorResolver {
215
+ _callback: () => void;
216
+ _data: ?SelectorData;
217
+ _environment: IEnvironment;
218
+ _isMissingData: boolean;
219
+ _selector: SingularReaderSelector;
220
+ _subscription: ?Disposable;
221
+
222
+ constructor(
223
+ environment: IEnvironment,
224
+ selector: SingularReaderSelector,
225
+ callback: () => void,
226
+ ) {
227
+ const snapshot = environment.lookup(selector);
228
+ this._callback = callback;
229
+ this._data = snapshot.data;
230
+ this._isMissingData = snapshot.isMissingData;
231
+ this._environment = environment;
232
+ this._selector = selector;
233
+ this._subscription = environment.subscribe(snapshot, this._onChange);
234
+ }
235
+
236
+ dispose(): void {
237
+ if (this._subscription) {
238
+ this._subscription.dispose();
239
+ this._subscription = null;
240
+ }
241
+ }
242
+
243
+ resolve(): ?Object {
244
+ if (
245
+ RelayFeatureFlags.ENABLE_RELAY_CONTAINERS_SUSPENSE === true &&
246
+ this._isMissingData === true
247
+ ) {
248
+ // NOTE: This branch exists to handle the case in which:
249
+ // - A RelayModern container is rendered as a descendant of a Relay Hook
250
+ // root using a "partial" renderPolicy (this means that eargerly
251
+ // reading any cached data that is available instead of blocking
252
+ // at the root until the whole query is fetched).
253
+ // - A parent Relay Hook didnt' suspend earlier on data being fetched,
254
+ // either because the fragment data for the parent was available, or
255
+ // the parent fragment didn't have any data dependencies.
256
+ // Even though our Flow types reflect the possiblity of null data, there
257
+ // might still be cases where it's not handled at runtime becuase the
258
+ // Flow types are being ignored, or simply not being used (for example,
259
+ // the case reported here: https://fburl.com/srnbucf8, was due to
260
+ // misuse of Flow types here: https://fburl.com/g3m0mqqh).
261
+ // Additionally, even though the null data might be handled without a
262
+ // runtime error, we might not suspend when we intended to if a parent
263
+ // Relay Hook (e.g. that is using @defer) decided not to suspend becuase
264
+ // it's immediate data was already available (even if it was deferred),
265
+ // or it didn't actually need any data (was just spreading other fragments).
266
+ // This should eventually go away with something like @optional, where we only
267
+ // suspend at specific boundaries depending on whether the boundary
268
+ // can be fulfilled or not.
269
+ const promise =
270
+ getPromiseForActiveRequest(this._environment, this._selector.owner) ??
271
+ this._environment
272
+ .getOperationTracker()
273
+ .getPromiseForPendingOperationsAffectingOwner(this._selector.owner);
274
+ if (promise != null) {
275
+ warning(
276
+ false,
277
+ 'Relay: Relay Container for fragment `%s` suspended. When using ' +
278
+ 'features such as @defer or @module, use `useFragment` instead ' +
279
+ 'of a Relay Container.',
280
+ this._selector.node.name,
281
+ );
282
+ throw promise;
283
+ }
284
+ }
285
+ return this._data;
286
+ }
287
+
288
+ setSelector(selector: SingularReaderSelector): void {
289
+ if (
290
+ this._subscription != null &&
291
+ areEqualSelectors(selector, this._selector)
292
+ ) {
293
+ return;
294
+ }
295
+ this.dispose();
296
+ const snapshot = this._environment.lookup(selector);
297
+ this._data = snapshot.data;
298
+ this._isMissingData = snapshot.isMissingData;
299
+ this._selector = selector;
300
+ this._subscription = this._environment.subscribe(snapshot, this._onChange);
301
+ }
302
+
303
+ setVariables(variables: Variables, request: ConcreteRequest): void {
304
+ if (areEqual(variables, this._selector.variables)) {
305
+ // If we're not actually setting new variables, we don't actually want
306
+ // to create a new fragment owner, since areEqualSelectors relies on
307
+ // owner identity.
308
+ // In fact, we don't even need to try to attempt to set a new selector.
309
+ // When fragment ownership is not enabled, setSelector will also bail
310
+ // out since the selector doesn't really change, so we're doing it here
311
+ // earlier.
312
+ return;
313
+ }
314
+ // NOTE: We manually create the request descriptor here instead of
315
+ // calling createOperationDescriptor() because we want to set a
316
+ // descriptor with *unaltered* variables as the fragment owner.
317
+ // This is a hack that allows us to preserve exisiting (broken)
318
+ // behavior of RelayModern containers while using fragment ownership
319
+ // to propagate variables instead of Context.
320
+ // For more details, see the summary of D13999308
321
+ const requestDescriptor = createRequestDescriptor(request, variables);
322
+ const selector = createReaderSelector(
323
+ this._selector.node,
324
+ this._selector.dataID,
325
+ variables,
326
+ requestDescriptor,
327
+ );
328
+ this.setSelector(selector);
329
+ }
330
+
331
+ _onChange = (snapshot: Snapshot): void => {
332
+ this._data = snapshot.data;
333
+ this._isMissingData = snapshot.isMissingData;
334
+ this._callback();
335
+ };
336
+ }
337
+
338
+ /**
339
+ * A resolver for an array of Selectors.
340
+ */
341
+ class SelectorListResolver {
342
+ _callback: () => void;
343
+ _data: Array<?SelectorData>;
344
+ _environment: IEnvironment;
345
+ _resolvers: Array<SelectorResolver>;
346
+ _stale: boolean;
347
+
348
+ constructor(
349
+ environment: IEnvironment,
350
+ selector: PluralReaderSelector,
351
+ callback: () => void,
352
+ ) {
353
+ this._callback = callback;
354
+ this._data = [];
355
+ this._environment = environment;
356
+ this._resolvers = [];
357
+ this._stale = true;
358
+
359
+ this.setSelector(selector);
360
+ }
361
+
362
+ dispose(): void {
363
+ this._resolvers.forEach(disposeCallback);
364
+ }
365
+
366
+ resolve(): Array<?Object> {
367
+ if (this._stale) {
368
+ // Avoid mapping the array multiple times, which could occur if data for
369
+ // multiple indices changes in the same event loop.
370
+ const prevData = this._data;
371
+ let nextData;
372
+ for (let ii = 0; ii < this._resolvers.length; ii++) {
373
+ const prevItem = prevData[ii];
374
+ const nextItem = this._resolvers[ii].resolve();
375
+ if (nextData || nextItem !== prevItem) {
376
+ nextData = nextData || prevData.slice(0, ii);
377
+ nextData.push(nextItem);
378
+ }
379
+ }
380
+ if (!nextData && this._resolvers.length !== prevData.length) {
381
+ nextData = prevData.slice(0, this._resolvers.length);
382
+ }
383
+ this._data = nextData || prevData;
384
+ this._stale = false;
385
+ }
386
+ return this._data;
387
+ }
388
+
389
+ setSelector(selector: PluralReaderSelector): void {
390
+ const {selectors} = selector;
391
+ while (this._resolvers.length > selectors.length) {
392
+ const resolver = this._resolvers.pop();
393
+ resolver.dispose();
394
+ }
395
+ for (let ii = 0; ii < selectors.length; ii++) {
396
+ if (ii < this._resolvers.length) {
397
+ this._resolvers[ii].setSelector(selectors[ii]);
398
+ } else {
399
+ this._resolvers[ii] = new SelectorResolver(
400
+ this._environment,
401
+ selectors[ii],
402
+ this._onChange,
403
+ );
404
+ }
405
+ }
406
+ this._stale = true;
407
+ }
408
+
409
+ setVariables(variables: Variables, request: ConcreteRequest): void {
410
+ this._resolvers.forEach(resolver =>
411
+ resolver.setVariables(variables, request),
412
+ );
413
+ this._stale = true;
414
+ }
415
+
416
+ _onChange = (data: ?Object): void => {
417
+ this._stale = true;
418
+ this._callback();
419
+ };
420
+ }
421
+
422
+ function disposeCallback(disposable: ?Disposable): void {
423
+ disposable && disposable.dispose();
424
+ }
425
+
426
+ module.exports = RelayModernFragmentSpecResolver;
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict-local
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+
13
+ 'use strict';
14
+
15
+ const deepFreeze = require('../util/deepFreeze');
16
+ const getRequestIdentifier = require('../util/getRequestIdentifier');
17
+
18
+ const {getOperationVariables} = require('./RelayConcreteVariables');
19
+ const {
20
+ createNormalizationSelector,
21
+ createReaderSelector,
22
+ } = require('./RelayModernSelector');
23
+ const {ROOT_ID} = require('./RelayStoreUtils');
24
+
25
+ import type {ConcreteRequest} from '../util/RelayConcreteNode';
26
+ import type {DataID, Variables} from '../util/RelayRuntimeTypes';
27
+ import type {OperationDescriptor, RequestDescriptor} from './RelayStoreTypes';
28
+
29
+ /**
30
+ * Creates an instance of the `OperationDescriptor` type defined in
31
+ * `RelayStoreTypes` given an operation and some variables. The input variables
32
+ * are filtered to exclude variables that do not match defined arguments on the
33
+ * operation, and default values are populated for null values.
34
+ */
35
+ function createOperationDescriptor(
36
+ request: ConcreteRequest,
37
+ variables: Variables,
38
+ dataID?: DataID = ROOT_ID,
39
+ ): OperationDescriptor {
40
+ const operation = request.operation;
41
+ const operationVariables = getOperationVariables(operation, variables);
42
+ const requestDescriptor = createRequestDescriptor(
43
+ request,
44
+ operationVariables,
45
+ );
46
+ const operationDescriptor = {
47
+ fragment: createReaderSelector(
48
+ request.fragment,
49
+ dataID,
50
+ operationVariables,
51
+ requestDescriptor,
52
+ ),
53
+ request: requestDescriptor,
54
+ root: createNormalizationSelector(operation, dataID, operationVariables),
55
+ };
56
+
57
+ if (__DEV__) {
58
+ // Freezing properties short-circuits a deepFreeze of snapshots that contain
59
+ // an OperationDescriptor via their selector's owner, avoiding stack
60
+ // overflow on larger queries.
61
+ Object.freeze(operationDescriptor.fragment);
62
+ Object.freeze(operationDescriptor.root);
63
+ Object.freeze(operationDescriptor);
64
+ }
65
+ return operationDescriptor;
66
+ }
67
+
68
+ function createRequestDescriptor(
69
+ request: ConcreteRequest,
70
+ variables: Variables,
71
+ ): RequestDescriptor {
72
+ const requestDescriptor = {
73
+ identifier: getRequestIdentifier(request.params, variables),
74
+ node: request,
75
+ variables: variables,
76
+ };
77
+ if (__DEV__) {
78
+ deepFreeze(variables);
79
+ Object.freeze(request);
80
+ Object.freeze(requestDescriptor);
81
+ }
82
+ return requestDescriptor;
83
+ }
84
+
85
+ module.exports = {
86
+ createOperationDescriptor,
87
+ createRequestDescriptor,
88
+ };