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.
- package/handlers/RelayDefaultHandlerProvider.js.flow +34 -0
- package/handlers/connection/ConnectionHandler.js.flow +549 -0
- package/handlers/connection/ConnectionInterface.js.flow +92 -0
- package/index.js +1 -1
- package/index.js.flow +314 -0
- package/lib/handlers/RelayDefaultHandlerProvider.js +3 -2
- package/lib/handlers/connection/{RelayConnectionHandler.js → ConnectionHandler.js} +34 -35
- package/lib/handlers/connection/{RelayConnectionInterface.js → ConnectionInterface.js} +3 -30
- package/lib/index.js +29 -27
- package/lib/mutations/RelayDeclarativeMutationConfig.js +30 -52
- package/lib/mutations/RelayRecordProxy.js +6 -3
- package/lib/mutations/RelayRecordSourceMutator.js +3 -9
- package/lib/mutations/RelayRecordSourceProxy.js +21 -24
- package/lib/mutations/RelayRecordSourceSelectorProxy.js +18 -14
- package/lib/mutations/applyOptimisticMutation.js +2 -1
- package/lib/mutations/commitLocalUpdate.js +1 -0
- package/lib/mutations/commitMutation.js +26 -8
- package/lib/mutations/validateMutation.js +21 -11
- package/lib/network/ConvertToExecuteFunction.js +1 -0
- package/lib/network/RelayNetwork.js +1 -0
- package/lib/network/RelayNetworkTypes.js +1 -0
- package/lib/network/RelayObservable.js +10 -9
- package/lib/network/RelayQueryResponseCache.js +9 -7
- package/lib/query/{RelayModernGraphQLTag.js → GraphQLTag.js} +15 -8
- package/lib/query/fetchQuery.js +2 -1
- package/lib/query/fetchQueryInternal.js +30 -20
- package/lib/store/ClientID.js +1 -0
- package/lib/store/DataChecker.js +47 -97
- package/lib/store/RelayConcreteVariables.js +7 -2
- package/lib/store/RelayModernEnvironment.js +82 -41
- package/lib/store/RelayModernFragmentSpecResolver.js +61 -21
- package/lib/store/RelayModernOperationDescriptor.js +2 -1
- package/lib/store/RelayModernQueryExecutor.js +476 -333
- package/lib/store/RelayModernRecord.js +39 -9
- package/lib/store/RelayModernSelector.js +2 -1
- package/lib/store/RelayModernStore.js +359 -371
- package/lib/store/RelayOperationTracker.js +36 -78
- package/lib/store/RelayOptimisticRecordSource.js +8 -5
- package/lib/store/RelayPublishQueue.js +66 -53
- package/lib/store/RelayReader.js +2 -24
- package/lib/store/RelayRecordSource.js +3 -9
- package/lib/store/RelayRecordSourceMapImpl.js +14 -18
- package/lib/store/RelayRecordState.js +1 -0
- package/lib/store/RelayReferenceMarker.js +8 -58
- package/lib/store/RelayResponseNormalizer.js +15 -144
- package/lib/store/RelayStoreTypes.js +1 -0
- package/lib/store/RelayStoreUtils.js +34 -10
- package/lib/store/StoreInspector.js +11 -5
- package/lib/store/ViewerPattern.js +1 -0
- package/lib/store/cloneRelayHandleSourceField.js +1 -0
- package/lib/store/createFragmentSpecResolver.js +1 -0
- package/lib/store/createRelayContext.js +1 -0
- package/lib/store/defaultGetDataID.js +1 -0
- package/lib/store/hasOverlappingIDs.js +1 -0
- package/lib/store/isRelayModernEnvironment.js +1 -0
- package/lib/store/normalizeRelayPayload.js +8 -4
- package/lib/store/readInlineData.js +2 -1
- package/lib/subscription/requestSubscription.js +6 -3
- package/lib/util/JSResourceTypes.flow.js +12 -0
- package/lib/util/NormalizationNode.js +1 -0
- package/lib/util/ReaderNode.js +1 -0
- package/lib/util/RelayConcreteNode.js +3 -0
- package/lib/util/RelayDefaultHandleKey.js +1 -0
- package/lib/util/RelayError.js +2 -1
- package/lib/util/RelayFeatureFlags.js +3 -2
- package/lib/util/RelayProfiler.js +1 -0
- package/lib/util/RelayReplaySubject.js +2 -3
- package/lib/util/RelayRuntimeTypes.js +1 -0
- package/lib/util/createPayloadFor3DField.js +34 -0
- package/lib/util/deepFreeze.js +1 -0
- package/lib/util/generateID.js +1 -0
- package/lib/util/getFragmentIdentifier.js +1 -0
- package/lib/util/getRelayHandleKey.js +1 -0
- package/lib/util/getRequestIdentifier.js +1 -0
- package/lib/util/isPromise.js +1 -0
- package/lib/util/isScalarAndEqual.js +1 -0
- package/lib/util/recycleNodesInto.js +1 -0
- package/lib/util/resolveImmediate.js +1 -0
- package/lib/util/stableCopy.js +1 -0
- package/mutations/RelayDeclarativeMutationConfig.js.flow +380 -0
- package/mutations/RelayRecordProxy.js.flow +165 -0
- package/mutations/RelayRecordSourceMutator.js.flow +238 -0
- package/mutations/RelayRecordSourceProxy.js.flow +164 -0
- package/mutations/RelayRecordSourceSelectorProxy.js.flow +119 -0
- package/mutations/applyOptimisticMutation.js.flow +76 -0
- package/mutations/commitLocalUpdate.js.flow +24 -0
- package/mutations/commitMutation.js.flow +184 -0
- package/mutations/validateMutation.js.flow +211 -0
- package/network/ConvertToExecuteFunction.js.flow +49 -0
- package/network/RelayNetwork.js.flow +84 -0
- package/network/RelayNetworkTypes.js.flow +123 -0
- package/network/RelayObservable.js.flow +634 -0
- package/network/RelayQueryResponseCache.js.flow +111 -0
- package/package.json +1 -1
- package/query/GraphQLTag.js.flow +166 -0
- package/query/fetchQuery.js.flow +47 -0
- package/query/fetchQueryInternal.js.flow +349 -0
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +2 -2
- package/store/ClientID.js.flow +43 -0
- package/store/DataChecker.js.flow +426 -0
- package/store/RelayConcreteVariables.js.flow +96 -0
- package/store/RelayModernEnvironment.js.flow +526 -0
- package/store/RelayModernFragmentSpecResolver.js.flow +426 -0
- package/store/RelayModernOperationDescriptor.js.flow +88 -0
- package/store/RelayModernQueryExecutor.js.flow +1327 -0
- package/store/RelayModernRecord.js.flow +403 -0
- package/store/RelayModernSelector.js.flow +444 -0
- package/store/RelayModernStore.js.flow +757 -0
- package/store/RelayOperationTracker.js.flow +164 -0
- package/store/RelayOptimisticRecordSource.js.flow +119 -0
- package/store/RelayPublishQueue.js.flow +401 -0
- package/store/RelayReader.js.flow +376 -0
- package/store/RelayRecordSource.js.flow +29 -0
- package/store/RelayRecordSourceMapImpl.js.flow +87 -0
- package/store/RelayRecordState.js.flow +37 -0
- package/store/RelayReferenceMarker.js.flow +236 -0
- package/store/RelayResponseNormalizer.js.flow +556 -0
- package/store/RelayStoreTypes.js.flow +873 -0
- package/store/RelayStoreUtils.js.flow +218 -0
- package/store/StoreInspector.js.flow +173 -0
- package/store/ViewerPattern.js.flow +26 -0
- package/store/cloneRelayHandleSourceField.js.flow +66 -0
- package/store/createFragmentSpecResolver.js.flow +55 -0
- package/store/createRelayContext.js.flow +44 -0
- package/store/defaultGetDataID.js.flow +27 -0
- package/store/hasOverlappingIDs.js.flow +34 -0
- package/store/isRelayModernEnvironment.js.flow +27 -0
- package/store/normalizeRelayPayload.js.flow +51 -0
- package/store/readInlineData.js.flow +75 -0
- package/subscription/requestSubscription.js.flow +100 -0
- package/util/JSResourceTypes.flow.js.flow +20 -0
- package/util/NormalizationNode.js.flow +191 -0
- package/util/ReaderNode.js.flow +208 -0
- package/util/RelayConcreteNode.js.flow +80 -0
- package/util/RelayDefaultHandleKey.js.flow +17 -0
- package/util/RelayError.js.flow +33 -0
- package/util/RelayFeatureFlags.js.flow +30 -0
- package/util/RelayProfiler.js.flow +284 -0
- package/util/RelayReplaySubject.js.flow +134 -0
- package/util/RelayRuntimeTypes.js.flow +70 -0
- package/util/createPayloadFor3DField.js.flow +43 -0
- package/util/deepFreeze.js.flow +36 -0
- package/util/generateID.js.flow +21 -0
- package/util/getFragmentIdentifier.js.flow +52 -0
- package/util/getRelayHandleKey.js.flow +41 -0
- package/util/getRequestIdentifier.js.flow +41 -0
- package/util/isPromise.js.flow +21 -0
- package/util/isScalarAndEqual.js.flow +26 -0
- package/util/recycleNodesInto.js.flow +80 -0
- package/util/resolveImmediate.js.flow +30 -0
- package/util/stableCopy.js.flow +35 -0
- package/lib/handlers/RelayDefaultMissingFieldHandlers.js +0 -26
- package/lib/store/RelayConnection.js +0 -36
- package/lib/store/RelayConnectionResolver.js +0 -177
- package/lib/store/RelayRecordSourceObjectImpl.js +0 -78
- package/lib/util/getFragmentSpecIdentifier.js +0 -26
|
@@ -0,0 +1,556 @@
|
|
|
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 RelayModernRecord = require('./RelayModernRecord');
|
|
16
|
+
const RelayProfiler = require('../util/RelayProfiler');
|
|
17
|
+
|
|
18
|
+
const invariant = require('invariant');
|
|
19
|
+
const warning = require('warning');
|
|
20
|
+
|
|
21
|
+
const {
|
|
22
|
+
CONDITION,
|
|
23
|
+
CLIENT_EXTENSION,
|
|
24
|
+
DEFER,
|
|
25
|
+
INLINE_FRAGMENT,
|
|
26
|
+
LINKED_FIELD,
|
|
27
|
+
LINKED_HANDLE,
|
|
28
|
+
MODULE_IMPORT,
|
|
29
|
+
SCALAR_FIELD,
|
|
30
|
+
SCALAR_HANDLE,
|
|
31
|
+
STREAM,
|
|
32
|
+
} = require('../util/RelayConcreteNode');
|
|
33
|
+
const {generateClientID, isClientID} = require('./ClientID');
|
|
34
|
+
const {createNormalizationSelector} = require('./RelayModernSelector');
|
|
35
|
+
const {
|
|
36
|
+
getArgumentValues,
|
|
37
|
+
getHandleStorageKey,
|
|
38
|
+
getModuleComponentKey,
|
|
39
|
+
getModuleOperationKey,
|
|
40
|
+
getStorageKey,
|
|
41
|
+
TYPENAME_KEY,
|
|
42
|
+
ROOT_ID,
|
|
43
|
+
} = require('./RelayStoreUtils');
|
|
44
|
+
|
|
45
|
+
import type {PayloadData} from '../network/RelayNetworkTypes';
|
|
46
|
+
import type {
|
|
47
|
+
NormalizationDefer,
|
|
48
|
+
NormalizationLinkedField,
|
|
49
|
+
NormalizationModuleImport,
|
|
50
|
+
NormalizationNode,
|
|
51
|
+
NormalizationScalarField,
|
|
52
|
+
NormalizationStream,
|
|
53
|
+
} from '../util/NormalizationNode';
|
|
54
|
+
import type {DataID, Variables} from '../util/RelayRuntimeTypes';
|
|
55
|
+
import type {
|
|
56
|
+
HandleFieldPayload,
|
|
57
|
+
IncrementalDataPlaceholder,
|
|
58
|
+
ModuleImportPayload,
|
|
59
|
+
MutableRecordSource,
|
|
60
|
+
NormalizationSelector,
|
|
61
|
+
Record,
|
|
62
|
+
RelayResponsePayload,
|
|
63
|
+
RequestDescriptor,
|
|
64
|
+
} from './RelayStoreTypes';
|
|
65
|
+
|
|
66
|
+
export type GetDataID = (
|
|
67
|
+
fieldValue: {[string]: mixed, ...},
|
|
68
|
+
typeName: string,
|
|
69
|
+
) => mixed;
|
|
70
|
+
|
|
71
|
+
export type NormalizationOptions = {|
|
|
72
|
+
+getDataID: GetDataID,
|
|
73
|
+
+treatMissingFieldsAsNull: boolean,
|
|
74
|
+
+path?: $ReadOnlyArray<string>,
|
|
75
|
+
+request: RequestDescriptor,
|
|
76
|
+
|};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Normalizes the results of a query and standard GraphQL response, writing the
|
|
80
|
+
* normalized records/fields into the given MutableRecordSource.
|
|
81
|
+
*/
|
|
82
|
+
function normalize(
|
|
83
|
+
recordSource: MutableRecordSource,
|
|
84
|
+
selector: NormalizationSelector,
|
|
85
|
+
response: PayloadData,
|
|
86
|
+
options: NormalizationOptions,
|
|
87
|
+
): RelayResponsePayload {
|
|
88
|
+
const {dataID, node, variables} = selector;
|
|
89
|
+
const normalizer = new RelayResponseNormalizer(
|
|
90
|
+
recordSource,
|
|
91
|
+
variables,
|
|
92
|
+
options,
|
|
93
|
+
);
|
|
94
|
+
return normalizer.normalizeResponse(node, dataID, response);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @private
|
|
99
|
+
*
|
|
100
|
+
* Helper for handling payloads.
|
|
101
|
+
*/
|
|
102
|
+
class RelayResponseNormalizer {
|
|
103
|
+
_getDataId: GetDataID;
|
|
104
|
+
_handleFieldPayloads: Array<HandleFieldPayload>;
|
|
105
|
+
_treatMissingFieldsAsNull: boolean;
|
|
106
|
+
_incrementalPlaceholders: Array<IncrementalDataPlaceholder>;
|
|
107
|
+
_isClientExtension: boolean;
|
|
108
|
+
_moduleImportPayloads: Array<ModuleImportPayload>;
|
|
109
|
+
_path: Array<string>;
|
|
110
|
+
_recordSource: MutableRecordSource;
|
|
111
|
+
_request: RequestDescriptor;
|
|
112
|
+
_variables: Variables;
|
|
113
|
+
|
|
114
|
+
constructor(
|
|
115
|
+
recordSource: MutableRecordSource,
|
|
116
|
+
variables: Variables,
|
|
117
|
+
options: NormalizationOptions,
|
|
118
|
+
) {
|
|
119
|
+
this._getDataId = options.getDataID;
|
|
120
|
+
this._handleFieldPayloads = [];
|
|
121
|
+
this._treatMissingFieldsAsNull = options.treatMissingFieldsAsNull;
|
|
122
|
+
this._incrementalPlaceholders = [];
|
|
123
|
+
this._isClientExtension = false;
|
|
124
|
+
this._moduleImportPayloads = [];
|
|
125
|
+
this._path = options.path ? [...options.path] : [];
|
|
126
|
+
this._recordSource = recordSource;
|
|
127
|
+
this._request = options.request;
|
|
128
|
+
this._variables = variables;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
normalizeResponse(
|
|
132
|
+
node: NormalizationNode,
|
|
133
|
+
dataID: DataID,
|
|
134
|
+
data: PayloadData,
|
|
135
|
+
): RelayResponsePayload {
|
|
136
|
+
const record = this._recordSource.get(dataID);
|
|
137
|
+
invariant(
|
|
138
|
+
record,
|
|
139
|
+
'RelayResponseNormalizer(): Expected root record `%s` to exist.',
|
|
140
|
+
dataID,
|
|
141
|
+
);
|
|
142
|
+
this._traverseSelections(node, record, data);
|
|
143
|
+
return {
|
|
144
|
+
errors: null,
|
|
145
|
+
fieldPayloads: this._handleFieldPayloads,
|
|
146
|
+
incrementalPlaceholders: this._incrementalPlaceholders,
|
|
147
|
+
moduleImportPayloads: this._moduleImportPayloads,
|
|
148
|
+
source: this._recordSource,
|
|
149
|
+
isFinal: false,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
_getVariableValue(name: string): mixed {
|
|
154
|
+
invariant(
|
|
155
|
+
this._variables.hasOwnProperty(name),
|
|
156
|
+
'RelayResponseNormalizer(): Undefined variable `%s`.',
|
|
157
|
+
name,
|
|
158
|
+
);
|
|
159
|
+
return this._variables[name];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
_getRecordType(data: PayloadData): string {
|
|
163
|
+
const typeName = (data: any)[TYPENAME_KEY];
|
|
164
|
+
invariant(
|
|
165
|
+
typeName != null,
|
|
166
|
+
'RelayResponseNormalizer(): Expected a typename for record `%s`.',
|
|
167
|
+
JSON.stringify(data, null, 2),
|
|
168
|
+
);
|
|
169
|
+
return typeName;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
_traverseSelections(
|
|
173
|
+
node: NormalizationNode,
|
|
174
|
+
record: Record,
|
|
175
|
+
data: PayloadData,
|
|
176
|
+
): void {
|
|
177
|
+
for (let i = 0; i < node.selections.length; i++) {
|
|
178
|
+
const selection = node.selections[i];
|
|
179
|
+
switch (selection.kind) {
|
|
180
|
+
case SCALAR_FIELD:
|
|
181
|
+
case LINKED_FIELD:
|
|
182
|
+
this._normalizeField(node, selection, record, data);
|
|
183
|
+
break;
|
|
184
|
+
case CONDITION:
|
|
185
|
+
const conditionValue = this._getVariableValue(selection.condition);
|
|
186
|
+
if (conditionValue === selection.passingValue) {
|
|
187
|
+
this._traverseSelections(selection, record, data);
|
|
188
|
+
}
|
|
189
|
+
break;
|
|
190
|
+
case INLINE_FRAGMENT:
|
|
191
|
+
const typeName = RelayModernRecord.getType(record);
|
|
192
|
+
if (typeName === selection.type) {
|
|
193
|
+
this._traverseSelections(selection, record, data);
|
|
194
|
+
}
|
|
195
|
+
break;
|
|
196
|
+
case LINKED_HANDLE:
|
|
197
|
+
case SCALAR_HANDLE:
|
|
198
|
+
const args = selection.args
|
|
199
|
+
? getArgumentValues(selection.args, this._variables)
|
|
200
|
+
: {};
|
|
201
|
+
const fieldKey = getStorageKey(selection, this._variables);
|
|
202
|
+
const handleKey = getHandleStorageKey(selection, this._variables);
|
|
203
|
+
this._handleFieldPayloads.push({
|
|
204
|
+
args,
|
|
205
|
+
dataID: RelayModernRecord.getDataID(record),
|
|
206
|
+
fieldKey,
|
|
207
|
+
handle: selection.handle,
|
|
208
|
+
handleKey,
|
|
209
|
+
});
|
|
210
|
+
break;
|
|
211
|
+
case MODULE_IMPORT:
|
|
212
|
+
this._normalizeModuleImport(node, selection, record, data);
|
|
213
|
+
break;
|
|
214
|
+
case DEFER:
|
|
215
|
+
this._normalizeDefer(selection, record, data);
|
|
216
|
+
break;
|
|
217
|
+
case STREAM:
|
|
218
|
+
this._normalizeStream(selection, record, data);
|
|
219
|
+
break;
|
|
220
|
+
case CLIENT_EXTENSION:
|
|
221
|
+
const isClientExtension = this._isClientExtension;
|
|
222
|
+
this._isClientExtension = true;
|
|
223
|
+
this._traverseSelections(selection, record, data);
|
|
224
|
+
this._isClientExtension = isClientExtension;
|
|
225
|
+
break;
|
|
226
|
+
default:
|
|
227
|
+
(selection: empty);
|
|
228
|
+
invariant(
|
|
229
|
+
false,
|
|
230
|
+
'RelayResponseNormalizer(): Unexpected ast kind `%s`.',
|
|
231
|
+
selection.kind,
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
_normalizeDefer(
|
|
238
|
+
defer: NormalizationDefer,
|
|
239
|
+
record: Record,
|
|
240
|
+
data: PayloadData,
|
|
241
|
+
) {
|
|
242
|
+
const isDeferred = defer.if === null || this._getVariableValue(defer.if);
|
|
243
|
+
if (__DEV__) {
|
|
244
|
+
warning(
|
|
245
|
+
typeof isDeferred === 'boolean',
|
|
246
|
+
'RelayResponseNormalizer: Expected value for @defer `if` argument to ' +
|
|
247
|
+
'be a boolean, got `%s`.',
|
|
248
|
+
isDeferred,
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
if (isDeferred === false) {
|
|
252
|
+
// If defer is disabled there will be no additional response chunk:
|
|
253
|
+
// normalize the data already present.
|
|
254
|
+
this._traverseSelections(defer, record, data);
|
|
255
|
+
} else {
|
|
256
|
+
// Otherwise data *for this selection* should not be present: enqueue
|
|
257
|
+
// metadata to process the subsequent response chunk.
|
|
258
|
+
this._incrementalPlaceholders.push({
|
|
259
|
+
kind: 'defer',
|
|
260
|
+
data,
|
|
261
|
+
label: defer.label,
|
|
262
|
+
path: [...this._path],
|
|
263
|
+
selector: createNormalizationSelector(
|
|
264
|
+
defer,
|
|
265
|
+
RelayModernRecord.getDataID(record),
|
|
266
|
+
this._variables,
|
|
267
|
+
),
|
|
268
|
+
typeName: RelayModernRecord.getType(record),
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
_normalizeStream(
|
|
274
|
+
stream: NormalizationStream,
|
|
275
|
+
record: Record,
|
|
276
|
+
data: PayloadData,
|
|
277
|
+
) {
|
|
278
|
+
// Always normalize regardless of whether streaming is enabled or not,
|
|
279
|
+
// this populates the initial array value (including any items when
|
|
280
|
+
// initial_count > 0).
|
|
281
|
+
this._traverseSelections(stream, record, data);
|
|
282
|
+
const isStreamed = stream.if === null || this._getVariableValue(stream.if);
|
|
283
|
+
if (__DEV__) {
|
|
284
|
+
warning(
|
|
285
|
+
typeof isStreamed === 'boolean',
|
|
286
|
+
'RelayResponseNormalizer: Expected value for @stream `if` argument ' +
|
|
287
|
+
'to be a boolean, got `%s`.',
|
|
288
|
+
isStreamed,
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
if (isStreamed === true) {
|
|
292
|
+
// If streaming is enabled, *also* emit metadata to process any
|
|
293
|
+
// response chunks that may be delivered.
|
|
294
|
+
this._incrementalPlaceholders.push({
|
|
295
|
+
kind: 'stream',
|
|
296
|
+
label: stream.label,
|
|
297
|
+
path: [...this._path],
|
|
298
|
+
parentID: RelayModernRecord.getDataID(record),
|
|
299
|
+
node: stream,
|
|
300
|
+
variables: this._variables,
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
_normalizeModuleImport(
|
|
306
|
+
parent: NormalizationNode,
|
|
307
|
+
moduleImport: NormalizationModuleImport,
|
|
308
|
+
record: Record,
|
|
309
|
+
data: PayloadData,
|
|
310
|
+
) {
|
|
311
|
+
invariant(
|
|
312
|
+
typeof data === 'object' && data,
|
|
313
|
+
'RelayResponseNormalizer: Expected data for @module to be an object.',
|
|
314
|
+
);
|
|
315
|
+
const typeName: string = RelayModernRecord.getType(record);
|
|
316
|
+
const componentKey = getModuleComponentKey(moduleImport.documentName);
|
|
317
|
+
const componentReference = data[componentKey];
|
|
318
|
+
RelayModernRecord.setValue(
|
|
319
|
+
record,
|
|
320
|
+
componentKey,
|
|
321
|
+
componentReference ?? null,
|
|
322
|
+
);
|
|
323
|
+
const operationKey = getModuleOperationKey(moduleImport.documentName);
|
|
324
|
+
const operationReference = data[operationKey];
|
|
325
|
+
RelayModernRecord.setValue(
|
|
326
|
+
record,
|
|
327
|
+
operationKey,
|
|
328
|
+
operationReference ?? null,
|
|
329
|
+
);
|
|
330
|
+
if (operationReference != null) {
|
|
331
|
+
this._moduleImportPayloads.push({
|
|
332
|
+
data,
|
|
333
|
+
dataID: RelayModernRecord.getDataID(record),
|
|
334
|
+
operationReference,
|
|
335
|
+
path: [...this._path],
|
|
336
|
+
typeName,
|
|
337
|
+
variables: this._variables,
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
_normalizeField(
|
|
343
|
+
parent: NormalizationNode,
|
|
344
|
+
selection: NormalizationLinkedField | NormalizationScalarField,
|
|
345
|
+
record: Record,
|
|
346
|
+
data: PayloadData,
|
|
347
|
+
) {
|
|
348
|
+
invariant(
|
|
349
|
+
typeof data === 'object' && data,
|
|
350
|
+
'writeField(): Expected data for field `%s` to be an object.',
|
|
351
|
+
selection.name,
|
|
352
|
+
);
|
|
353
|
+
const responseKey = selection.alias || selection.name;
|
|
354
|
+
const storageKey = getStorageKey(selection, this._variables);
|
|
355
|
+
const fieldValue = data[responseKey];
|
|
356
|
+
if (fieldValue == null) {
|
|
357
|
+
if (!this._treatMissingFieldsAsNull && fieldValue === undefined) {
|
|
358
|
+
// Fields that are missing in the response are not set on the record.
|
|
359
|
+
// There are three main cases where this can occur:
|
|
360
|
+
// - Inside a client extension: the server will not generally return
|
|
361
|
+
// values for these fields, but a local update may provide them.
|
|
362
|
+
// - Fields on abstract types: these may be missing if the concrete
|
|
363
|
+
// response type does not match the abstract type.
|
|
364
|
+
//
|
|
365
|
+
// Otherwise, missing fields usually indicate a server or user error (
|
|
366
|
+
// the latter for manually constructed payloads).
|
|
367
|
+
if (__DEV__) {
|
|
368
|
+
warning(
|
|
369
|
+
this._isClientExtension ||
|
|
370
|
+
(parent.kind === LINKED_FIELD && parent.concreteType == null)
|
|
371
|
+
? true
|
|
372
|
+
: Object.prototype.hasOwnProperty.call(data, responseKey),
|
|
373
|
+
'RelayResponseNormalizer: Payload did not contain a value ' +
|
|
374
|
+
'for field `%s: %s`. Check that you are parsing with the same ' +
|
|
375
|
+
'query that was used to fetch the payload.',
|
|
376
|
+
responseKey,
|
|
377
|
+
storageKey,
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
RelayModernRecord.setValue(record, storageKey, null);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (selection.kind === SCALAR_FIELD) {
|
|
387
|
+
RelayModernRecord.setValue(record, storageKey, fieldValue);
|
|
388
|
+
} else if (selection.kind === LINKED_FIELD) {
|
|
389
|
+
this._path.push(responseKey);
|
|
390
|
+
if (selection.plural) {
|
|
391
|
+
this._normalizePluralLink(selection, record, storageKey, fieldValue);
|
|
392
|
+
} else {
|
|
393
|
+
this._normalizeLink(selection, record, storageKey, fieldValue);
|
|
394
|
+
}
|
|
395
|
+
this._path.pop();
|
|
396
|
+
} else {
|
|
397
|
+
(selection: empty);
|
|
398
|
+
invariant(
|
|
399
|
+
false,
|
|
400
|
+
'RelayResponseNormalizer(): Unexpected ast kind `%s` during normalization.',
|
|
401
|
+
selection.kind,
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
_normalizeLink(
|
|
407
|
+
field: NormalizationLinkedField,
|
|
408
|
+
record: Record,
|
|
409
|
+
storageKey: string,
|
|
410
|
+
fieldValue: mixed,
|
|
411
|
+
): void {
|
|
412
|
+
invariant(
|
|
413
|
+
typeof fieldValue === 'object' && fieldValue,
|
|
414
|
+
'RelayResponseNormalizer: Expected data for field `%s` to be an object.',
|
|
415
|
+
storageKey,
|
|
416
|
+
);
|
|
417
|
+
const nextID =
|
|
418
|
+
this._getDataId(
|
|
419
|
+
/* $FlowFixMe(>=0.98.0 site=www,mobile,react_native_fb,oss) This comment
|
|
420
|
+
* suppresses an error found when Flow v0.98 was deployed. To see the
|
|
421
|
+
* error delete this comment and run Flow. */
|
|
422
|
+
fieldValue,
|
|
423
|
+
/* $FlowFixMe(>=0.98.0 site=www,mobile,react_native_fb,oss) This comment
|
|
424
|
+
* suppresses an error found when Flow v0.98 was deployed. To see the
|
|
425
|
+
* error delete this comment and run Flow. */
|
|
426
|
+
field.concreteType ?? this._getRecordType(fieldValue),
|
|
427
|
+
) ||
|
|
428
|
+
// Reuse previously generated client IDs
|
|
429
|
+
RelayModernRecord.getLinkedRecordID(record, storageKey) ||
|
|
430
|
+
generateClientID(RelayModernRecord.getDataID(record), storageKey);
|
|
431
|
+
invariant(
|
|
432
|
+
typeof nextID === 'string',
|
|
433
|
+
'RelayResponseNormalizer: Expected id on field `%s` to be a string.',
|
|
434
|
+
storageKey,
|
|
435
|
+
);
|
|
436
|
+
RelayModernRecord.setLinkedRecordID(record, storageKey, nextID);
|
|
437
|
+
let nextRecord = this._recordSource.get(nextID);
|
|
438
|
+
if (!nextRecord) {
|
|
439
|
+
/* $FlowFixMe(>=0.98.0 site=www,mobile,react_native_fb,oss) This comment
|
|
440
|
+
* suppresses an error found when Flow v0.98 was deployed. To see the
|
|
441
|
+
* error delete this comment and run Flow. */
|
|
442
|
+
const typeName = field.concreteType || this._getRecordType(fieldValue);
|
|
443
|
+
nextRecord = RelayModernRecord.create(nextID, typeName);
|
|
444
|
+
this._recordSource.set(nextID, nextRecord);
|
|
445
|
+
} else if (__DEV__) {
|
|
446
|
+
this._validateRecordType(nextRecord, field, fieldValue);
|
|
447
|
+
}
|
|
448
|
+
/* $FlowFixMe(>=0.98.0 site=www,mobile,react_native_fb,oss) This comment
|
|
449
|
+
* suppresses an error found when Flow v0.98 was deployed. To see the error
|
|
450
|
+
* delete this comment and run Flow. */
|
|
451
|
+
this._traverseSelections(field, nextRecord, fieldValue);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
_normalizePluralLink(
|
|
455
|
+
field: NormalizationLinkedField,
|
|
456
|
+
record: Record,
|
|
457
|
+
storageKey: string,
|
|
458
|
+
fieldValue: mixed,
|
|
459
|
+
): void {
|
|
460
|
+
invariant(
|
|
461
|
+
Array.isArray(fieldValue),
|
|
462
|
+
'RelayResponseNormalizer: Expected data for field `%s` to be an array ' +
|
|
463
|
+
'of objects.',
|
|
464
|
+
storageKey,
|
|
465
|
+
);
|
|
466
|
+
const prevIDs = RelayModernRecord.getLinkedRecordIDs(record, storageKey);
|
|
467
|
+
const nextIDs = [];
|
|
468
|
+
fieldValue.forEach((item, nextIndex) => {
|
|
469
|
+
// validate response data
|
|
470
|
+
if (item == null) {
|
|
471
|
+
nextIDs.push(item);
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
this._path.push(String(nextIndex));
|
|
475
|
+
invariant(
|
|
476
|
+
typeof item === 'object',
|
|
477
|
+
'RelayResponseNormalizer: Expected elements for field `%s` to be ' +
|
|
478
|
+
'objects.',
|
|
479
|
+
storageKey,
|
|
480
|
+
);
|
|
481
|
+
const nextID =
|
|
482
|
+
this._getDataId(
|
|
483
|
+
/* $FlowFixMe(>=0.98.0 site=www,mobile,react_native_fb,oss) This comment
|
|
484
|
+
* suppresses an error found when Flow v0.98 was deployed. To see the
|
|
485
|
+
* error delete this comment and run Flow. */
|
|
486
|
+
item,
|
|
487
|
+
/* $FlowFixMe(>=0.98.0 site=www,mobile,react_native_fb,oss) This comment
|
|
488
|
+
* suppresses an error found when Flow v0.98 was deployed. To see the
|
|
489
|
+
* error delete this comment and run Flow. */
|
|
490
|
+
field.concreteType ?? this._getRecordType(item),
|
|
491
|
+
) ||
|
|
492
|
+
(prevIDs && prevIDs[nextIndex]) || // Reuse previously generated client IDs:
|
|
493
|
+
generateClientID(
|
|
494
|
+
RelayModernRecord.getDataID(record),
|
|
495
|
+
storageKey,
|
|
496
|
+
nextIndex,
|
|
497
|
+
);
|
|
498
|
+
invariant(
|
|
499
|
+
typeof nextID === 'string',
|
|
500
|
+
'RelayResponseNormalizer: Expected id of elements of field `%s` to ' +
|
|
501
|
+
'be strings.',
|
|
502
|
+
storageKey,
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
nextIDs.push(nextID);
|
|
506
|
+
let nextRecord = this._recordSource.get(nextID);
|
|
507
|
+
if (!nextRecord) {
|
|
508
|
+
/* $FlowFixMe(>=0.98.0 site=www,mobile,react_native_fb,oss) This comment
|
|
509
|
+
* suppresses an error found when Flow v0.98 was deployed. To see the
|
|
510
|
+
* error delete this comment and run Flow. */
|
|
511
|
+
const typeName = field.concreteType || this._getRecordType(item);
|
|
512
|
+
nextRecord = RelayModernRecord.create(nextID, typeName);
|
|
513
|
+
this._recordSource.set(nextID, nextRecord);
|
|
514
|
+
} else if (__DEV__) {
|
|
515
|
+
this._validateRecordType(nextRecord, field, item);
|
|
516
|
+
}
|
|
517
|
+
/* $FlowFixMe(>=0.98.0 site=www,mobile,react_native_fb,oss) This comment
|
|
518
|
+
* suppresses an error found when Flow v0.98 was deployed. To see the
|
|
519
|
+
* error delete this comment and run Flow. */
|
|
520
|
+
this._traverseSelections(field, nextRecord, item);
|
|
521
|
+
this._path.pop();
|
|
522
|
+
});
|
|
523
|
+
RelayModernRecord.setLinkedRecordIDs(record, storageKey, nextIDs);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Warns if the type of the record does not match the type of the field/payload.
|
|
528
|
+
*/
|
|
529
|
+
_validateRecordType(
|
|
530
|
+
record: Record,
|
|
531
|
+
field: NormalizationLinkedField,
|
|
532
|
+
payload: Object,
|
|
533
|
+
): void {
|
|
534
|
+
const typeName = field.concreteType ?? this._getRecordType(payload);
|
|
535
|
+
const dataID = RelayModernRecord.getDataID(record);
|
|
536
|
+
warning(
|
|
537
|
+
(isClientID(dataID) && dataID !== ROOT_ID) ||
|
|
538
|
+
RelayModernRecord.getType(record) === typeName,
|
|
539
|
+
'RelayResponseNormalizer: Invalid record `%s`. Expected %s to be ' +
|
|
540
|
+
'consistent, but the record was assigned conflicting types `%s` ' +
|
|
541
|
+
'and `%s`. The GraphQL server likely violated the globally unique ' +
|
|
542
|
+
'id requirement by returning the same id for different objects.',
|
|
543
|
+
dataID,
|
|
544
|
+
TYPENAME_KEY,
|
|
545
|
+
RelayModernRecord.getType(record),
|
|
546
|
+
typeName,
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
const instrumentedNormalize: typeof normalize = RelayProfiler.instrument(
|
|
552
|
+
'RelayResponseNormalizer.normalize',
|
|
553
|
+
normalize,
|
|
554
|
+
);
|
|
555
|
+
|
|
556
|
+
module.exports = {normalize: instrumentedNormalize};
|