relay-runtime 10.1.3 → 11.0.2

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 (106) hide show
  1. package/handlers/connection/ConnectionHandler.js.flow +60 -0
  2. package/handlers/connection/MutationHandlers.js.flow +28 -0
  3. package/index.js +1 -1
  4. package/index.js.flow +9 -3
  5. package/lib/handlers/RelayDefaultHandlerProvider.js +1 -1
  6. package/lib/handlers/connection/ConnectionHandler.js +68 -6
  7. package/lib/handlers/connection/MutationHandlers.js +67 -8
  8. package/lib/index.js +3 -0
  9. package/lib/multi-actor-environment/ActorIdentifier.js +23 -0
  10. package/lib/multi-actor-environment/ActorSpecificEnvironment.js +108 -0
  11. package/lib/multi-actor-environment/MultiActorEnvironment.js +156 -0
  12. package/lib/multi-actor-environment/MultiActorEnvironmentTypes.js +11 -0
  13. package/lib/multi-actor-environment/index.js +17 -0
  14. package/lib/mutations/RelayRecordProxy.js +1 -1
  15. package/lib/mutations/RelayRecordSourceMutator.js +1 -1
  16. package/lib/mutations/RelayRecordSourceProxy.js +1 -1
  17. package/lib/mutations/RelayRecordSourceSelectorProxy.js +1 -1
  18. package/lib/mutations/applyOptimisticMutation.js +1 -1
  19. package/lib/mutations/commitMutation.js +1 -1
  20. package/lib/mutations/validateMutation.js +36 -15
  21. package/lib/network/RelayNetwork.js +1 -1
  22. package/lib/network/RelayQueryResponseCache.js +3 -2
  23. package/lib/query/GraphQLTag.js +1 -1
  24. package/lib/query/fetchQuery.js +129 -13
  25. package/lib/query/fetchQueryInternal.js +3 -4
  26. package/lib/query/fetchQuery_DEPRECATED.js +39 -0
  27. package/lib/store/DataChecker.js +26 -14
  28. package/lib/store/{RelayModernQueryExecutor.js → OperationExecutor.js} +117 -47
  29. package/lib/store/RelayConcreteVariables.js +8 -4
  30. package/lib/store/RelayModernEnvironment.js +105 -136
  31. package/lib/store/RelayModernFragmentSpecResolver.js +16 -9
  32. package/lib/store/RelayModernRecord.js +1 -1
  33. package/lib/store/RelayModernSelector.js +1 -1
  34. package/lib/store/RelayModernStore.js +19 -20
  35. package/lib/store/RelayOperationTracker.js +55 -49
  36. package/lib/store/RelayPublishQueue.js +9 -5
  37. package/lib/store/RelayReader.js +68 -14
  38. package/lib/store/RelayReferenceMarker.js +28 -14
  39. package/lib/store/RelayResponseNormalizer.js +109 -15
  40. package/lib/store/RelayStoreReactFlightUtils.js +6 -4
  41. package/lib/store/RelayStoreSubscriptions.js +18 -8
  42. package/lib/store/RelayStoreSubscriptionsUsingMapByID.js +90 -30
  43. package/lib/store/RelayStoreUtils.js +3 -2
  44. package/lib/store/ResolverFragments.js +57 -0
  45. package/lib/store/cloneRelayHandleSourceField.js +1 -1
  46. package/lib/store/cloneRelayScalarHandleSourceField.js +1 -1
  47. package/lib/store/createFragmentSpecResolver.js +2 -2
  48. package/lib/store/createRelayContext.js +1 -1
  49. package/lib/store/defaultGetDataID.js +3 -1
  50. package/lib/store/hasOverlappingIDs.js +11 -3
  51. package/lib/store/readInlineData.js +1 -1
  52. package/lib/subscription/requestSubscription.js +33 -5
  53. package/lib/util/RelayConcreteNode.js +2 -0
  54. package/lib/util/RelayFeatureFlags.js +8 -3
  55. package/lib/util/RelayProfiler.js +17 -187
  56. package/lib/util/RelayReplaySubject.js +1 -1
  57. package/lib/util/deepFreeze.js +1 -0
  58. package/lib/util/getRelayHandleKey.js +1 -1
  59. package/lib/util/getRequestIdentifier.js +1 -1
  60. package/multi-actor-environment/ActorIdentifier.js.flow +27 -0
  61. package/multi-actor-environment/ActorSpecificEnvironment.js.flow +189 -0
  62. package/multi-actor-environment/MultiActorEnvironment.js.flow +233 -0
  63. package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +196 -0
  64. package/multi-actor-environment/index.js.flow +24 -0
  65. package/mutations/RelayRecordSourceProxy.js.flow +3 -2
  66. package/mutations/commitMutation.js.flow +1 -1
  67. package/mutations/validateMutation.js.flow +40 -15
  68. package/network/RelayNetworkTypes.js.flow +31 -11
  69. package/network/RelayQueryResponseCache.js.flow +2 -1
  70. package/package.json +3 -2
  71. package/query/fetchQuery.js.flow +147 -20
  72. package/query/fetchQueryInternal.js.flow +2 -3
  73. package/query/fetchQuery_DEPRECATED.js.flow +47 -0
  74. package/relay-runtime.js +2 -2
  75. package/relay-runtime.min.js +2 -2
  76. package/store/DataChecker.js.flow +23 -15
  77. package/store/{RelayModernQueryExecutor.js.flow → OperationExecutor.js.flow} +128 -40
  78. package/store/RelayConcreteVariables.js.flow +5 -0
  79. package/store/RelayModernEnvironment.js.flow +100 -130
  80. package/store/RelayModernFragmentSpecResolver.js.flow +30 -8
  81. package/store/RelayModernStore.js.flow +28 -24
  82. package/store/RelayOperationTracker.js.flow +69 -56
  83. package/store/RelayPublishQueue.js.flow +7 -4
  84. package/store/RelayReader.js.flow +63 -11
  85. package/store/RelayRecordSource.js.flow +3 -3
  86. package/store/RelayRecordSourceMapImpl.js.flow +6 -2
  87. package/store/RelayReferenceMarker.js.flow +28 -18
  88. package/store/RelayResponseNormalizer.js.flow +134 -23
  89. package/store/RelayStoreReactFlightUtils.js.flow +9 -4
  90. package/store/RelayStoreSubscriptions.js.flow +22 -7
  91. package/store/RelayStoreSubscriptionsUsingMapByID.js.flow +36 -12
  92. package/store/RelayStoreTypes.js.flow +51 -22
  93. package/store/RelayStoreUtils.js.flow +2 -1
  94. package/store/ResolverFragments.js.flow +125 -0
  95. package/store/createFragmentSpecResolver.js.flow +2 -0
  96. package/store/defaultGetDataID.js.flow +3 -1
  97. package/store/hasOverlappingIDs.js.flow +11 -9
  98. package/subscription/requestSubscription.js.flow +25 -2
  99. package/util/NormalizationNode.js.flow +13 -0
  100. package/util/ReaderNode.js.flow +14 -1
  101. package/util/RelayConcreteNode.js.flow +2 -0
  102. package/util/RelayFeatureFlags.js.flow +12 -2
  103. package/util/RelayProfiler.js.flow +22 -194
  104. package/util/RelayRuntimeTypes.js.flow +4 -5
  105. package/util/deepFreeze.js.flow +2 -1
  106. package/util/isEmptyObject.js.flow +1 -1
@@ -19,6 +19,7 @@ const invariant = require('invariant');
19
19
  const warning = require('warning');
20
20
 
21
21
  const {generateClientID} = require('../../store/ClientID');
22
+ const {getStableStorageKey} = require('../../store/RelayStoreUtils');
22
23
 
23
24
  import type {
24
25
  HandleFieldPayload,
@@ -145,10 +146,12 @@ function update(store: RecordSourceProxy, payload: HandleFieldPayload): void {
145
146
  let nextEdges = [];
146
147
  const args = payload.args;
147
148
  if (prevEdges && serverEdges) {
149
+ // $FlowFixMe[prop-missing]
148
150
  if (args.after != null) {
149
151
  // Forward pagination from the end of the connection: append edges
150
152
  if (
151
153
  clientPageInfo &&
154
+ // $FlowFixMe[prop-missing]
152
155
  args.after === clientPageInfo.getValue(END_CURSOR)
153
156
  ) {
154
157
  const nodeIDs = new Set();
@@ -164,10 +167,12 @@ function update(store: RecordSourceProxy, payload: HandleFieldPayload): void {
164
167
  );
165
168
  return;
166
169
  }
170
+ // $FlowFixMe[prop-missing]
167
171
  } else if (args.before != null) {
168
172
  // Backward pagination from the start of the connection: prepend edges
169
173
  if (
170
174
  clientPageInfo &&
175
+ // $FlowFixMe[prop-missing]
171
176
  args.before === clientPageInfo.getValue(START_CURSOR)
172
177
  ) {
173
178
  const nodeIDs = new Set();
@@ -199,10 +204,12 @@ function update(store: RecordSourceProxy, payload: HandleFieldPayload): void {
199
204
  }
200
205
  // Page info should be updated even if no new edge were returned.
201
206
  if (clientPageInfo && serverPageInfo) {
207
+ // $FlowFixMe[prop-missing]
202
208
  if (args.after == null && args.before == null) {
203
209
  // The connection was refetched from the beginning/end: replace
204
210
  // page_info
205
211
  clientPageInfo.copyFieldsFrom(serverPageInfo);
212
+ // $FlowFixMe[prop-missing]
206
213
  } else if (args.before != null || (args.after == null && args.last)) {
207
214
  clientPageInfo.setValue(
208
215
  !!serverPageInfo.getValue(HAS_PREV_PAGE),
@@ -212,6 +219,7 @@ function update(store: RecordSourceProxy, payload: HandleFieldPayload): void {
212
219
  if (typeof startCursor === 'string') {
213
220
  clientPageInfo.setValue(startCursor, START_CURSOR);
214
221
  }
222
+ // $FlowFixMe[prop-missing]
215
223
  } else if (args.after != null || (args.before == null && args.first)) {
216
224
  clientPageInfo.setValue(
217
225
  !!serverPageInfo.getValue(HAS_NEXT_PAGE),
@@ -273,6 +281,47 @@ function getConnection(
273
281
  return record.getLinkedRecord(handleKey, filters);
274
282
  }
275
283
 
284
+ /**
285
+ * @public
286
+ *
287
+ * Given a record ID, the key of a connection field, and optional filters used
288
+ * to identify the connection, returns the connection ID.
289
+ *
290
+ * Example:
291
+ *
292
+ * Given that data has already been fetched on some user `<user-id>` on the `friends`
293
+ * field:
294
+ *
295
+ * ```
296
+ * fragment FriendsFragment on User {
297
+ * friends(first: 10) @connection(key: "FriendsFragment_friends") {
298
+ * edges {
299
+ * node {
300
+ * id
301
+ * }
302
+ * }
303
+ * }
304
+ * }
305
+ * ```
306
+ *
307
+ * The ID of the `friends` connection record can be accessed with:
308
+ *
309
+ * ```
310
+ * store => {
311
+ * const connectionID = ConnectionHandler.getConnectionID('<user-id>', 'FriendsFragment_friends');
312
+ * }
313
+ * ```
314
+ */
315
+ function getConnectionID(
316
+ recordID: DataID,
317
+ key: string,
318
+ filters?: ?Variables,
319
+ ): DataID {
320
+ const handleKey = getRelayHandleKey(CONNECTION, key, null);
321
+ const storageKey = getStableStorageKey(handleKey, filters);
322
+ return generateClientID(recordID, storageKey);
323
+ }
324
+
276
325
  /**
277
326
  * @public
278
327
  *
@@ -369,6 +418,11 @@ function createEdge(
369
418
  edge = store.create(edgeID, edgeType);
370
419
  }
371
420
  edge.setLinkedRecord(node, NODE);
421
+ if (edge.getValue('cursor') == null) {
422
+ // Always use null instead of undefined value for cursor
423
+ // to avoid considering it as missing data
424
+ edge.setValue(null, 'cursor');
425
+ }
372
426
  return edge;
373
427
  }
374
428
 
@@ -504,6 +558,11 @@ function buildConnectionEdge(
504
558
  const edgeID = generateClientID(connection.getDataID(), EDGES, edgeIndex);
505
559
  const connectionEdge = store.create(edgeID, edge.getType());
506
560
  connectionEdge.copyFieldsFrom(edge);
561
+ if (connectionEdge.getValue('cursor') == null) {
562
+ // Always use null instead of undefined value for cursor
563
+ // to avoid considering it as missing data
564
+ connectionEdge.setValue(null, 'cursor');
565
+ }
507
566
  connection.setValue(edgeIndex + 1, NEXT_EDGE_INDEX);
508
567
  return connectionEdge;
509
568
  }
@@ -543,6 +602,7 @@ module.exports = {
543
602
  createEdge,
544
603
  deleteNode,
545
604
  getConnection,
605
+ getConnectionID,
546
606
  insertEdgeAfter,
547
607
  insertEdgeBefore,
548
608
  update,
@@ -13,6 +13,7 @@
13
13
  'use strict';
14
14
 
15
15
  const ConnectionHandler = require('./ConnectionHandler');
16
+ const ConnectionInterface = require('./ConnectionInterface');
16
17
 
17
18
  const invariant = require('invariant');
18
19
  const warning = require('warning');
@@ -50,6 +51,7 @@ const DeleteEdgeHandler = {
50
51
  if (record == null) {
51
52
  return;
52
53
  }
54
+ // $FlowFixMe[prop-missing]
53
55
  const {connections} = payload.handleArgs;
54
56
  invariant(
55
57
  connections != null,
@@ -99,6 +101,7 @@ function edgeUpdater(
99
101
  if (record == null) {
100
102
  return;
101
103
  }
104
+ // $FlowFixMe[prop-missing]
102
105
  const {connections} = payload.handleArgs;
103
106
  invariant(
104
107
  connections != null,
@@ -120,11 +123,17 @@ function edgeUpdater(
120
123
  );
121
124
  return;
122
125
  }
126
+ const {NODE, EDGES} = ConnectionInterface.get();
123
127
  const serverEdgeList = serverEdges ?? [singleServerEdge];
124
128
  for (const serverEdge of serverEdgeList) {
125
129
  if (serverEdge == null) {
126
130
  continue;
127
131
  }
132
+ const serverNode = serverEdge.getLinkedRecord('node');
133
+ if (!serverNode) {
134
+ continue;
135
+ }
136
+ const serverNodeId = serverNode.getDataID();
128
137
  for (const connectionID of connections) {
129
138
  const connection = store.get(connectionID);
130
139
  if (connection == null) {
@@ -134,6 +143,14 @@ function edgeUpdater(
134
143
  );
135
144
  continue;
136
145
  }
146
+ const nodeAlreadyExistsInConnection = connection
147
+ .getLinkedRecords(EDGES)
148
+ ?.some(
149
+ edge => edge?.getLinkedRecord(NODE)?.getDataID() === serverNodeId,
150
+ );
151
+ if (nodeAlreadyExistsInConnection) {
152
+ continue;
153
+ }
137
154
  const clientEdge = ConnectionHandler.buildConnectionEdge(
138
155
  store,
139
156
  connection,
@@ -157,6 +174,7 @@ function nodeUpdater(
157
174
  if (record == null) {
158
175
  return;
159
176
  }
177
+ // $FlowFixMe[prop-missing]
160
178
  const {connections, edgeTypeName} = payload.handleArgs;
161
179
  invariant(
162
180
  connections != null,
@@ -180,11 +198,13 @@ function nodeUpdater(
180
198
  warning(false, 'MutationHandlers: Expected target node to exist.');
181
199
  return;
182
200
  }
201
+ const {NODE, EDGES} = ConnectionInterface.get();
183
202
  const serverNodeList = serverNodes ?? [singleServerNode];
184
203
  for (const serverNode of serverNodeList) {
185
204
  if (serverNode == null) {
186
205
  continue;
187
206
  }
207
+ const serverNodeId = serverNode.getDataID();
188
208
  for (const connectionID of connections) {
189
209
  const connection = store.get(connectionID);
190
210
  if (connection == null) {
@@ -194,6 +214,14 @@ function nodeUpdater(
194
214
  );
195
215
  continue;
196
216
  }
217
+ const nodeAlreadyExistsInConnection = connection
218
+ .getLinkedRecords(EDGES)
219
+ ?.some(
220
+ edge => edge?.getLinkedRecord(NODE)?.getDataID() === serverNodeId,
221
+ );
222
+ if (nodeAlreadyExistsInConnection) {
223
+ continue;
224
+ }
197
225
  const clientEdge = ConnectionHandler.createEdge(
198
226
  store,
199
227
  connection,
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Relay v10.1.3
2
+ * Relay v11.0.2
3
3
  *
4
4
  * Copyright (c) Facebook, Inc. and its affiliates.
5
5
  *
package/index.js.flow CHANGED
@@ -48,6 +48,7 @@ const createRelayContext = require('./store/createRelayContext');
48
48
  const deepFreeze = require('./util/deepFreeze');
49
49
  const fetchQuery = require('./query/fetchQuery');
50
50
  const fetchQueryInternal = require('./query/fetchQueryInternal');
51
+ const fetchQuery_DEPRECATED = require('./query/fetchQuery_DEPRECATED');
51
52
  const getFragmentIdentifier = require('./util/getFragmentIdentifier');
52
53
  const getRelayHandleKey = require('./util/getRelayHandleKey');
53
54
  const getRequestIdentifier = require('./util/getRequestIdentifier');
@@ -97,6 +98,7 @@ export type {
97
98
  ReactFlightPayloadData,
98
99
  ReactFlightPayloadQuery,
99
100
  ReactFlightServerTree,
101
+ ReactFlightServerError,
100
102
  SubscribeFunction,
101
103
  Uploadable,
102
104
  UploadableMap,
@@ -108,10 +110,11 @@ export type {
108
110
  Subscription,
109
111
  } from './network/RelayObservable';
110
112
  export type {GraphQLTaggedNode} from './query/GraphQLTag';
113
+ export type {TaskScheduler} from './store/OperationExecutor';
111
114
  export type {EnvironmentConfig} from './store/RelayModernEnvironment';
112
- export type {TaskScheduler} from './store/RelayModernQueryExecutor';
113
115
  export type {RecordState} from './store/RelayRecordState';
114
116
  export type {
117
+ ExecuteMutationConfig,
115
118
  FragmentMap,
116
119
  FragmentReference,
117
120
  FragmentSpecResolver,
@@ -134,8 +137,9 @@ export type {
134
137
  PluralReaderSelector,
135
138
  Props,
136
139
  PublishQueue,
137
- ReactFlightPayloadDeserializer,
138
140
  ReactFlightClientResponse,
141
+ ReactFlightPayloadDeserializer,
142
+ ReactFlightServerErrorHandler,
139
143
  ReaderSelector,
140
144
  ReadOnlyRecordProxy,
141
145
  RecordProxy,
@@ -143,6 +147,7 @@ export type {
143
147
  RecordSourceSelectorProxy,
144
148
  RelayContext,
145
149
  RequestDescriptor,
150
+ RequiredFieldLogger,
146
151
  SelectorData,
147
152
  SelectorStoreUpdater,
148
153
  SingularReaderSelector,
@@ -287,7 +292,8 @@ module.exports = {
287
292
  applyOptimisticMutation,
288
293
  commitLocalUpdate,
289
294
  commitMutation,
290
- fetchQuery,
295
+ fetchQuery: fetchQuery,
296
+ fetchQuery_DEPRECATED,
291
297
  isRelayModernEnvironment,
292
298
  requestSubscription,
293
299
 
@@ -14,7 +14,7 @@ var ConnectionHandler = require('./connection/ConnectionHandler');
14
14
 
15
15
  var MutationHandlers = require('./connection/MutationHandlers');
16
16
 
17
- var invariant = require("fbjs/lib/invariant");
17
+ var invariant = require('invariant');
18
18
 
19
19
  function RelayDefaultHandlerProvider(handle) {
20
20
  switch (handle) {
@@ -14,13 +14,16 @@ var ConnectionInterface = require('./ConnectionInterface');
14
14
 
15
15
  var getRelayHandleKey = require('../../util/getRelayHandleKey');
16
16
 
17
- var invariant = require("fbjs/lib/invariant");
17
+ var invariant = require('invariant');
18
18
 
19
19
  var warning = require("fbjs/lib/warning");
20
20
 
21
21
  var _require = require('../../store/ClientID'),
22
22
  generateClientID = _require.generateClientID;
23
23
 
24
+ var _require2 = require('../../store/RelayStoreUtils'),
25
+ getStableStorageKey = _require2.getStableStorageKey;
26
+
24
27
  var CONNECTION = 'connection'; // Per-instance incrementing index used to generate unique edge IDs
25
28
 
26
29
  var NEXT_EDGE_INDEX = '__connection_next_edge_index';
@@ -130,19 +133,23 @@ function update(store, payload) {
130
133
  var args = payload.args;
131
134
 
132
135
  if (prevEdges && _serverEdges) {
136
+ // $FlowFixMe[prop-missing]
133
137
  if (args.after != null) {
134
138
  // Forward pagination from the end of the connection: append edges
135
- if (clientPageInfo && args.after === clientPageInfo.getValue(END_CURSOR)) {
139
+ if (clientPageInfo && // $FlowFixMe[prop-missing]
140
+ args.after === clientPageInfo.getValue(END_CURSOR)) {
136
141
  var nodeIDs = new Set();
137
142
  mergeEdges(prevEdges, nextEdges, nodeIDs);
138
143
  mergeEdges(_serverEdges, nextEdges, nodeIDs);
139
144
  } else {
140
145
  process.env.NODE_ENV !== "production" ? warning(false, 'Relay: Unexpected after cursor `%s`, edges must ' + 'be fetched from the end of the list (`%s`).', args.after, clientPageInfo && clientPageInfo.getValue(END_CURSOR)) : void 0;
141
146
  return;
142
- }
147
+ } // $FlowFixMe[prop-missing]
148
+
143
149
  } else if (args.before != null) {
144
150
  // Backward pagination from the start of the connection: prepend edges
145
- if (clientPageInfo && args.before === clientPageInfo.getValue(START_CURSOR)) {
151
+ if (clientPageInfo && // $FlowFixMe[prop-missing]
152
+ args.before === clientPageInfo.getValue(START_CURSOR)) {
146
153
  var _nodeIDs = new Set();
147
154
 
148
155
  mergeEdges(_serverEdges, nextEdges, _nodeIDs);
@@ -169,17 +176,19 @@ function update(store, payload) {
169
176
 
170
177
 
171
178
  if (clientPageInfo && serverPageInfo) {
179
+ // $FlowFixMe[prop-missing]
172
180
  if (args.after == null && args.before == null) {
173
181
  // The connection was refetched from the beginning/end: replace
174
182
  // page_info
175
- clientPageInfo.copyFieldsFrom(serverPageInfo);
183
+ clientPageInfo.copyFieldsFrom(serverPageInfo); // $FlowFixMe[prop-missing]
176
184
  } else if (args.before != null || args.after == null && args.last) {
177
185
  clientPageInfo.setValue(!!serverPageInfo.getValue(HAS_PREV_PAGE), HAS_PREV_PAGE);
178
186
  var startCursor = serverPageInfo.getValue(START_CURSOR);
179
187
 
180
188
  if (typeof startCursor === 'string') {
181
189
  clientPageInfo.setValue(startCursor, START_CURSOR);
182
- }
190
+ } // $FlowFixMe[prop-missing]
191
+
183
192
  } else if (args.after != null || args.before == null && args.first) {
184
193
  clientPageInfo.setValue(!!serverPageInfo.getValue(HAS_NEXT_PAGE), HAS_NEXT_PAGE);
185
194
  var endCursor = serverPageInfo.getValue(END_CURSOR);
@@ -235,6 +244,44 @@ function getConnection(record, key, filters) {
235
244
  var handleKey = getRelayHandleKey(CONNECTION, key, null);
236
245
  return record.getLinkedRecord(handleKey, filters);
237
246
  }
247
+ /**
248
+ * @public
249
+ *
250
+ * Given a record ID, the key of a connection field, and optional filters used
251
+ * to identify the connection, returns the connection ID.
252
+ *
253
+ * Example:
254
+ *
255
+ * Given that data has already been fetched on some user `<user-id>` on the `friends`
256
+ * field:
257
+ *
258
+ * ```
259
+ * fragment FriendsFragment on User {
260
+ * friends(first: 10) @connection(key: "FriendsFragment_friends") {
261
+ * edges {
262
+ * node {
263
+ * id
264
+ * }
265
+ * }
266
+ * }
267
+ * }
268
+ * ```
269
+ *
270
+ * The ID of the `friends` connection record can be accessed with:
271
+ *
272
+ * ```
273
+ * store => {
274
+ * const connectionID = ConnectionHandler.getConnectionID('<user-id>', 'FriendsFragment_friends');
275
+ * }
276
+ * ```
277
+ */
278
+
279
+
280
+ function getConnectionID(recordID, key, filters) {
281
+ var handleKey = getRelayHandleKey(CONNECTION, key, null);
282
+ var storageKey = getStableStorageKey(handleKey, filters);
283
+ return generateClientID(recordID, storageKey);
284
+ }
238
285
  /**
239
286
  * @public
240
287
  *
@@ -339,6 +386,13 @@ function createEdge(store, record, node, edgeType) {
339
386
  }
340
387
 
341
388
  edge.setLinkedRecord(node, NODE);
389
+
390
+ if (edge.getValue('cursor') == null) {
391
+ // Always use null instead of undefined value for cursor
392
+ // to avoid considering it as missing data
393
+ edge.setValue(null, 'cursor');
394
+ }
395
+
342
396
  return edge;
343
397
  }
344
398
  /**
@@ -484,6 +538,13 @@ function buildConnectionEdge(store, connection, edge) {
484
538
  var edgeID = generateClientID(connection.getDataID(), EDGES, edgeIndex);
485
539
  var connectionEdge = store.create(edgeID, edge.getType());
486
540
  connectionEdge.copyFieldsFrom(edge);
541
+
542
+ if (connectionEdge.getValue('cursor') == null) {
543
+ // Always use null instead of undefined value for cursor
544
+ // to avoid considering it as missing data
545
+ connectionEdge.setValue(null, 'cursor');
546
+ }
547
+
487
548
  connection.setValue(edgeIndex + 1, NEXT_EDGE_INDEX);
488
549
  return connectionEdge;
489
550
  }
@@ -526,6 +587,7 @@ module.exports = {
526
587
  createEdge: createEdge,
527
588
  deleteNode: deleteNode,
528
589
  getConnection: getConnection,
590
+ getConnectionID: getConnectionID,
529
591
  insertEdgeAfter: insertEdgeAfter,
530
592
  insertEdgeBefore: insertEdgeBefore,
531
593
  update: update
@@ -16,7 +16,9 @@ var _createForOfIteratorHelper2 = _interopRequireDefault(require("@babel/runtime
16
16
 
17
17
  var ConnectionHandler = require('./ConnectionHandler');
18
18
 
19
- var invariant = require("fbjs/lib/invariant");
19
+ var ConnectionInterface = require('./ConnectionInterface');
20
+
21
+ var invariant = require('invariant');
20
22
 
21
23
  var warning = require("fbjs/lib/warning");
22
24
 
@@ -45,7 +47,8 @@ var DeleteEdgeHandler = {
45
47
 
46
48
  if (record == null) {
47
49
  return;
48
- }
50
+ } // $FlowFixMe[prop-missing]
51
+
49
52
 
50
53
  var connections = payload.handleArgs.connections;
51
54
  !(connections != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'MutationHandlers: Expected connection IDs to be specified.') : invariant(false) : void 0;
@@ -98,7 +101,8 @@ function edgeUpdater(insertFn) {
98
101
 
99
102
  if (record == null) {
100
103
  return;
101
- }
104
+ } // $FlowFixMe[prop-missing]
105
+
102
106
 
103
107
  var connections = payload.handleArgs.connections;
104
108
  !(connections != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'MutationHandlers: Expected connection IDs to be specified.') : invariant(false) : void 0;
@@ -119,19 +123,31 @@ function edgeUpdater(insertFn) {
119
123
  return;
120
124
  }
121
125
 
126
+ var _ConnectionInterface$ = ConnectionInterface.get(),
127
+ NODE = _ConnectionInterface$.NODE,
128
+ EDGES = _ConnectionInterface$.EDGES;
129
+
122
130
  var serverEdgeList = (_serverEdges = serverEdges) !== null && _serverEdges !== void 0 ? _serverEdges : [singleServerEdge];
123
131
 
124
132
  var _iterator2 = (0, _createForOfIteratorHelper2["default"])(serverEdgeList),
125
133
  _step2;
126
134
 
127
135
  try {
128
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
136
+ var _loop = function _loop() {
129
137
  var serverEdge = _step2.value;
130
138
 
131
139
  if (serverEdge == null) {
132
- continue;
140
+ return "continue";
133
141
  }
134
142
 
143
+ var serverNode = serverEdge.getLinkedRecord('node');
144
+
145
+ if (!serverNode) {
146
+ return "continue";
147
+ }
148
+
149
+ var serverNodeId = serverNode.getDataID();
150
+
135
151
  var _iterator3 = (0, _createForOfIteratorHelper2["default"])(connections),
136
152
  _step3;
137
153
 
@@ -145,6 +161,16 @@ function edgeUpdater(insertFn) {
145
161
  continue;
146
162
  }
147
163
 
164
+ var nodeAlreadyExistsInConnection = (_connection$getLinked = connection.getLinkedRecords(EDGES)) === null || _connection$getLinked === void 0 ? void 0 : _connection$getLinked.some(function (edge) {
165
+ var _edge$getLinkedRecord;
166
+
167
+ return (edge === null || edge === void 0 ? void 0 : (_edge$getLinkedRecord = edge.getLinkedRecord(NODE)) === null || _edge$getLinkedRecord === void 0 ? void 0 : _edge$getLinkedRecord.getDataID()) === serverNodeId;
168
+ });
169
+
170
+ if (nodeAlreadyExistsInConnection) {
171
+ continue;
172
+ }
173
+
148
174
  var clientEdge = ConnectionHandler.buildConnectionEdge(store, connection, serverEdge);
149
175
  !(clientEdge != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'MutationHandlers: Failed to build the edge.') : invariant(false) : void 0;
150
176
  insertFn(connection, clientEdge);
@@ -154,6 +180,14 @@ function edgeUpdater(insertFn) {
154
180
  } finally {
155
181
  _iterator3.f();
156
182
  }
183
+ };
184
+
185
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
186
+ var _connection$getLinked;
187
+
188
+ var _ret = _loop();
189
+
190
+ if (_ret === "continue") continue;
157
191
  }
158
192
  } catch (err) {
159
193
  _iterator2.e(err);
@@ -171,7 +205,8 @@ function nodeUpdater(insertFn) {
171
205
 
172
206
  if (record == null) {
173
207
  return;
174
- }
208
+ } // $FlowFixMe[prop-missing]
209
+
175
210
 
176
211
  var _payload$handleArgs = payload.handleArgs,
177
212
  connections = _payload$handleArgs.connections,
@@ -196,19 +231,25 @@ function nodeUpdater(insertFn) {
196
231
  return;
197
232
  }
198
233
 
234
+ var _ConnectionInterface$2 = ConnectionInterface.get(),
235
+ NODE = _ConnectionInterface$2.NODE,
236
+ EDGES = _ConnectionInterface$2.EDGES;
237
+
199
238
  var serverNodeList = (_serverNodes = serverNodes) !== null && _serverNodes !== void 0 ? _serverNodes : [singleServerNode];
200
239
 
201
240
  var _iterator4 = (0, _createForOfIteratorHelper2["default"])(serverNodeList),
202
241
  _step4;
203
242
 
204
243
  try {
205
- for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
244
+ var _loop2 = function _loop2() {
206
245
  var serverNode = _step4.value;
207
246
 
208
247
  if (serverNode == null) {
209
- continue;
248
+ return "continue";
210
249
  }
211
250
 
251
+ var serverNodeId = serverNode.getDataID();
252
+
212
253
  var _iterator5 = (0, _createForOfIteratorHelper2["default"])(connections),
213
254
  _step5;
214
255
 
@@ -222,6 +263,16 @@ function nodeUpdater(insertFn) {
222
263
  continue;
223
264
  }
224
265
 
266
+ var nodeAlreadyExistsInConnection = (_connection$getLinked2 = connection.getLinkedRecords(EDGES)) === null || _connection$getLinked2 === void 0 ? void 0 : _connection$getLinked2.some(function (edge) {
267
+ var _edge$getLinkedRecord2;
268
+
269
+ return (edge === null || edge === void 0 ? void 0 : (_edge$getLinkedRecord2 = edge.getLinkedRecord(NODE)) === null || _edge$getLinkedRecord2 === void 0 ? void 0 : _edge$getLinkedRecord2.getDataID()) === serverNodeId;
270
+ });
271
+
272
+ if (nodeAlreadyExistsInConnection) {
273
+ continue;
274
+ }
275
+
225
276
  var clientEdge = ConnectionHandler.createEdge(store, connection, serverNode, edgeTypeName);
226
277
  !(clientEdge != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'MutationHandlers: Failed to build the edge.') : invariant(false) : void 0;
227
278
  insertFn(connection, clientEdge);
@@ -231,6 +282,14 @@ function nodeUpdater(insertFn) {
231
282
  } finally {
232
283
  _iterator5.f();
233
284
  }
285
+ };
286
+
287
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
288
+ var _connection$getLinked2;
289
+
290
+ var _ret2 = _loop2();
291
+
292
+ if (_ret2 === "continue") continue;
234
293
  }
235
294
  } catch (err) {
236
295
  _iterator4.e(err);
package/lib/index.js CHANGED
@@ -80,6 +80,8 @@ var fetchQuery = require('./query/fetchQuery');
80
80
 
81
81
  var fetchQueryInternal = require('./query/fetchQueryInternal');
82
82
 
83
+ var fetchQuery_DEPRECATED = require('./query/fetchQuery_DEPRECATED');
84
+
83
85
  var getFragmentIdentifier = require('./util/getFragmentIdentifier');
84
86
 
85
87
  var getRelayHandleKey = require('./util/getRelayHandleKey');
@@ -180,6 +182,7 @@ module.exports = {
180
182
  commitLocalUpdate: commitLocalUpdate,
181
183
  commitMutation: commitMutation,
182
184
  fetchQuery: fetchQuery,
185
+ fetchQuery_DEPRECATED: fetchQuery_DEPRECATED,
183
186
  isRelayModernEnvironment: isRelayModernEnvironment,
184
187
  requestSubscription: requestSubscription,
185
188
  // Configuration interface for legacy or special uses
@@ -0,0 +1,23 @@
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
+ * @emails oncall+relay
8
+ *
9
+ * @format
10
+ */
11
+ 'use strict';
12
+ /**
13
+ * A unique identifier of the current actor.
14
+ */
15
+
16
+ module.exports = {
17
+ getActorIdentifier: function getActorIdentifier(actorID) {
18
+ return actorID;
19
+ },
20
+ getDefaultActorIdentifier: function getDefaultActorIdentifier() {
21
+ throw new Error('Not Implemented');
22
+ }
23
+ };