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.
- package/handlers/RelayDefaultHandlerProvider.js.flow +47 -0
- package/handlers/connection/ConnectionHandler.js.flow +549 -0
- package/handlers/connection/ConnectionInterface.js.flow +92 -0
- package/handlers/connection/MutationHandlers.js.flow +199 -0
- package/index.js +1 -1
- package/index.js.flow +335 -0
- package/lib/handlers/RelayDefaultHandlerProvider.js +20 -0
- package/lib/handlers/connection/ConnectionHandler.js +1 -3
- package/lib/handlers/connection/MutationHandlers.js +212 -0
- package/lib/index.js +14 -2
- package/lib/mutations/RelayDeclarativeMutationConfig.js +22 -45
- package/lib/mutations/RelayRecordProxy.js +1 -3
- package/lib/mutations/RelayRecordSourceMutator.js +1 -3
- package/lib/mutations/RelayRecordSourceProxy.js +1 -3
- package/lib/mutations/RelayRecordSourceSelectorProxy.js +1 -3
- package/lib/mutations/commitMutation.js +2 -3
- package/lib/mutations/validateMutation.js +40 -9
- package/lib/network/RelayObservable.js +9 -9
- package/lib/network/RelayQueryResponseCache.js +8 -6
- package/lib/query/GraphQLTag.js +2 -1
- package/lib/query/PreloadableQueryRegistry.js +70 -0
- package/lib/query/fetchQuery.js +2 -3
- package/lib/query/fetchQueryInternal.js +5 -14
- package/lib/store/DataChecker.js +200 -71
- package/lib/store/RelayConcreteVariables.js +6 -2
- package/lib/store/RelayModernEnvironment.js +124 -65
- package/lib/store/RelayModernFragmentSpecResolver.js +19 -14
- package/lib/store/RelayModernOperationDescriptor.js +6 -5
- package/lib/store/RelayModernQueryExecutor.js +122 -73
- package/lib/store/RelayModernRecord.js +14 -9
- package/lib/store/RelayModernSelector.js +6 -2
- package/lib/store/RelayModernStore.js +281 -131
- package/lib/store/RelayOperationTracker.js +35 -78
- package/lib/store/RelayOptimisticRecordSource.js +7 -5
- package/lib/store/RelayPublishQueue.js +2 -4
- package/lib/store/RelayReader.js +304 -52
- package/lib/store/RelayRecordSource.js +1 -3
- package/lib/store/RelayRecordSourceMapImpl.js +13 -18
- package/lib/store/RelayReferenceMarker.js +125 -14
- package/lib/store/RelayResponseNormalizer.js +261 -66
- package/lib/store/RelayStoreReactFlightUtils.js +47 -0
- package/lib/store/RelayStoreUtils.js +1 -0
- package/lib/store/StoreInspector.js +8 -8
- package/lib/store/TypeID.js +28 -0
- package/lib/store/cloneRelayScalarHandleSourceField.js +44 -0
- package/lib/store/defaultRequiredFieldLogger.js +18 -0
- package/lib/store/normalizeRelayPayload.js +6 -2
- package/lib/store/readInlineData.js +1 -1
- package/lib/subscription/requestSubscription.js +4 -3
- package/lib/util/NormalizationNode.js +1 -5
- package/lib/util/RelayConcreteNode.js +11 -6
- package/lib/util/RelayError.js +39 -9
- package/lib/util/RelayFeatureFlags.js +6 -3
- package/lib/util/RelayReplaySubject.js +3 -3
- package/lib/util/createPayloadFor3DField.js +7 -2
- package/lib/util/getFragmentIdentifier.js +12 -3
- package/lib/util/getOperation.js +33 -0
- package/lib/util/getRequestIdentifier.js +2 -2
- package/lib/util/isEmptyObject.js +25 -0
- package/lib/util/recycleNodesInto.js +6 -7
- package/lib/util/reportMissingRequiredFields.js +48 -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 +181 -0
- package/mutations/validateMutation.js.flow +242 -0
- package/network/ConvertToExecuteFunction.js.flow +49 -0
- package/network/RelayNetwork.js.flow +84 -0
- package/network/RelayNetworkTypes.js.flow +145 -0
- package/network/RelayObservable.js.flow +634 -0
- package/network/RelayQueryResponseCache.js.flow +111 -0
- package/package.json +2 -2
- package/query/GraphQLTag.js.flow +168 -0
- package/query/PreloadableQueryRegistry.js.flow +65 -0
- package/query/fetchQuery.js.flow +47 -0
- package/query/fetchQueryInternal.js.flow +343 -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 +568 -0
- package/store/RelayConcreteVariables.js.flow +96 -0
- package/store/RelayModernEnvironment.js.flow +571 -0
- package/store/RelayModernFragmentSpecResolver.js.flow +438 -0
- package/store/RelayModernOperationDescriptor.js.flow +92 -0
- package/store/RelayModernQueryExecutor.js.flow +1345 -0
- package/store/RelayModernRecord.js.flow +403 -0
- package/store/RelayModernSelector.js.flow +455 -0
- package/store/RelayModernStore.js.flow +858 -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 +638 -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 +324 -0
- package/store/RelayResponseNormalizer.js.flow +791 -0
- package/store/RelayStoreReactFlightUtils.js.flow +64 -0
- package/store/RelayStoreTypes.js.flow +958 -0
- package/store/RelayStoreUtils.js.flow +219 -0
- package/store/StoreInspector.js.flow +171 -0
- package/store/TypeID.js.flow +28 -0
- package/store/ViewerPattern.js.flow +26 -0
- package/store/cloneRelayHandleSourceField.js.flow +66 -0
- package/store/cloneRelayScalarHandleSourceField.js.flow +62 -0
- package/store/createFragmentSpecResolver.js.flow +55 -0
- package/store/createRelayContext.js.flow +44 -0
- package/store/defaultGetDataID.js.flow +27 -0
- package/store/defaultRequiredFieldLogger.js.flow +23 -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 +103 -0
- package/util/JSResourceTypes.flow.js.flow +20 -0
- package/util/NormalizationNode.js.flow +213 -0
- package/util/ReaderNode.js.flow +227 -0
- package/util/RelayConcreteNode.js.flow +99 -0
- package/util/RelayDefaultHandleKey.js.flow +17 -0
- package/util/RelayError.js.flow +62 -0
- package/util/RelayFeatureFlags.js.flow +37 -0
- package/util/RelayProfiler.js.flow +284 -0
- package/util/RelayReplaySubject.js.flow +135 -0
- package/util/RelayRuntimeTypes.js.flow +72 -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 +76 -0
- package/util/getOperation.js.flow +40 -0
- package/util/getRelayHandleKey.js.flow +41 -0
- package/util/getRequestIdentifier.js.flow +42 -0
- package/util/isEmptyObject.js.flow +25 -0
- package/util/isPromise.js.flow +21 -0
- package/util/isScalarAndEqual.js.flow +26 -0
- package/util/recycleNodesInto.js.flow +87 -0
- package/util/reportMissingRequiredFields.js.flow +51 -0
- package/util/resolveImmediate.js.flow +30 -0
- package/util/stableCopy.js.flow +35 -0
|
@@ -0,0 +1,380 @@
|
|
|
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 ConnectionHandler = require('../handlers/connection/ConnectionHandler');
|
|
16
|
+
|
|
17
|
+
const warning = require('warning');
|
|
18
|
+
|
|
19
|
+
import type {
|
|
20
|
+
RecordSourceSelectorProxy,
|
|
21
|
+
SelectorData,
|
|
22
|
+
SelectorStoreUpdater,
|
|
23
|
+
} from '../store/RelayStoreTypes';
|
|
24
|
+
import type {ConcreteRequest} from '../util/RelayConcreteNode';
|
|
25
|
+
import type {Variables} from '../util/RelayRuntimeTypes';
|
|
26
|
+
|
|
27
|
+
const MutationTypes = Object.freeze({
|
|
28
|
+
RANGE_ADD: 'RANGE_ADD',
|
|
29
|
+
RANGE_DELETE: 'RANGE_DELETE',
|
|
30
|
+
NODE_DELETE: 'NODE_DELETE',
|
|
31
|
+
});
|
|
32
|
+
export type MutationType = $Values<typeof MutationTypes>;
|
|
33
|
+
|
|
34
|
+
const RangeOperations = Object.freeze({
|
|
35
|
+
APPEND: 'append',
|
|
36
|
+
PREPEND: 'prepend',
|
|
37
|
+
});
|
|
38
|
+
export type RangeOperation = $Values<typeof RangeOperations>;
|
|
39
|
+
|
|
40
|
+
type RangeBehaviorsFunction = (connectionArgs: {
|
|
41
|
+
[name: string]: $FlowFixMe,
|
|
42
|
+
...,
|
|
43
|
+
}) => RangeOperation;
|
|
44
|
+
type RangeBehaviorsObject = {[key: string]: RangeOperation, ...};
|
|
45
|
+
export type RangeBehaviors = RangeBehaviorsFunction | RangeBehaviorsObject;
|
|
46
|
+
|
|
47
|
+
type RangeAddConfig = {|
|
|
48
|
+
type: 'RANGE_ADD',
|
|
49
|
+
parentName?: string,
|
|
50
|
+
parentID?: string,
|
|
51
|
+
connectionInfo?: Array<{|
|
|
52
|
+
key: string,
|
|
53
|
+
filters?: Variables,
|
|
54
|
+
rangeBehavior: string,
|
|
55
|
+
|}>,
|
|
56
|
+
connectionName?: string,
|
|
57
|
+
edgeName: string,
|
|
58
|
+
rangeBehaviors?: RangeBehaviors,
|
|
59
|
+
|};
|
|
60
|
+
|
|
61
|
+
type RangeDeleteConfig = {|
|
|
62
|
+
type: 'RANGE_DELETE',
|
|
63
|
+
parentName?: string,
|
|
64
|
+
parentID?: string,
|
|
65
|
+
connectionKeys?: Array<{|
|
|
66
|
+
key: string,
|
|
67
|
+
filters?: Variables,
|
|
68
|
+
|}>,
|
|
69
|
+
connectionName?: string,
|
|
70
|
+
deletedIDFieldName: string | Array<string>,
|
|
71
|
+
pathToConnection: Array<string>,
|
|
72
|
+
|};
|
|
73
|
+
|
|
74
|
+
type NodeDeleteConfig = {|
|
|
75
|
+
type: 'NODE_DELETE',
|
|
76
|
+
parentName?: string,
|
|
77
|
+
parentID?: string,
|
|
78
|
+
connectionName?: string,
|
|
79
|
+
deletedIDFieldName: string,
|
|
80
|
+
|};
|
|
81
|
+
|
|
82
|
+
export type DeclarativeMutationConfig =
|
|
83
|
+
| RangeAddConfig
|
|
84
|
+
| RangeDeleteConfig
|
|
85
|
+
| NodeDeleteConfig;
|
|
86
|
+
|
|
87
|
+
function convert(
|
|
88
|
+
configs: Array<DeclarativeMutationConfig>,
|
|
89
|
+
request: ConcreteRequest,
|
|
90
|
+
optimisticUpdater?: ?SelectorStoreUpdater,
|
|
91
|
+
updater?: ?SelectorStoreUpdater,
|
|
92
|
+
): {
|
|
93
|
+
optimisticUpdater: SelectorStoreUpdater,
|
|
94
|
+
updater: SelectorStoreUpdater,
|
|
95
|
+
...
|
|
96
|
+
} {
|
|
97
|
+
const configOptimisticUpdates = optimisticUpdater ? [optimisticUpdater] : [];
|
|
98
|
+
const configUpdates = updater ? [updater] : [];
|
|
99
|
+
configs.forEach(config => {
|
|
100
|
+
switch (config.type) {
|
|
101
|
+
case 'NODE_DELETE':
|
|
102
|
+
const nodeDeleteResult = nodeDelete(config, request);
|
|
103
|
+
if (nodeDeleteResult) {
|
|
104
|
+
configOptimisticUpdates.push(nodeDeleteResult);
|
|
105
|
+
configUpdates.push(nodeDeleteResult);
|
|
106
|
+
}
|
|
107
|
+
break;
|
|
108
|
+
case 'RANGE_ADD':
|
|
109
|
+
const rangeAddResult = rangeAdd(config, request);
|
|
110
|
+
if (rangeAddResult) {
|
|
111
|
+
configOptimisticUpdates.push(rangeAddResult);
|
|
112
|
+
configUpdates.push(rangeAddResult);
|
|
113
|
+
}
|
|
114
|
+
break;
|
|
115
|
+
case 'RANGE_DELETE':
|
|
116
|
+
const rangeDeleteResult = rangeDelete(config, request);
|
|
117
|
+
if (rangeDeleteResult) {
|
|
118
|
+
configOptimisticUpdates.push(rangeDeleteResult);
|
|
119
|
+
configUpdates.push(rangeDeleteResult);
|
|
120
|
+
}
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
return {
|
|
125
|
+
optimisticUpdater: (
|
|
126
|
+
store: RecordSourceSelectorProxy,
|
|
127
|
+
data: ?SelectorData,
|
|
128
|
+
) => {
|
|
129
|
+
configOptimisticUpdates.forEach(eachOptimisticUpdater => {
|
|
130
|
+
eachOptimisticUpdater(store, data);
|
|
131
|
+
});
|
|
132
|
+
},
|
|
133
|
+
updater: (store: RecordSourceSelectorProxy, data: ?SelectorData) => {
|
|
134
|
+
configUpdates.forEach(eachUpdater => {
|
|
135
|
+
eachUpdater(store, data);
|
|
136
|
+
});
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function nodeDelete(
|
|
142
|
+
config: NodeDeleteConfig,
|
|
143
|
+
request: ConcreteRequest,
|
|
144
|
+
): ?SelectorStoreUpdater {
|
|
145
|
+
const {deletedIDFieldName} = config;
|
|
146
|
+
const rootField = getRootField(request);
|
|
147
|
+
if (!rootField) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
return (store: RecordSourceSelectorProxy, data: ?SelectorData) => {
|
|
151
|
+
const payload = store.getRootField(rootField);
|
|
152
|
+
if (!payload) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const deleteID = payload.getValue(deletedIDFieldName);
|
|
156
|
+
const deleteIDs = Array.isArray(deleteID) ? deleteID : [deleteID];
|
|
157
|
+
deleteIDs.forEach(id => {
|
|
158
|
+
if (id && typeof id === 'string') {
|
|
159
|
+
store.delete(id);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function rangeAdd(
|
|
166
|
+
config: RangeAddConfig,
|
|
167
|
+
request: ConcreteRequest,
|
|
168
|
+
): ?SelectorStoreUpdater {
|
|
169
|
+
const {parentID, connectionInfo, edgeName} = config;
|
|
170
|
+
if (!parentID) {
|
|
171
|
+
warning(
|
|
172
|
+
false,
|
|
173
|
+
'RelayDeclarativeMutationConfig: For mutation config RANGE_ADD ' +
|
|
174
|
+
'to work you must include a parentID',
|
|
175
|
+
);
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
const rootField = getRootField(request);
|
|
179
|
+
if (!connectionInfo || !rootField) {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
return (store: RecordSourceSelectorProxy, data: ?SelectorData) => {
|
|
183
|
+
const parent = store.get(parentID);
|
|
184
|
+
if (!parent) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const payload = store.getRootField(rootField);
|
|
188
|
+
if (!payload) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
const serverEdge = payload.getLinkedRecord(edgeName);
|
|
192
|
+
for (const info of connectionInfo) {
|
|
193
|
+
if (!serverEdge) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
const connection = ConnectionHandler.getConnection(
|
|
197
|
+
parent,
|
|
198
|
+
info.key,
|
|
199
|
+
info.filters,
|
|
200
|
+
);
|
|
201
|
+
if (!connection) {
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
const clientEdge = ConnectionHandler.buildConnectionEdge(
|
|
205
|
+
store,
|
|
206
|
+
connection,
|
|
207
|
+
serverEdge,
|
|
208
|
+
);
|
|
209
|
+
if (!clientEdge) {
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
switch (info.rangeBehavior) {
|
|
213
|
+
case 'append':
|
|
214
|
+
ConnectionHandler.insertEdgeAfter(connection, clientEdge);
|
|
215
|
+
break;
|
|
216
|
+
case 'prepend':
|
|
217
|
+
ConnectionHandler.insertEdgeBefore(connection, clientEdge);
|
|
218
|
+
break;
|
|
219
|
+
default:
|
|
220
|
+
warning(
|
|
221
|
+
false,
|
|
222
|
+
'RelayDeclarativeMutationConfig: RANGE_ADD range behavior `%s` ' +
|
|
223
|
+
'will not work as expected in RelayModern, supported range ' +
|
|
224
|
+
"behaviors are 'append', 'prepend'.",
|
|
225
|
+
info.rangeBehavior,
|
|
226
|
+
);
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function rangeDelete(
|
|
234
|
+
config: RangeDeleteConfig,
|
|
235
|
+
request: ConcreteRequest,
|
|
236
|
+
): ?SelectorStoreUpdater {
|
|
237
|
+
const {
|
|
238
|
+
parentID,
|
|
239
|
+
connectionKeys,
|
|
240
|
+
pathToConnection,
|
|
241
|
+
deletedIDFieldName,
|
|
242
|
+
} = config;
|
|
243
|
+
if (!parentID) {
|
|
244
|
+
warning(
|
|
245
|
+
false,
|
|
246
|
+
'RelayDeclarativeMutationConfig: For mutation config RANGE_DELETE ' +
|
|
247
|
+
'to work you must include a parentID',
|
|
248
|
+
);
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
const rootField = getRootField(request);
|
|
252
|
+
if (!rootField) {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
return (store: RecordSourceSelectorProxy, data: ?SelectorData) => {
|
|
256
|
+
if (!data) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const deleteIDs = [];
|
|
260
|
+
let deletedIDField = data[rootField];
|
|
261
|
+
if (deletedIDField && Array.isArray(deletedIDFieldName)) {
|
|
262
|
+
for (const eachField of deletedIDFieldName) {
|
|
263
|
+
if (deletedIDField && typeof deletedIDField === 'object') {
|
|
264
|
+
deletedIDField = deletedIDField[eachField];
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (Array.isArray(deletedIDField)) {
|
|
268
|
+
deletedIDField.forEach(idObject => {
|
|
269
|
+
if (
|
|
270
|
+
idObject &&
|
|
271
|
+
idObject.id &&
|
|
272
|
+
typeof idObject === 'object' &&
|
|
273
|
+
typeof idObject.id === 'string'
|
|
274
|
+
) {
|
|
275
|
+
deleteIDs.push(idObject.id);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
} else if (
|
|
279
|
+
deletedIDField &&
|
|
280
|
+
deletedIDField.id &&
|
|
281
|
+
typeof deletedIDField.id === 'string'
|
|
282
|
+
) {
|
|
283
|
+
deleteIDs.push(deletedIDField.id);
|
|
284
|
+
}
|
|
285
|
+
} else if (
|
|
286
|
+
deletedIDField &&
|
|
287
|
+
typeof deletedIDFieldName === 'string' &&
|
|
288
|
+
typeof deletedIDField === 'object'
|
|
289
|
+
) {
|
|
290
|
+
deletedIDField = deletedIDField[deletedIDFieldName];
|
|
291
|
+
if (typeof deletedIDField === 'string') {
|
|
292
|
+
deleteIDs.push(deletedIDField);
|
|
293
|
+
} else if (Array.isArray(deletedIDField)) {
|
|
294
|
+
deletedIDField.forEach(id => {
|
|
295
|
+
if (typeof id === 'string') {
|
|
296
|
+
deleteIDs.push(id);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
deleteNode(parentID, connectionKeys, pathToConnection, store, deleteIDs);
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function deleteNode(
|
|
306
|
+
parentID: string,
|
|
307
|
+
connectionKeys: ?Array<{|
|
|
308
|
+
key: string,
|
|
309
|
+
filters?: Variables,
|
|
310
|
+
|}>,
|
|
311
|
+
pathToConnection: Array<string>,
|
|
312
|
+
store: RecordSourceSelectorProxy,
|
|
313
|
+
deleteIDs: Array<string>,
|
|
314
|
+
): void {
|
|
315
|
+
warning(
|
|
316
|
+
connectionKeys != null,
|
|
317
|
+
'RelayDeclarativeMutationConfig: RANGE_DELETE must provide a ' +
|
|
318
|
+
'connectionKeys',
|
|
319
|
+
);
|
|
320
|
+
const parent = store.get(parentID);
|
|
321
|
+
if (!parent) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
if (pathToConnection.length < 2) {
|
|
325
|
+
warning(
|
|
326
|
+
false,
|
|
327
|
+
'RelayDeclarativeMutationConfig: RANGE_DELETE ' +
|
|
328
|
+
'pathToConnection must include at least parent and connection',
|
|
329
|
+
);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
let recordProxy = parent;
|
|
333
|
+
for (let i = 1; i < pathToConnection.length - 1; i++) {
|
|
334
|
+
if (recordProxy) {
|
|
335
|
+
recordProxy = recordProxy.getLinkedRecord(pathToConnection[i]);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
// Should never enter loop except edge cases
|
|
339
|
+
if (!connectionKeys || !recordProxy) {
|
|
340
|
+
warning(
|
|
341
|
+
false,
|
|
342
|
+
'RelayDeclarativeMutationConfig: RANGE_DELETE ' +
|
|
343
|
+
'pathToConnection is incorrect. Unable to find connection with ' +
|
|
344
|
+
'parentID: %s and path: %s',
|
|
345
|
+
parentID,
|
|
346
|
+
pathToConnection.toString(),
|
|
347
|
+
);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
for (const key of connectionKeys) {
|
|
351
|
+
const connection = ConnectionHandler.getConnection(
|
|
352
|
+
recordProxy,
|
|
353
|
+
key.key,
|
|
354
|
+
key.filters,
|
|
355
|
+
);
|
|
356
|
+
if (connection) {
|
|
357
|
+
deleteIDs.forEach(deleteID => {
|
|
358
|
+
ConnectionHandler.deleteNode(connection, deleteID);
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function getRootField(request: ConcreteRequest): ?string {
|
|
365
|
+
if (
|
|
366
|
+
request.fragment.selections &&
|
|
367
|
+
request.fragment.selections.length > 0 &&
|
|
368
|
+
request.fragment.selections[0].kind === 'LinkedField'
|
|
369
|
+
) {
|
|
370
|
+
return request.fragment.selections[0].name;
|
|
371
|
+
}
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
module.exports = {
|
|
376
|
+
MutationTypes,
|
|
377
|
+
RangeOperations,
|
|
378
|
+
|
|
379
|
+
convert,
|
|
380
|
+
};
|
|
@@ -0,0 +1,165 @@
|
|
|
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 invariant = require('invariant');
|
|
16
|
+
|
|
17
|
+
const {generateClientID} = require('../store/ClientID');
|
|
18
|
+
const {getStableStorageKey} = require('../store/RelayStoreUtils');
|
|
19
|
+
|
|
20
|
+
import type {RecordProxy} from '../store/RelayStoreTypes';
|
|
21
|
+
import type {Arguments} from '../store/RelayStoreUtils';
|
|
22
|
+
import type {DataID} from '../util/RelayRuntimeTypes';
|
|
23
|
+
import type RelayRecordSourceMutator from './RelayRecordSourceMutator';
|
|
24
|
+
import type RelayRecordSourceProxy from './RelayRecordSourceProxy';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @internal
|
|
28
|
+
*
|
|
29
|
+
* A helper class for manipulating a given record from a record source via an
|
|
30
|
+
* imperative/OO-style API.
|
|
31
|
+
*/
|
|
32
|
+
class RelayRecordProxy implements RecordProxy {
|
|
33
|
+
_dataID: DataID;
|
|
34
|
+
_mutator: RelayRecordSourceMutator;
|
|
35
|
+
_source: RelayRecordSourceProxy;
|
|
36
|
+
|
|
37
|
+
constructor(
|
|
38
|
+
source: RelayRecordSourceProxy,
|
|
39
|
+
mutator: RelayRecordSourceMutator,
|
|
40
|
+
dataID: DataID,
|
|
41
|
+
) {
|
|
42
|
+
this._dataID = dataID;
|
|
43
|
+
this._mutator = mutator;
|
|
44
|
+
this._source = source;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
copyFieldsFrom(source: RecordProxy): void {
|
|
48
|
+
this._mutator.copyFields(source.getDataID(), this._dataID);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
getDataID(): DataID {
|
|
52
|
+
return this._dataID;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
getType(): string {
|
|
56
|
+
const type = this._mutator.getType(this._dataID);
|
|
57
|
+
invariant(
|
|
58
|
+
type != null,
|
|
59
|
+
'RelayRecordProxy: Cannot get the type of deleted record `%s`.',
|
|
60
|
+
this._dataID,
|
|
61
|
+
);
|
|
62
|
+
return type;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
getValue(name: string, args?: ?Arguments): mixed {
|
|
66
|
+
const storageKey = getStableStorageKey(name, args);
|
|
67
|
+
return this._mutator.getValue(this._dataID, storageKey);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
setValue(value: mixed, name: string, args?: ?Arguments): RecordProxy {
|
|
71
|
+
invariant(
|
|
72
|
+
isValidLeafValue(value),
|
|
73
|
+
'RelayRecordProxy#setValue(): Expected a scalar or array of scalars, ' +
|
|
74
|
+
'got `%s`.',
|
|
75
|
+
JSON.stringify(value),
|
|
76
|
+
);
|
|
77
|
+
const storageKey = getStableStorageKey(name, args);
|
|
78
|
+
this._mutator.setValue(this._dataID, storageKey, value);
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
getLinkedRecord(name: string, args?: ?Arguments): ?RecordProxy {
|
|
83
|
+
const storageKey = getStableStorageKey(name, args);
|
|
84
|
+
const linkedID = this._mutator.getLinkedRecordID(this._dataID, storageKey);
|
|
85
|
+
return linkedID != null ? this._source.get(linkedID) : linkedID;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
setLinkedRecord(
|
|
89
|
+
record: RecordProxy,
|
|
90
|
+
name: string,
|
|
91
|
+
args?: ?Arguments,
|
|
92
|
+
): RecordProxy {
|
|
93
|
+
invariant(
|
|
94
|
+
record instanceof RelayRecordProxy,
|
|
95
|
+
'RelayRecordProxy#setLinkedRecord(): Expected a record, got `%s`.',
|
|
96
|
+
record,
|
|
97
|
+
);
|
|
98
|
+
const storageKey = getStableStorageKey(name, args);
|
|
99
|
+
const linkedID = record.getDataID();
|
|
100
|
+
this._mutator.setLinkedRecordID(this._dataID, storageKey, linkedID);
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
getOrCreateLinkedRecord(
|
|
105
|
+
name: string,
|
|
106
|
+
typeName: string,
|
|
107
|
+
args?: ?Arguments,
|
|
108
|
+
): RecordProxy {
|
|
109
|
+
let linkedRecord = this.getLinkedRecord(name, args);
|
|
110
|
+
if (!linkedRecord) {
|
|
111
|
+
const storageKey = getStableStorageKey(name, args);
|
|
112
|
+
const clientID = generateClientID(this.getDataID(), storageKey);
|
|
113
|
+
// NOTE: it's possible that a client record for this field exists
|
|
114
|
+
// but the field itself was unset.
|
|
115
|
+
linkedRecord =
|
|
116
|
+
this._source.get(clientID) ?? this._source.create(clientID, typeName);
|
|
117
|
+
this.setLinkedRecord(linkedRecord, name, args);
|
|
118
|
+
}
|
|
119
|
+
return linkedRecord;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
getLinkedRecords(name: string, args?: ?Arguments): ?Array<?RecordProxy> {
|
|
123
|
+
const storageKey = getStableStorageKey(name, args);
|
|
124
|
+
const linkedIDs = this._mutator.getLinkedRecordIDs(
|
|
125
|
+
this._dataID,
|
|
126
|
+
storageKey,
|
|
127
|
+
);
|
|
128
|
+
if (linkedIDs == null) {
|
|
129
|
+
return linkedIDs;
|
|
130
|
+
}
|
|
131
|
+
return linkedIDs.map(linkedID => {
|
|
132
|
+
return linkedID != null ? this._source.get(linkedID) : linkedID;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
setLinkedRecords(
|
|
137
|
+
records: Array<?RecordProxy>,
|
|
138
|
+
name: string,
|
|
139
|
+
args?: ?Arguments,
|
|
140
|
+
): RecordProxy {
|
|
141
|
+
invariant(
|
|
142
|
+
Array.isArray(records),
|
|
143
|
+
'RelayRecordProxy#setLinkedRecords(): Expected records to be an array, got `%s`.',
|
|
144
|
+
records,
|
|
145
|
+
);
|
|
146
|
+
const storageKey = getStableStorageKey(name, args);
|
|
147
|
+
const linkedIDs = records.map(record => record && record.getDataID());
|
|
148
|
+
this._mutator.setLinkedRecordIDs(this._dataID, storageKey, linkedIDs);
|
|
149
|
+
return this;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
invalidateRecord(): void {
|
|
153
|
+
this._source.markIDForInvalidation(this._dataID);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function isValidLeafValue(value: mixed): boolean {
|
|
158
|
+
return (
|
|
159
|
+
value == null ||
|
|
160
|
+
typeof value !== 'object' ||
|
|
161
|
+
(Array.isArray(value) && value.every(isValidLeafValue))
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
module.exports = RelayRecordProxy;
|