relay-runtime 13.0.0-rc.0 → 13.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +1 -1
- package/lib/store/RelayExperimentalGraphResponseHandler.js +153 -0
- package/lib/store/RelayExperimentalGraphResponseTransform.js +391 -0
- package/package.json +1 -1
- package/relay-runtime.js +1 -1
- package/relay-runtime.min.js +1 -1
- package/store/RelayExperimentalGraphResponseHandler.js.flow +124 -0
- package/store/RelayExperimentalGraphResponseTransform.js.flow +475 -0
- package/util/RelayConcreteNode.js.flow +2 -0
package/index.js
CHANGED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.handleGraphModeResponse = handleGraphModeResponse;
|
|
9
|
+
|
|
10
|
+
var _createForOfIteratorHelper2 = _interopRequireDefault(require("@babel/runtime/helpers/createForOfIteratorHelper"));
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
14
|
+
*
|
|
15
|
+
* This source code is licensed under the MIT license found in the
|
|
16
|
+
* LICENSE file in the root directory of this source tree.
|
|
17
|
+
*
|
|
18
|
+
* @emails oncall+relay
|
|
19
|
+
*
|
|
20
|
+
* @format
|
|
21
|
+
*/
|
|
22
|
+
var invariant = require('invariant');
|
|
23
|
+
|
|
24
|
+
var RelayModernRecord = require('relay-runtime/store/RelayModernRecord');
|
|
25
|
+
/**
|
|
26
|
+
* Given a stream of GraphMode chunks, populate a MutableRecordSource.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
function handleGraphModeResponse(recordSource, response) {
|
|
31
|
+
var handler = new GraphModeHandler(recordSource);
|
|
32
|
+
return handler.populateRecordSource(response);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
var GraphModeHandler = /*#__PURE__*/function () {
|
|
36
|
+
function GraphModeHandler(recordSource) {
|
|
37
|
+
this._recordSource = recordSource;
|
|
38
|
+
this._streamIdToCacheKey = new Map();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
var _proto = GraphModeHandler.prototype;
|
|
42
|
+
|
|
43
|
+
_proto.populateRecordSource = function populateRecordSource(response) {
|
|
44
|
+
var _iterator = (0, _createForOfIteratorHelper2["default"])(response),
|
|
45
|
+
_step;
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
49
|
+
var chunk = _step.value;
|
|
50
|
+
|
|
51
|
+
switch (chunk.$kind) {
|
|
52
|
+
case 'Record':
|
|
53
|
+
this._handleRecordChunk(chunk);
|
|
54
|
+
|
|
55
|
+
break;
|
|
56
|
+
|
|
57
|
+
case 'Extend':
|
|
58
|
+
{
|
|
59
|
+
var cacheKey = this._lookupCacheKey(chunk.$streamID);
|
|
60
|
+
|
|
61
|
+
var record = this._recordSource.get(cacheKey);
|
|
62
|
+
|
|
63
|
+
!(record != null) ? process.env.NODE_ENV !== "production" ? invariant(false, "Expected to have a record for cache key ".concat(cacheKey)) : invariant(false) : void 0;
|
|
64
|
+
|
|
65
|
+
this._populateRecord(record, chunk);
|
|
66
|
+
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
case 'Complete':
|
|
71
|
+
this._streamIdToCacheKey.clear();
|
|
72
|
+
|
|
73
|
+
break;
|
|
74
|
+
|
|
75
|
+
default:
|
|
76
|
+
chunk.$kind;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
} catch (err) {
|
|
80
|
+
_iterator.e(err);
|
|
81
|
+
} finally {
|
|
82
|
+
_iterator.f();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return this._recordSource;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
_proto._handleRecordChunk = function _handleRecordChunk(chunk) {
|
|
89
|
+
var cacheKey = chunk.__id;
|
|
90
|
+
|
|
91
|
+
var record = this._recordSource.get(cacheKey);
|
|
92
|
+
|
|
93
|
+
if (record == null) {
|
|
94
|
+
record = RelayModernRecord.create(cacheKey, chunk.__typename);
|
|
95
|
+
|
|
96
|
+
this._recordSource.set(cacheKey, record);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this._streamIdToCacheKey.set(chunk.$streamID, cacheKey);
|
|
100
|
+
|
|
101
|
+
this._populateRecord(record, chunk);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
_proto._populateRecord = function _populateRecord(parentRecord, chunk) {
|
|
105
|
+
var _this = this;
|
|
106
|
+
|
|
107
|
+
for (var _i = 0, _Object$entries = Object.entries(chunk); _i < _Object$entries.length; _i++) {
|
|
108
|
+
var _Object$entries$_i = _Object$entries[_i],
|
|
109
|
+
key = _Object$entries$_i[0],
|
|
110
|
+
value = _Object$entries$_i[1];
|
|
111
|
+
|
|
112
|
+
switch (key) {
|
|
113
|
+
case '$streamID':
|
|
114
|
+
case '$kind':
|
|
115
|
+
case '__typename':
|
|
116
|
+
break;
|
|
117
|
+
|
|
118
|
+
default:
|
|
119
|
+
if (typeof value !== 'object' || value == null || Array.isArray(value)) {
|
|
120
|
+
RelayModernRecord.setValue(parentRecord, key, value);
|
|
121
|
+
} else {
|
|
122
|
+
if (value.hasOwnProperty('__id')) {
|
|
123
|
+
// Singular
|
|
124
|
+
var streamID = value.__id;
|
|
125
|
+
|
|
126
|
+
var id = this._lookupCacheKey(streamID);
|
|
127
|
+
|
|
128
|
+
RelayModernRecord.setLinkedRecordID(parentRecord, key, id);
|
|
129
|
+
} else if (value.hasOwnProperty('__ids')) {
|
|
130
|
+
// Plural
|
|
131
|
+
var streamIDs = value.__ids;
|
|
132
|
+
var ids = streamIDs.map(function (sID) {
|
|
133
|
+
return sID == null ? null : _this._lookupCacheKey(sID);
|
|
134
|
+
});
|
|
135
|
+
RelayModernRecord.setLinkedRecordIDs(parentRecord, key, ids);
|
|
136
|
+
} else {
|
|
137
|
+
!false ? process.env.NODE_ENV !== "production" ? invariant(false, 'Expected object to have either __id or __ids.') : invariant(false) : void 0;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
_proto._lookupCacheKey = function _lookupCacheKey(streamID) {
|
|
146
|
+
var cacheKey = this._streamIdToCacheKey.get(streamID);
|
|
147
|
+
|
|
148
|
+
!(cacheKey != null) ? process.env.NODE_ENV !== "production" ? invariant(false, "Expected to have a cacheKey for $streamID ".concat(streamID)) : invariant(false) : void 0;
|
|
149
|
+
return cacheKey;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
return GraphModeHandler;
|
|
153
|
+
}();
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.normalizeResponse = normalizeResponse;
|
|
9
|
+
|
|
10
|
+
var _createForOfIteratorHelper2 = _interopRequireDefault(require("@babel/runtime/helpers/createForOfIteratorHelper"));
|
|
11
|
+
|
|
12
|
+
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
|
|
13
|
+
|
|
14
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
18
|
+
*
|
|
19
|
+
* This source code is licensed under the MIT license found in the
|
|
20
|
+
* LICENSE file in the root directory of this source tree.
|
|
21
|
+
*
|
|
22
|
+
* @emails oncall+relay
|
|
23
|
+
*
|
|
24
|
+
* @format
|
|
25
|
+
*/
|
|
26
|
+
var _require = require('./RelayConcreteVariables'),
|
|
27
|
+
getLocalVariables = _require.getLocalVariables;
|
|
28
|
+
|
|
29
|
+
var _require2 = require('./RelayModernSelector'),
|
|
30
|
+
createNormalizationSelector = _require2.createNormalizationSelector;
|
|
31
|
+
|
|
32
|
+
var invariant = require('invariant');
|
|
33
|
+
|
|
34
|
+
var _require3 = require('relay-runtime'),
|
|
35
|
+
generateClientID = _require3.generateClientID;
|
|
36
|
+
|
|
37
|
+
var _require4 = require('relay-runtime/store/RelayStoreUtils'),
|
|
38
|
+
ROOT_TYPE = _require4.ROOT_TYPE,
|
|
39
|
+
TYPENAME_KEY = _require4.TYPENAME_KEY,
|
|
40
|
+
getStorageKey = _require4.getStorageKey;
|
|
41
|
+
|
|
42
|
+
var _require5 = require('relay-runtime/util/RelayConcreteNode'),
|
|
43
|
+
CLIENT_EXTENSION = _require5.CLIENT_EXTENSION,
|
|
44
|
+
CONDITION = _require5.CONDITION,
|
|
45
|
+
DEFER = _require5.DEFER,
|
|
46
|
+
FRAGMENT_SPREAD = _require5.FRAGMENT_SPREAD,
|
|
47
|
+
INLINE_FRAGMENT = _require5.INLINE_FRAGMENT,
|
|
48
|
+
LINKED_FIELD = _require5.LINKED_FIELD,
|
|
49
|
+
SCALAR_FIELD = _require5.SCALAR_FIELD;
|
|
50
|
+
/**
|
|
51
|
+
* This module is an experiment to explore a proposal normalized response format for GraphQL.
|
|
52
|
+
* See the Quip document: Canonical Normalized Response Format (“GraphMode”) Proposal
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* # TODO
|
|
57
|
+
*
|
|
58
|
+
* - [ ] Compute storage keys using method outlined in the proposal
|
|
59
|
+
* - [ ] Plural fields
|
|
60
|
+
* - [ ] Write a utility to populate the store using a GraphMode response.
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Converts a JSON response (and Normalization AST) into a stream of GraphMode chunks
|
|
66
|
+
*
|
|
67
|
+
* The stream is modeled as a Generator in order to highlight the streaming
|
|
68
|
+
* nature of the response. Once a chunk is generated, it can be immediately flushed
|
|
69
|
+
* to the client.
|
|
70
|
+
*
|
|
71
|
+
* The response is traversed depth-first, meaning children are emitted before
|
|
72
|
+
* the parent. This allows parent objects to reference children using their
|
|
73
|
+
* `$streamID`.
|
|
74
|
+
*
|
|
75
|
+
* After each object is traversed, a chunk is emitted. The first time an object
|
|
76
|
+
* -- identified by its strong ID -- is encountered we emit a `Record`, and its
|
|
77
|
+
* `$streamID` is recorded. If that same object is encountered again later in
|
|
78
|
+
* the response, an `Extend` chunk is emitted, which includes any previously
|
|
79
|
+
* unsent fields. If no unsent fields are present in the second appearance of
|
|
80
|
+
* the new object, no chunk is emitted.
|
|
81
|
+
*
|
|
82
|
+
* ## State
|
|
83
|
+
*
|
|
84
|
+
* As we traverse we must maintain some state:
|
|
85
|
+
*
|
|
86
|
+
* - The next streamID
|
|
87
|
+
* - A mapping of cache keys to streamIDs
|
|
88
|
+
* - The set of fields which we've sent for each streamID. This allows us to
|
|
89
|
+
* avoid sending fields twice.
|
|
90
|
+
*/
|
|
91
|
+
function normalizeResponse(response, selector, options) {
|
|
92
|
+
var node = selector.node,
|
|
93
|
+
variables = selector.variables,
|
|
94
|
+
dataID = selector.dataID;
|
|
95
|
+
var normalizer = new GraphModeNormalizer(variables, options);
|
|
96
|
+
return normalizer.normalizeResponse(node, dataID, response);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
var GraphModeNormalizer = /*#__PURE__*/function () {
|
|
100
|
+
function GraphModeNormalizer(variables, options) {
|
|
101
|
+
this._actorIdentifier = options.actorIdentifier;
|
|
102
|
+
this._path = options.path ? (0, _toConsumableArray2["default"])(options.path) : [];
|
|
103
|
+
this._getDataID = options.getDataID;
|
|
104
|
+
this._cacheKeyToStreamID = new Map();
|
|
105
|
+
this._sentFields = new Map();
|
|
106
|
+
this._nextStreamID = 0;
|
|
107
|
+
this._variables = variables;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
var _proto = GraphModeNormalizer.prototype;
|
|
111
|
+
|
|
112
|
+
_proto._getStreamID = function _getStreamID() {
|
|
113
|
+
return this._nextStreamID++;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
_proto._getSentFields = function _getSentFields(cacheKey) {
|
|
117
|
+
var maybeSent = this._sentFields.get(cacheKey);
|
|
118
|
+
|
|
119
|
+
if (maybeSent != null) {
|
|
120
|
+
return maybeSent;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
var sent = new Set();
|
|
124
|
+
|
|
125
|
+
this._sentFields.set(cacheKey, sent);
|
|
126
|
+
|
|
127
|
+
return sent;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
_proto._getObjectType = function _getObjectType(data) {
|
|
131
|
+
var typeName = data[TYPENAME_KEY];
|
|
132
|
+
!(typeName != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Expected a typename for record `%s`.', JSON.stringify(data, null, 2)) : invariant(false) : void 0;
|
|
133
|
+
return typeName;
|
|
134
|
+
} // TODO: The GraphMode proposal outlines different approachs to derive keys. We
|
|
135
|
+
// can expriment with different approaches here.
|
|
136
|
+
;
|
|
137
|
+
|
|
138
|
+
_proto._getStorageKey = function _getStorageKey(selection) {
|
|
139
|
+
return getStorageKey(selection, this._variables);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
_proto._getVariableValue = function _getVariableValue(name) {
|
|
143
|
+
!this._variables.hasOwnProperty(name) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Unexpected undefined variable `%s`.', name) : invariant(false) : void 0;
|
|
144
|
+
return this._variables[name];
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
_proto.normalizeResponse = function* normalizeResponse(node, dataID, data) {
|
|
148
|
+
var rootFields = {};
|
|
149
|
+
yield* this._traverseSelections(node, data, rootFields, dataID, new Set());
|
|
150
|
+
|
|
151
|
+
var $streamID = this._getStreamID();
|
|
152
|
+
|
|
153
|
+
yield (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, rootFields), {}, {
|
|
154
|
+
$kind: 'Record',
|
|
155
|
+
$streamID: $streamID,
|
|
156
|
+
__id: dataID,
|
|
157
|
+
__typename: ROOT_TYPE
|
|
158
|
+
});
|
|
159
|
+
yield {
|
|
160
|
+
$kind: 'Complete'
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
_proto._flushFields = function* _flushFields(cacheKey, typename, fields) {
|
|
165
|
+
var maybeStreamID = this._cacheKeyToStreamID.get(cacheKey);
|
|
166
|
+
|
|
167
|
+
var $streamID = maybeStreamID !== null && maybeStreamID !== void 0 ? maybeStreamID : this._getStreamID();
|
|
168
|
+
|
|
169
|
+
if (maybeStreamID == null) {
|
|
170
|
+
this._cacheKeyToStreamID.set(cacheKey, $streamID); // TODO: We could mutate `fields` rather than constructing a new
|
|
171
|
+
// chunk object, but it's hard to convince Flow that we've
|
|
172
|
+
// constructed a valid Chunk, and perf is not important for this
|
|
173
|
+
// experimental transform
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
yield (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, fields), {}, {
|
|
177
|
+
$kind: 'Record',
|
|
178
|
+
__typename: typename,
|
|
179
|
+
__id: cacheKey,
|
|
180
|
+
$streamID: $streamID
|
|
181
|
+
});
|
|
182
|
+
} else if (Object.keys(fields).length > 0) {
|
|
183
|
+
yield (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, fields), {}, {
|
|
184
|
+
$kind: 'Extend',
|
|
185
|
+
$streamID: $streamID
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return $streamID;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
_proto._traverseSelections = function* _traverseSelections(node, data, parentFields, parentID, sentFields) {
|
|
193
|
+
var selections = node.selections;
|
|
194
|
+
|
|
195
|
+
var _iterator = (0, _createForOfIteratorHelper2["default"])(selections),
|
|
196
|
+
_step;
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
200
|
+
var selection = _step.value;
|
|
201
|
+
|
|
202
|
+
switch (selection.kind) {
|
|
203
|
+
case LINKED_FIELD:
|
|
204
|
+
{
|
|
205
|
+
var _selection$alias;
|
|
206
|
+
|
|
207
|
+
var responseKey = (_selection$alias = selection.alias) !== null && _selection$alias !== void 0 ? _selection$alias : selection.name;
|
|
208
|
+
var fieldData = data[responseKey];
|
|
209
|
+
|
|
210
|
+
var storageKey = this._getStorageKey(selection);
|
|
211
|
+
|
|
212
|
+
this._path.push(responseKey);
|
|
213
|
+
|
|
214
|
+
var fieldValue = yield* this._traverseLinkedField(selection.plural, fieldData, storageKey, selection, parentID);
|
|
215
|
+
|
|
216
|
+
this._path.pop(); // TODO: We could also opt to confirm that this matches the previously
|
|
217
|
+
// seen value.
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
if (sentFields.has(storageKey)) {
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
parentFields[storageKey] = fieldValue;
|
|
225
|
+
sentFields.add(storageKey);
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
case SCALAR_FIELD:
|
|
230
|
+
{
|
|
231
|
+
var _selection$alias2;
|
|
232
|
+
|
|
233
|
+
var _responseKey = (_selection$alias2 = selection.alias) !== null && _selection$alias2 !== void 0 ? _selection$alias2 : selection.name;
|
|
234
|
+
|
|
235
|
+
var _storageKey = this._getStorageKey(selection); // TODO: We could also opt to confirm that this matches the previously
|
|
236
|
+
// seen value.
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
if (sentFields.has(_storageKey)) {
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
var _fieldData = data[_responseKey];
|
|
244
|
+
parentFields[_storageKey] = _fieldData;
|
|
245
|
+
sentFields.add(_storageKey);
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
case INLINE_FRAGMENT:
|
|
250
|
+
{
|
|
251
|
+
var objType = this._getObjectType(data);
|
|
252
|
+
|
|
253
|
+
var abstractKey = selection.abstractKey;
|
|
254
|
+
|
|
255
|
+
if (abstractKey == null) {
|
|
256
|
+
if (objType !== selection.type) {
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
} else if (!data.hasOwnProperty(abstractKey)) {
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
yield* this._traverseSelections(selection, data, parentFields, parentID, sentFields);
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
case FRAGMENT_SPREAD:
|
|
268
|
+
{
|
|
269
|
+
var prevVariables = this._variables;
|
|
270
|
+
this._variables = getLocalVariables(this._variables, selection.fragment.argumentDefinitions, selection.args);
|
|
271
|
+
yield* this._traverseSelections(selection.fragment, data, parentFields, parentID, sentFields);
|
|
272
|
+
this._variables = prevVariables;
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
case CONDITION:
|
|
277
|
+
var conditionValue = Boolean(this._getVariableValue(selection.condition));
|
|
278
|
+
|
|
279
|
+
if (conditionValue === selection.passingValue) {
|
|
280
|
+
yield* this._traverseSelections(selection, data, parentFields, parentID, sentFields);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
break;
|
|
284
|
+
|
|
285
|
+
case DEFER:
|
|
286
|
+
var isDeferred = selection["if"] === null || this._getVariableValue(selection["if"]);
|
|
287
|
+
|
|
288
|
+
if (isDeferred === false) {
|
|
289
|
+
// If defer is disabled there will be no additional response chunk:
|
|
290
|
+
// normalize the data already present.
|
|
291
|
+
yield* this._traverseSelections(selection, data, parentFields, parentID, sentFields);
|
|
292
|
+
} else {
|
|
293
|
+
// Otherwise data *for this selection* should not be present: enqueue
|
|
294
|
+
// metadata to process the subsequent response chunk.
|
|
295
|
+
this._incrementalPlaceholders.push({
|
|
296
|
+
kind: 'defer',
|
|
297
|
+
data: data,
|
|
298
|
+
label: selection.label,
|
|
299
|
+
path: (0, _toConsumableArray2["default"])(this._path),
|
|
300
|
+
selector: createNormalizationSelector(selection, parentID, this._variables),
|
|
301
|
+
typeName: this._getObjectType(data),
|
|
302
|
+
actorIdentifier: this._actorIdentifier
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
break;
|
|
307
|
+
|
|
308
|
+
case CLIENT_EXTENSION:
|
|
309
|
+
// Since we are only expecting to handle server responses, we can skip
|
|
310
|
+
// over client extensions.
|
|
311
|
+
break;
|
|
312
|
+
|
|
313
|
+
default:
|
|
314
|
+
throw new Error("Unexpected selection type: ".concat(selection.kind));
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
} catch (err) {
|
|
318
|
+
_iterator.e(err);
|
|
319
|
+
} finally {
|
|
320
|
+
_iterator.f();
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
_proto._traverseLinkedField = function* _traverseLinkedField(plural, fieldData, storageKey, selection, parentID, index) {
|
|
325
|
+
var _selection$concreteTy;
|
|
326
|
+
|
|
327
|
+
if (fieldData == null) {
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (plural) {
|
|
332
|
+
!Array.isArray(fieldData) ? process.env.NODE_ENV !== "production" ? invariant(false, "Expected fieldData to be an array. Got ".concat(JSON.stringify(fieldData))) : invariant(false) : void 0;
|
|
333
|
+
var fieldValue = [];
|
|
334
|
+
|
|
335
|
+
var _iterator2 = (0, _createForOfIteratorHelper2["default"])(fieldData.entries()),
|
|
336
|
+
_step2;
|
|
337
|
+
|
|
338
|
+
try {
|
|
339
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
340
|
+
var _step2$value = _step2.value,
|
|
341
|
+
i = _step2$value[0],
|
|
342
|
+
itemData = _step2$value[1];
|
|
343
|
+
|
|
344
|
+
this._path.push(String(i));
|
|
345
|
+
|
|
346
|
+
var itemValue = yield* this._traverseLinkedField(false, itemData, storageKey, selection, parentID, i);
|
|
347
|
+
|
|
348
|
+
this._path.pop();
|
|
349
|
+
|
|
350
|
+
fieldValue.push(itemValue);
|
|
351
|
+
}
|
|
352
|
+
} catch (err) {
|
|
353
|
+
_iterator2.e(err);
|
|
354
|
+
} finally {
|
|
355
|
+
_iterator2.f();
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
var ids = fieldValue.map(function (value) {
|
|
359
|
+
if (value == null) {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
!(typeof value.__id === 'number') ? process.env.NODE_ENV !== "production" ? invariant(false, 'Expected objects in a plural linked field to have an __id.') : invariant(false) : void 0;
|
|
364
|
+
return value.__id;
|
|
365
|
+
});
|
|
366
|
+
return {
|
|
367
|
+
__ids: ids
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
!(typeof fieldData === 'object') ? process.env.NODE_ENV !== "production" ? invariant(false, 'Expected data for field `%s` to be an object.', storageKey) : invariant(false) : void 0;
|
|
372
|
+
var objType = (_selection$concreteTy = selection.concreteType) !== null && _selection$concreteTy !== void 0 ? _selection$concreteTy : this._getObjectType(fieldData);
|
|
373
|
+
var nextID = this._getDataID(fieldData, objType) || // Note: In RelayResponseNormalizer we try to access a cached
|
|
374
|
+
// version of the key before generating a new one. I'm not clear if
|
|
375
|
+
// that's a performance optimization (which would not be important
|
|
376
|
+
// here) or important for stable ids.
|
|
377
|
+
// TODO: The proposal does not yet specify how we handle objects
|
|
378
|
+
// without strong ids.
|
|
379
|
+
generateClientID(parentID, storageKey, index);
|
|
380
|
+
!(typeof nextID === 'string') ? process.env.NODE_ENV !== "production" ? invariant(false, 'Expected id on field `%s` to be a string.', storageKey) : invariant(false) : void 0;
|
|
381
|
+
var fields = {}; // Yield any decendent record chunks, and mutatively populate direct fields.
|
|
382
|
+
|
|
383
|
+
yield* this._traverseSelections(selection, fieldData, fields, nextID, this._getSentFields(nextID));
|
|
384
|
+
var $streamID = yield* this._flushFields(nextID, objType, fields);
|
|
385
|
+
return {
|
|
386
|
+
__id: $streamID
|
|
387
|
+
};
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
return GraphModeNormalizer;
|
|
391
|
+
}();
|