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