relay-runtime 8.0.0 → 10.0.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 (135) hide show
  1. package/handlers/RelayDefaultHandlerProvider.js.flow +41 -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 +88 -0
  5. package/index.js +1 -1
  6. package/index.js.flow +320 -0
  7. package/lib/handlers/RelayDefaultHandlerProvider.js +13 -2
  8. package/lib/handlers/connection/{RelayConnectionHandler.js → ConnectionHandler.js} +33 -35
  9. package/lib/handlers/connection/{RelayConnectionInterface.js → ConnectionInterface.js} +2 -2
  10. package/lib/handlers/connection/MutationHandlers.js +86 -0
  11. package/lib/index.js +15 -19
  12. package/lib/mutations/RelayDeclarativeMutationConfig.js +29 -52
  13. package/lib/mutations/RelayRecordProxy.js +1 -3
  14. package/lib/mutations/RelayRecordSourceMutator.js +2 -9
  15. package/lib/mutations/RelayRecordSourceProxy.js +2 -4
  16. package/lib/mutations/RelayRecordSourceSelectorProxy.js +1 -13
  17. package/lib/mutations/commitMutation.js +13 -3
  18. package/lib/mutations/validateMutation.js +16 -9
  19. package/lib/network/RelayObservable.js +9 -9
  20. package/lib/network/RelayQueryResponseCache.js +8 -6
  21. package/lib/query/PreloadableQueryRegistry.js +70 -0
  22. package/lib/query/fetchQueryInternal.js +31 -23
  23. package/lib/store/DataChecker.js +122 -110
  24. package/lib/store/RelayConcreteVariables.js +6 -2
  25. package/lib/store/RelayModernEnvironment.js +121 -67
  26. package/lib/store/RelayModernFragmentSpecResolver.js +12 -16
  27. package/lib/store/RelayModernQueryExecutor.js +389 -314
  28. package/lib/store/RelayModernRecord.js +14 -9
  29. package/lib/store/RelayModernSelector.js +7 -3
  30. package/lib/store/RelayModernStore.js +289 -484
  31. package/lib/store/RelayOperationTracker.js +35 -78
  32. package/lib/store/RelayOptimisticRecordSource.js +7 -5
  33. package/lib/store/RelayPublishQueue.js +6 -33
  34. package/lib/store/RelayReader.js +113 -45
  35. package/lib/store/RelayRecordSource.js +2 -9
  36. package/lib/store/RelayRecordSourceMapImpl.js +13 -18
  37. package/lib/store/RelayReferenceMarker.js +40 -60
  38. package/lib/store/RelayResponseNormalizer.js +158 -193
  39. package/lib/store/RelayStoreUtils.js +1 -0
  40. package/lib/store/StoreInspector.js +8 -8
  41. package/lib/store/TypeID.js +28 -0
  42. package/lib/store/cloneRelayScalarHandleSourceField.js +44 -0
  43. package/lib/store/normalizeRelayPayload.js +6 -2
  44. package/lib/store/readInlineData.js +1 -1
  45. package/lib/subscription/requestSubscription.js +5 -3
  46. package/lib/util/RelayConcreteNode.js +9 -6
  47. package/lib/util/RelayError.js +39 -9
  48. package/lib/util/RelayFeatureFlags.js +2 -5
  49. package/lib/util/RelayReplaySubject.js +3 -3
  50. package/lib/util/createPayloadFor3DField.js +7 -2
  51. package/lib/util/getRequestIdentifier.js +2 -2
  52. package/lib/util/recycleNodesInto.js +2 -6
  53. package/mutations/RelayDeclarativeMutationConfig.js.flow +380 -0
  54. package/mutations/RelayRecordProxy.js.flow +165 -0
  55. package/mutations/RelayRecordSourceMutator.js.flow +238 -0
  56. package/mutations/RelayRecordSourceProxy.js.flow +164 -0
  57. package/mutations/RelayRecordSourceSelectorProxy.js.flow +119 -0
  58. package/mutations/applyOptimisticMutation.js.flow +76 -0
  59. package/mutations/commitLocalUpdate.js.flow +24 -0
  60. package/mutations/commitMutation.js.flow +182 -0
  61. package/mutations/validateMutation.js.flow +213 -0
  62. package/network/ConvertToExecuteFunction.js.flow +49 -0
  63. package/network/RelayNetwork.js.flow +84 -0
  64. package/network/RelayNetworkTypes.js.flow +123 -0
  65. package/network/RelayObservable.js.flow +634 -0
  66. package/network/RelayQueryResponseCache.js.flow +111 -0
  67. package/package.json +1 -1
  68. package/query/GraphQLTag.js.flow +166 -0
  69. package/query/PreloadableQueryRegistry.js.flow +65 -0
  70. package/query/fetchQuery.js.flow +47 -0
  71. package/query/fetchQueryInternal.js.flow +348 -0
  72. package/relay-runtime.js +2 -2
  73. package/relay-runtime.min.js +2 -2
  74. package/store/ClientID.js.flow +43 -0
  75. package/store/DataChecker.js.flow +502 -0
  76. package/store/RelayConcreteVariables.js.flow +96 -0
  77. package/store/RelayModernEnvironment.js.flow +551 -0
  78. package/store/RelayModernFragmentSpecResolver.js.flow +426 -0
  79. package/store/RelayModernOperationDescriptor.js.flow +88 -0
  80. package/store/RelayModernQueryExecutor.js.flow +1321 -0
  81. package/store/RelayModernRecord.js.flow +403 -0
  82. package/store/RelayModernSelector.js.flow +455 -0
  83. package/store/RelayModernStore.js.flow +842 -0
  84. package/store/RelayOperationTracker.js.flow +164 -0
  85. package/store/RelayOptimisticRecordSource.js.flow +119 -0
  86. package/store/RelayPublishQueue.js.flow +401 -0
  87. package/store/RelayReader.js.flow +473 -0
  88. package/store/RelayRecordSource.js.flow +29 -0
  89. package/store/RelayRecordSourceMapImpl.js.flow +87 -0
  90. package/store/RelayRecordState.js.flow +37 -0
  91. package/store/RelayReferenceMarker.js.flow +257 -0
  92. package/store/RelayResponseNormalizer.js.flow +680 -0
  93. package/store/RelayStoreTypes.js.flow +899 -0
  94. package/store/RelayStoreUtils.js.flow +219 -0
  95. package/store/StoreInspector.js.flow +171 -0
  96. package/store/TypeID.js.flow +28 -0
  97. package/store/ViewerPattern.js.flow +26 -0
  98. package/store/cloneRelayHandleSourceField.js.flow +66 -0
  99. package/store/cloneRelayScalarHandleSourceField.js.flow +62 -0
  100. package/store/createFragmentSpecResolver.js.flow +55 -0
  101. package/store/createRelayContext.js.flow +44 -0
  102. package/store/defaultGetDataID.js.flow +27 -0
  103. package/store/hasOverlappingIDs.js.flow +34 -0
  104. package/store/isRelayModernEnvironment.js.flow +27 -0
  105. package/store/normalizeRelayPayload.js.flow +51 -0
  106. package/store/readInlineData.js.flow +75 -0
  107. package/subscription/requestSubscription.js.flow +100 -0
  108. package/util/JSResourceTypes.flow.js.flow +20 -0
  109. package/util/NormalizationNode.js.flow +198 -0
  110. package/util/ReaderNode.js.flow +208 -0
  111. package/util/RelayConcreteNode.js.flow +93 -0
  112. package/util/RelayDefaultHandleKey.js.flow +17 -0
  113. package/util/RelayError.js.flow +62 -0
  114. package/util/RelayFeatureFlags.js.flow +30 -0
  115. package/util/RelayProfiler.js.flow +284 -0
  116. package/util/RelayReplaySubject.js.flow +135 -0
  117. package/util/RelayRuntimeTypes.js.flow +72 -0
  118. package/util/createPayloadFor3DField.js.flow +43 -0
  119. package/util/deepFreeze.js.flow +36 -0
  120. package/util/generateID.js.flow +21 -0
  121. package/util/getFragmentIdentifier.js.flow +52 -0
  122. package/util/getRelayHandleKey.js.flow +41 -0
  123. package/util/getRequestIdentifier.js.flow +42 -0
  124. package/util/isPromise.js.flow +21 -0
  125. package/util/isScalarAndEqual.js.flow +26 -0
  126. package/util/recycleNodesInto.js.flow +76 -0
  127. package/util/resolveImmediate.js.flow +30 -0
  128. package/util/stableCopy.js.flow +35 -0
  129. package/lib/handlers/RelayDefaultMissingFieldHandlers.js +0 -26
  130. package/lib/handlers/getRelayDefaultMissingFieldHandlers.js +0 -36
  131. package/lib/query/RelayModernGraphQLTag.js +0 -104
  132. package/lib/store/RelayConnection.js +0 -37
  133. package/lib/store/RelayConnectionResolver.js +0 -178
  134. package/lib/store/RelayRecordSourceObjectImpl.js +0 -79
  135. package/lib/util/getFragmentSpecIdentifier.js +0 -27
@@ -0,0 +1,473 @@
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 RelayFeatureFlags = require('../util/RelayFeatureFlags');
16
+ const RelayModernRecord = require('./RelayModernRecord');
17
+
18
+ const invariant = require('invariant');
19
+
20
+ const {
21
+ CLIENT_EXTENSION,
22
+ CONDITION,
23
+ DEFER,
24
+ FRAGMENT_SPREAD,
25
+ INLINE_DATA_FRAGMENT_SPREAD,
26
+ INLINE_FRAGMENT,
27
+ LINKED_FIELD,
28
+ MODULE_IMPORT,
29
+ SCALAR_FIELD,
30
+ STREAM,
31
+ } = require('../util/RelayConcreteNode');
32
+ const {
33
+ FRAGMENTS_KEY,
34
+ FRAGMENT_OWNER_KEY,
35
+ FRAGMENT_PROP_NAME_KEY,
36
+ ID_KEY,
37
+ IS_WITHIN_UNMATCHED_TYPE_REFINEMENT,
38
+ MODULE_COMPONENT_KEY,
39
+ ROOT_ID,
40
+ getArgumentValues,
41
+ getStorageKey,
42
+ getModuleComponentKey,
43
+ } = require('./RelayStoreUtils');
44
+ const {generateTypeID} = require('./TypeID');
45
+
46
+ import type {
47
+ ReaderFragmentSpread,
48
+ ReaderInlineDataFragmentSpread,
49
+ ReaderLinkedField,
50
+ ReaderModuleImport,
51
+ ReaderNode,
52
+ ReaderScalarField,
53
+ ReaderSelection,
54
+ } from '../util/ReaderNode';
55
+ import type {DataID, Variables} from '../util/RelayRuntimeTypes';
56
+ import type {
57
+ Record,
58
+ RecordSource,
59
+ RequestDescriptor,
60
+ SelectorData,
61
+ SingularReaderSelector,
62
+ Snapshot,
63
+ } from './RelayStoreTypes';
64
+
65
+ function read(
66
+ recordSource: RecordSource,
67
+ selector: SingularReaderSelector,
68
+ ): Snapshot {
69
+ const reader = new RelayReader(recordSource, selector);
70
+ return reader.read();
71
+ }
72
+
73
+ /**
74
+ * @private
75
+ */
76
+ class RelayReader {
77
+ _isMissingData: boolean;
78
+ _isWithinUnmatchedTypeRefinement: boolean;
79
+ _owner: RequestDescriptor;
80
+ _recordSource: RecordSource;
81
+ _seenRecords: {[dataID: DataID]: ?Record, ...};
82
+ _selector: SingularReaderSelector;
83
+ _variables: Variables;
84
+
85
+ constructor(recordSource: RecordSource, selector: SingularReaderSelector) {
86
+ this._isMissingData = false;
87
+ this._isWithinUnmatchedTypeRefinement = false;
88
+ this._owner = selector.owner;
89
+ this._recordSource = recordSource;
90
+ this._seenRecords = {};
91
+ this._selector = selector;
92
+ this._variables = selector.variables;
93
+ }
94
+
95
+ read(): Snapshot {
96
+ const {node, dataID, isWithinUnmatchedTypeRefinement} = this._selector;
97
+ const {abstractKey} = node;
98
+ const record = this._recordSource.get(dataID);
99
+
100
+ // Relay historically allowed child fragments to be read even if the root object
101
+ // did not match the type of the fragment: either the root object has a different
102
+ // concrete type than the fragment (for concrete fragments) or the root object does
103
+ // not conform to the interface/union for abstract fragments.
104
+ // For suspense purposes, however, we want to accurately compute whether any data
105
+ // is missing: but if the fragment type doesn't match (or a parent type didn't
106
+ // match), then no data is expected to be present.
107
+
108
+ // By default data is expected to be present unless this selector was read out
109
+ // from within a non-matching type refinement in a parent fragment:
110
+ let isDataExpectedToBePresent = !isWithinUnmatchedTypeRefinement;
111
+
112
+ // If this is a concrete fragment and the concrete type of the record does not
113
+ // match, then no data is expected to be present.
114
+ if (isDataExpectedToBePresent && abstractKey == null && record != null) {
115
+ const recordType = RelayModernRecord.getType(record);
116
+ if (recordType !== node.type && dataID !== ROOT_ID) {
117
+ isDataExpectedToBePresent = false;
118
+ }
119
+ }
120
+
121
+ // If this is an abstract fragment (and the precise refinement GK is enabled)
122
+ // then data is only expected to be present if the record type is known to
123
+ // implement the interface. If we aren't sure whether the record implements
124
+ // the interface, that itself constitutes "expected" data being missing.
125
+ if (
126
+ isDataExpectedToBePresent &&
127
+ abstractKey != null &&
128
+ record != null &&
129
+ RelayFeatureFlags.ENABLE_PRECISE_TYPE_REFINEMENT
130
+ ) {
131
+ const recordType = RelayModernRecord.getType(record);
132
+ const typeID = generateTypeID(recordType);
133
+ const typeRecord = this._recordSource.get(typeID);
134
+ const implementsInterface =
135
+ typeRecord != null
136
+ ? RelayModernRecord.getValue(typeRecord, abstractKey)
137
+ : null;
138
+ if (implementsInterface === false) {
139
+ // Type known to not implement the interface
140
+ isDataExpectedToBePresent = false;
141
+ } else if (implementsInterface == null) {
142
+ // Don't know if the type implements the interface or not
143
+ this._isMissingData = true;
144
+ }
145
+ }
146
+
147
+ this._isWithinUnmatchedTypeRefinement = !isDataExpectedToBePresent;
148
+ const data = this._traverse(node, dataID, null);
149
+ return {
150
+ data,
151
+ isMissingData: this._isMissingData && isDataExpectedToBePresent,
152
+ seenRecords: this._seenRecords,
153
+ selector: this._selector,
154
+ };
155
+ }
156
+
157
+ _traverse(
158
+ node: ReaderNode,
159
+ dataID: DataID,
160
+ prevData: ?SelectorData,
161
+ ): ?SelectorData {
162
+ const record = this._recordSource.get(dataID);
163
+ this._seenRecords[dataID] = record;
164
+ if (record == null) {
165
+ if (record === undefined) {
166
+ this._isMissingData = true;
167
+ }
168
+ return record;
169
+ }
170
+ const data = prevData || {};
171
+ this._traverseSelections(node.selections, record, data);
172
+ return data;
173
+ }
174
+
175
+ _getVariableValue(name: string): mixed {
176
+ invariant(
177
+ this._variables.hasOwnProperty(name),
178
+ 'RelayReader(): Undefined variable `%s`.',
179
+ name,
180
+ );
181
+ return this._variables[name];
182
+ }
183
+
184
+ _traverseSelections(
185
+ selections: $ReadOnlyArray<ReaderSelection>,
186
+ record: Record,
187
+ data: SelectorData,
188
+ ): void {
189
+ for (let i = 0; i < selections.length; i++) {
190
+ const selection = selections[i];
191
+ switch (selection.kind) {
192
+ case SCALAR_FIELD:
193
+ this._readScalar(selection, record, data);
194
+ break;
195
+ case LINKED_FIELD:
196
+ if (selection.plural) {
197
+ this._readPluralLink(selection, record, data);
198
+ } else {
199
+ this._readLink(selection, record, data);
200
+ }
201
+ break;
202
+ case CONDITION:
203
+ const conditionValue = this._getVariableValue(selection.condition);
204
+ if (conditionValue === selection.passingValue) {
205
+ this._traverseSelections(selection.selections, record, data);
206
+ }
207
+ break;
208
+ case INLINE_FRAGMENT: {
209
+ const {abstractKey} = selection;
210
+ if (abstractKey == null) {
211
+ // concrete type refinement: only read data if the type exactly matches
212
+ const typeName = RelayModernRecord.getType(record);
213
+ if (typeName != null && typeName === selection.type) {
214
+ this._traverseSelections(selection.selections, record, data);
215
+ }
216
+ } else if (RelayFeatureFlags.ENABLE_PRECISE_TYPE_REFINEMENT) {
217
+ // Similar to the logic in read(): data is only expected to be present
218
+ // if the record is known to conform to the interface. If we don't know
219
+ // whether the type conforms or not, that constitutes missing data.
220
+
221
+ // store flags to reset after reading
222
+ const parentIsMissingData = this._isMissingData;
223
+ const parentIsWithinUnmatchedTypeRefinement = this
224
+ ._isWithinUnmatchedTypeRefinement;
225
+
226
+ const typeName = RelayModernRecord.getType(record);
227
+ const typeID = generateTypeID(typeName);
228
+ const typeRecord = this._recordSource.get(typeID);
229
+ const implementsInterface =
230
+ typeRecord != null
231
+ ? RelayModernRecord.getValue(typeRecord, abstractKey)
232
+ : null;
233
+ this._isWithinUnmatchedTypeRefinement =
234
+ parentIsWithinUnmatchedTypeRefinement ||
235
+ implementsInterface === false;
236
+ this._traverseSelections(selection.selections, record, data);
237
+ this._isWithinUnmatchedTypeRefinement = parentIsWithinUnmatchedTypeRefinement;
238
+
239
+ if (implementsInterface === false) {
240
+ // Type known to not implement the interface, no data expected
241
+ this._isMissingData = parentIsMissingData;
242
+ } else if (implementsInterface == null) {
243
+ // Don't know if the type implements the interface or not
244
+ this._isMissingData = true;
245
+ }
246
+ } else {
247
+ // legacy behavior for abstract refinements: always read even
248
+ // if the type doesn't conform and don't reset isMissingData
249
+ this._traverseSelections(selection.selections, record, data);
250
+ }
251
+ break;
252
+ }
253
+ case FRAGMENT_SPREAD:
254
+ this._createFragmentPointer(selection, record, data);
255
+ break;
256
+ case MODULE_IMPORT:
257
+ this._readModuleImport(selection, record, data);
258
+ break;
259
+ case INLINE_DATA_FRAGMENT_SPREAD:
260
+ this._createInlineDataFragmentPointer(selection, record, data);
261
+ break;
262
+ case DEFER:
263
+ case CLIENT_EXTENSION:
264
+ const isMissingData = this._isMissingData;
265
+ this._traverseSelections(selection.selections, record, data);
266
+ this._isMissingData = isMissingData;
267
+ break;
268
+ case STREAM:
269
+ this._traverseSelections(selection.selections, record, data);
270
+ break;
271
+ default:
272
+ (selection: empty);
273
+ invariant(
274
+ false,
275
+ 'RelayReader(): Unexpected ast kind `%s`.',
276
+ selection.kind,
277
+ );
278
+ }
279
+ }
280
+ }
281
+
282
+ _readScalar(
283
+ field: ReaderScalarField,
284
+ record: Record,
285
+ data: SelectorData,
286
+ ): void {
287
+ const applicationName = field.alias ?? field.name;
288
+ const storageKey = getStorageKey(field, this._variables);
289
+ const value = RelayModernRecord.getValue(record, storageKey);
290
+ if (value === undefined) {
291
+ this._isMissingData = true;
292
+ }
293
+ data[applicationName] = value;
294
+ }
295
+
296
+ _readLink(
297
+ field: ReaderLinkedField,
298
+ record: Record,
299
+ data: SelectorData,
300
+ ): void {
301
+ const applicationName = field.alias ?? field.name;
302
+ const storageKey = getStorageKey(field, this._variables);
303
+ const linkedID = RelayModernRecord.getLinkedRecordID(record, storageKey);
304
+ if (linkedID == null) {
305
+ data[applicationName] = linkedID;
306
+ if (linkedID === undefined) {
307
+ this._isMissingData = true;
308
+ }
309
+ return;
310
+ }
311
+
312
+ const prevData = data[applicationName];
313
+ invariant(
314
+ prevData == null || typeof prevData === 'object',
315
+ 'RelayReader(): Expected data for field `%s` on record `%s` ' +
316
+ 'to be an object, got `%s`.',
317
+ applicationName,
318
+ RelayModernRecord.getDataID(record),
319
+ prevData,
320
+ );
321
+ // $FlowFixMe[incompatible-variance]
322
+ data[applicationName] = this._traverse(field, linkedID, prevData);
323
+ }
324
+
325
+ _readPluralLink(
326
+ field: ReaderLinkedField,
327
+ record: Record,
328
+ data: SelectorData,
329
+ ): void {
330
+ const applicationName = field.alias ?? field.name;
331
+ const storageKey = getStorageKey(field, this._variables);
332
+ const linkedIDs = RelayModernRecord.getLinkedRecordIDs(record, storageKey);
333
+
334
+ if (linkedIDs == null) {
335
+ data[applicationName] = linkedIDs;
336
+ if (linkedIDs === undefined) {
337
+ this._isMissingData = true;
338
+ }
339
+ return;
340
+ }
341
+
342
+ const prevData = data[applicationName];
343
+ invariant(
344
+ prevData == null || Array.isArray(prevData),
345
+ 'RelayReader(): Expected data for field `%s` on record `%s` ' +
346
+ 'to be an array, got `%s`.',
347
+ applicationName,
348
+ RelayModernRecord.getDataID(record),
349
+ prevData,
350
+ );
351
+ const linkedArray = prevData || [];
352
+ linkedIDs.forEach((linkedID, nextIndex) => {
353
+ if (linkedID == null) {
354
+ if (linkedID === undefined) {
355
+ this._isMissingData = true;
356
+ }
357
+ // $FlowFixMe[cannot-write]
358
+ linkedArray[nextIndex] = linkedID;
359
+ return;
360
+ }
361
+ const prevItem = linkedArray[nextIndex];
362
+ invariant(
363
+ prevItem == null || typeof prevItem === 'object',
364
+ 'RelayReader(): Expected data for field `%s` on record `%s` ' +
365
+ 'to be an object, got `%s`.',
366
+ applicationName,
367
+ RelayModernRecord.getDataID(record),
368
+ prevItem,
369
+ );
370
+ // $FlowFixMe[cannot-write]
371
+ // $FlowFixMe[incompatible-variance]
372
+ linkedArray[nextIndex] = this._traverse(field, linkedID, prevItem);
373
+ });
374
+ data[applicationName] = linkedArray;
375
+ }
376
+
377
+ /**
378
+ * Reads a ReaderModuleImport, which was generated from using the @module
379
+ * directive.
380
+ */
381
+ _readModuleImport(
382
+ moduleImport: ReaderModuleImport,
383
+ record: Record,
384
+ data: SelectorData,
385
+ ): void {
386
+ // Determine the component module from the store: if the field is missing
387
+ // it means we don't know what component to render the match with.
388
+ const componentKey = getModuleComponentKey(moduleImport.documentName);
389
+ const component = RelayModernRecord.getValue(record, componentKey);
390
+ if (component == null) {
391
+ if (component === undefined) {
392
+ this._isMissingData = true;
393
+ }
394
+ return;
395
+ }
396
+
397
+ // Otherwise, read the fragment and module associated to the concrete
398
+ // type, and put that data with the result:
399
+ // - For the matched fragment, create the relevant fragment pointer and add
400
+ // the expected fragmentPropName
401
+ // - For the matched module, create a reference to the module
402
+ this._createFragmentPointer(
403
+ {
404
+ kind: 'FragmentSpread',
405
+ name: moduleImport.fragmentName,
406
+ args: null,
407
+ },
408
+ record,
409
+ data,
410
+ );
411
+ data[FRAGMENT_PROP_NAME_KEY] = moduleImport.fragmentPropName;
412
+ data[MODULE_COMPONENT_KEY] = component;
413
+ }
414
+
415
+ _createFragmentPointer(
416
+ fragmentSpread: ReaderFragmentSpread,
417
+ record: Record,
418
+ data: SelectorData,
419
+ ): void {
420
+ let fragmentPointers = data[FRAGMENTS_KEY];
421
+ if (fragmentPointers == null) {
422
+ fragmentPointers = data[FRAGMENTS_KEY] = {};
423
+ }
424
+ invariant(
425
+ typeof fragmentPointers === 'object' && fragmentPointers != null,
426
+ 'RelayReader: Expected fragment spread data to be an object, got `%s`.',
427
+ fragmentPointers,
428
+ );
429
+ if (data[ID_KEY] == null) {
430
+ data[ID_KEY] = RelayModernRecord.getDataID(record);
431
+ }
432
+ // $FlowFixMe[cannot-write] - writing into read-only field
433
+ fragmentPointers[fragmentSpread.name] = fragmentSpread.args
434
+ ? getArgumentValues(fragmentSpread.args, this._variables)
435
+ : {};
436
+ data[FRAGMENT_OWNER_KEY] = this._owner;
437
+
438
+ if (RelayFeatureFlags.ENABLE_PRECISE_TYPE_REFINEMENT) {
439
+ data[
440
+ IS_WITHIN_UNMATCHED_TYPE_REFINEMENT
441
+ ] = this._isWithinUnmatchedTypeRefinement;
442
+ }
443
+ }
444
+
445
+ _createInlineDataFragmentPointer(
446
+ inlineDataFragmentSpread: ReaderInlineDataFragmentSpread,
447
+ record: Record,
448
+ data: SelectorData,
449
+ ): void {
450
+ let fragmentPointers = data[FRAGMENTS_KEY];
451
+ if (fragmentPointers == null) {
452
+ fragmentPointers = data[FRAGMENTS_KEY] = {};
453
+ }
454
+ invariant(
455
+ typeof fragmentPointers === 'object' && fragmentPointers != null,
456
+ 'RelayReader: Expected fragment spread data to be an object, got `%s`.',
457
+ fragmentPointers,
458
+ );
459
+ if (data[ID_KEY] == null) {
460
+ data[ID_KEY] = RelayModernRecord.getDataID(record);
461
+ }
462
+ const inlineData = {};
463
+ this._traverseSelections(
464
+ inlineDataFragmentSpread.selections,
465
+ record,
466
+ inlineData,
467
+ );
468
+ // $FlowFixMe[cannot-write] - writing into read-only field
469
+ fragmentPointers[inlineDataFragmentSpread.name] = inlineData;
470
+ }
471
+ }
472
+
473
+ module.exports = {read};
@@ -0,0 +1,29 @@
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 RelayRecordSourceMapImpl = require('./RelayRecordSourceMapImpl');
16
+
17
+ import type {MutableRecordSource, RecordMap} from './RelayStoreTypes';
18
+
19
+ class RelayRecordSource {
20
+ constructor(records?: RecordMap): MutableRecordSource {
21
+ return RelayRecordSource.create(records);
22
+ }
23
+
24
+ static create(records?: RecordMap): MutableRecordSource {
25
+ return new RelayRecordSourceMapImpl(records);
26
+ }
27
+ }
28
+
29
+ module.exports = RelayRecordSource;
@@ -0,0 +1,87 @@
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 RelayRecordState = require('./RelayRecordState');
16
+
17
+ import type {DataID} from '../util/RelayRuntimeTypes';
18
+ import type {RecordState} from './RelayRecordState';
19
+ import type {MutableRecordSource, Record, RecordMap} from './RelayStoreTypes';
20
+
21
+ const {EXISTENT, NONEXISTENT, UNKNOWN} = RelayRecordState;
22
+
23
+ /**
24
+ * An implementation of the `MutableRecordSource` interface (defined in
25
+ * `RelayStoreTypes`) that holds all records in memory (JS Map).
26
+ */
27
+ class RelayMapRecordSourceMapImpl implements MutableRecordSource {
28
+ _records: Map<DataID, ?Record>;
29
+
30
+ constructor(records?: RecordMap) {
31
+ this._records = new Map();
32
+ if (records != null) {
33
+ Object.keys(records).forEach(key => {
34
+ this._records.set(key, records[key]);
35
+ });
36
+ }
37
+ }
38
+
39
+ clear(): void {
40
+ this._records = new Map();
41
+ }
42
+
43
+ delete(dataID: DataID): void {
44
+ this._records.set(dataID, null);
45
+ }
46
+
47
+ get(dataID: DataID): ?Record {
48
+ return this._records.get(dataID);
49
+ }
50
+
51
+ getRecordIDs(): Array<DataID> {
52
+ return Array.from(this._records.keys());
53
+ }
54
+
55
+ getStatus(dataID: DataID): RecordState {
56
+ if (!this._records.has(dataID)) {
57
+ return UNKNOWN;
58
+ }
59
+ return this._records.get(dataID) == null ? NONEXISTENT : EXISTENT;
60
+ }
61
+
62
+ has(dataID: DataID): boolean {
63
+ return this._records.has(dataID);
64
+ }
65
+
66
+ remove(dataID: DataID): void {
67
+ this._records.delete(dataID);
68
+ }
69
+
70
+ set(dataID: DataID, record: Record): void {
71
+ this._records.set(dataID, record);
72
+ }
73
+
74
+ size(): number {
75
+ return this._records.size;
76
+ }
77
+
78
+ toJSON(): {[DataID]: ?Record, ...} {
79
+ const obj = {};
80
+ for (const [key, value] of this._records) {
81
+ obj[key] = value;
82
+ }
83
+ return obj;
84
+ }
85
+ }
86
+
87
+ module.exports = RelayMapRecordSourceMapImpl;
@@ -0,0 +1,37 @@
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
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+
13
+ 'use strict';
14
+
15
+ export type RecordState = $Keys<typeof RelayRecordState>;
16
+
17
+ const RelayRecordState = {
18
+ /**
19
+ * Record exists (either fetched from the server or produced by a local,
20
+ * optimistic update).
21
+ */
22
+ EXISTENT: 'EXISTENT',
23
+
24
+ /**
25
+ * Record is known not to exist (either as the result of a mutation, or
26
+ * because the server returned `null` when queried for the record).
27
+ */
28
+ NONEXISTENT: 'NONEXISTENT',
29
+
30
+ /**
31
+ * Record State is unknown because it has not yet been fetched from the
32
+ * server.
33
+ */
34
+ UNKNOWN: 'UNKNOWN',
35
+ };
36
+
37
+ module.exports = RelayRecordState;