relay-runtime 10.0.1 → 10.1.3
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 +6 -0
- package/handlers/connection/MutationHandlers.js.flow +152 -20
- package/index.js +1 -1
- package/index.js.flow +17 -1
- package/lib/handlers/RelayDefaultHandlerProvider.js +9 -0
- package/lib/handlers/connection/MutationHandlers.js +185 -21
- package/lib/index.js +7 -0
- package/lib/mutations/RelayDeclarativeMutationConfig.js +5 -7
- package/lib/mutations/commitMutation.js +1 -4
- package/lib/mutations/validateMutation.js +28 -12
- package/lib/network/RelayQueryResponseCache.js +3 -7
- package/lib/query/GraphQLTag.js +2 -1
- package/lib/query/fetchQuery.js +2 -3
- package/lib/query/fetchQueryInternal.js +2 -3
- package/lib/store/DataChecker.js +85 -10
- package/lib/store/RelayConcreteVariables.js +2 -6
- package/lib/store/RelayModernEnvironment.js +81 -72
- package/lib/store/RelayModernFragmentSpecResolver.js +14 -7
- package/lib/store/RelayModernOperationDescriptor.js +6 -5
- package/lib/store/RelayModernQueryExecutor.js +46 -33
- package/lib/store/RelayModernRecord.js +3 -7
- package/lib/store/RelayModernStore.js +39 -137
- package/lib/store/RelayOperationTracker.js +7 -9
- package/lib/store/RelayOptimisticRecordSource.js +2 -6
- package/lib/store/RelayPublishQueue.js +1 -1
- package/lib/store/RelayReader.js +196 -33
- package/lib/store/RelayRecordSourceMapImpl.js +3 -5
- package/lib/store/RelayReferenceMarker.js +87 -5
- package/lib/store/RelayResponseNormalizer.js +115 -19
- package/lib/store/RelayStoreReactFlightUtils.js +47 -0
- package/lib/store/RelayStoreSubscriptions.js +162 -0
- package/lib/store/RelayStoreSubscriptionsUsingMapByID.js +258 -0
- package/lib/store/StoreInspector.js +2 -6
- package/lib/store/createRelayContext.js +5 -0
- package/lib/store/defaultRequiredFieldLogger.js +18 -0
- package/lib/store/normalizeRelayPayload.js +2 -6
- package/lib/subscription/requestSubscription.js +2 -3
- package/lib/util/NormalizationNode.js +1 -5
- package/lib/util/RelayConcreteNode.js +2 -0
- package/lib/util/RelayFeatureFlags.js +7 -2
- package/lib/util/createPayloadFor3DField.js +2 -7
- package/lib/util/getFragmentIdentifier.js +12 -3
- package/lib/util/getOperation.js +33 -0
- package/lib/util/isEmptyObject.js +25 -0
- package/lib/util/recycleNodesInto.js +4 -1
- package/lib/util/reportMissingRequiredFields.js +48 -0
- package/mutations/commitMutation.js.flow +1 -2
- package/mutations/validateMutation.js.flow +34 -5
- package/network/RelayNetworkTypes.js.flow +22 -0
- package/package.json +2 -2
- package/query/GraphQLTag.js.flow +3 -1
- package/query/fetchQuery.js.flow +2 -2
- package/query/fetchQueryInternal.js.flow +0 -5
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +2 -2
- package/store/DataChecker.js.flow +68 -2
- package/store/RelayModernEnvironment.js.flow +107 -87
- package/store/RelayModernFragmentSpecResolver.js.flow +13 -1
- package/store/RelayModernOperationDescriptor.js.flow +5 -1
- package/store/RelayModernQueryExecutor.js.flow +47 -23
- package/store/RelayModernStore.js.flow +33 -107
- package/store/RelayPublishQueue.js.flow +1 -1
- package/store/RelayReader.js.flow +180 -15
- package/store/RelayReferenceMarker.js.flow +72 -5
- package/store/RelayResponseNormalizer.js.flow +130 -19
- package/store/RelayStoreReactFlightUtils.js.flow +64 -0
- package/store/RelayStoreSubscriptions.js.flow +168 -0
- package/store/RelayStoreSubscriptionsUsingMapByID.js.flow +259 -0
- package/store/RelayStoreTypes.js.flow +130 -37
- package/store/createRelayContext.js.flow +3 -0
- package/store/defaultRequiredFieldLogger.js.flow +23 -0
- package/subscription/requestSubscription.js.flow +5 -2
- package/util/NormalizationNode.js.flow +17 -2
- package/util/ReaderNode.js.flow +20 -1
- package/util/RelayConcreteNode.js.flow +6 -0
- package/util/RelayFeatureFlags.js.flow +12 -1
- package/util/getFragmentIdentifier.js.flow +33 -9
- package/util/getOperation.js.flow +40 -0
- package/util/getRequestIdentifier.js.flow +1 -1
- package/util/isEmptyObject.js.flow +25 -0
- package/util/recycleNodesInto.js.flow +11 -0
- package/util/reportMissingRequiredFields.js.flow +51 -0
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
14
14
|
|
|
15
|
+
var _createForOfIteratorHelper2 = _interopRequireDefault(require("@babel/runtime/helpers/createForOfIteratorHelper"));
|
|
16
|
+
|
|
15
17
|
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
16
18
|
|
|
17
19
|
var RelayFeatureFlags = require('../util/RelayFeatureFlags');
|
|
@@ -20,6 +22,8 @@ var RelayModernRecord = require('./RelayModernRecord');
|
|
|
20
22
|
|
|
21
23
|
var RelayProfiler = require('../util/RelayProfiler');
|
|
22
24
|
|
|
25
|
+
var areEqual = require("fbjs/lib/areEqual");
|
|
26
|
+
|
|
23
27
|
var invariant = require("fbjs/lib/invariant");
|
|
24
28
|
|
|
25
29
|
var warning = require("fbjs/lib/warning");
|
|
@@ -28,6 +32,7 @@ var _require = require('../util/RelayConcreteNode'),
|
|
|
28
32
|
CONDITION = _require.CONDITION,
|
|
29
33
|
CLIENT_EXTENSION = _require.CLIENT_EXTENSION,
|
|
30
34
|
DEFER = _require.DEFER,
|
|
35
|
+
FLIGHT_FIELD = _require.FLIGHT_FIELD,
|
|
31
36
|
INLINE_FRAGMENT = _require.INLINE_FRAGMENT,
|
|
32
37
|
LINKED_FIELD = _require.LINKED_FIELD,
|
|
33
38
|
LINKED_HANDLE = _require.LINKED_HANDLE,
|
|
@@ -44,18 +49,25 @@ var _require2 = require('./ClientID'),
|
|
|
44
49
|
var _require3 = require('./RelayModernSelector'),
|
|
45
50
|
createNormalizationSelector = _require3.createNormalizationSelector;
|
|
46
51
|
|
|
47
|
-
var _require4 = require('./
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
var _require4 = require('./RelayStoreReactFlightUtils'),
|
|
53
|
+
refineToReactFlightPayloadData = _require4.refineToReactFlightPayloadData,
|
|
54
|
+
REACT_FLIGHT_QUERIES_STORAGE_KEY = _require4.REACT_FLIGHT_QUERIES_STORAGE_KEY,
|
|
55
|
+
REACT_FLIGHT_TREE_STORAGE_KEY = _require4.REACT_FLIGHT_TREE_STORAGE_KEY,
|
|
56
|
+
REACT_FLIGHT_TYPE_NAME = _require4.REACT_FLIGHT_TYPE_NAME;
|
|
57
|
+
|
|
58
|
+
var _require5 = require('./RelayStoreUtils'),
|
|
59
|
+
getArgumentValues = _require5.getArgumentValues,
|
|
60
|
+
getHandleStorageKey = _require5.getHandleStorageKey,
|
|
61
|
+
getModuleComponentKey = _require5.getModuleComponentKey,
|
|
62
|
+
getModuleOperationKey = _require5.getModuleOperationKey,
|
|
63
|
+
getStorageKey = _require5.getStorageKey,
|
|
64
|
+
TYPENAME_KEY = _require5.TYPENAME_KEY,
|
|
65
|
+
ROOT_ID = _require5.ROOT_ID,
|
|
66
|
+
ROOT_TYPE = _require5.ROOT_TYPE;
|
|
67
|
+
|
|
68
|
+
var _require6 = require('./TypeID'),
|
|
69
|
+
generateTypeID = _require6.generateTypeID,
|
|
70
|
+
TYPE_SCHEMA_TYPE = _require6.TYPE_SCHEMA_TYPE;
|
|
59
71
|
|
|
60
72
|
/**
|
|
61
73
|
* Normalizes the results of a query and standard GraphQL response, writing the
|
|
@@ -87,6 +99,7 @@ var RelayResponseNormalizer = /*#__PURE__*/function () {
|
|
|
87
99
|
this._path = options.path ? (0, _toConsumableArray2["default"])(options.path) : [];
|
|
88
100
|
this._recordSource = recordSource;
|
|
89
101
|
this._variables = variables;
|
|
102
|
+
this._reactFlightPayloadDeserializer = options.reactFlightPayloadDeserializer;
|
|
90
103
|
}
|
|
91
104
|
|
|
92
105
|
var _proto = RelayResponseNormalizer.prototype;
|
|
@@ -252,6 +265,15 @@ var RelayResponseNormalizer = /*#__PURE__*/function () {
|
|
|
252
265
|
this._isClientExtension = isClientExtension;
|
|
253
266
|
break;
|
|
254
267
|
|
|
268
|
+
case FLIGHT_FIELD:
|
|
269
|
+
if (RelayFeatureFlags.ENABLE_REACT_FLIGHT_COMPONENT_FIELD) {
|
|
270
|
+
this._normalizeFlightField(node, selection, record, data);
|
|
271
|
+
} else {
|
|
272
|
+
throw new Error('Flight fields are not yet supported.');
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
break;
|
|
276
|
+
|
|
255
277
|
default:
|
|
256
278
|
selection;
|
|
257
279
|
!false ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayResponseNormalizer(): Unexpected ast kind `%s`.', selection.kind) : invariant(false) : void 0;
|
|
@@ -366,8 +388,10 @@ var RelayResponseNormalizer = /*#__PURE__*/function () {
|
|
|
366
388
|
}
|
|
367
389
|
}
|
|
368
390
|
|
|
369
|
-
if (
|
|
370
|
-
|
|
391
|
+
if (process.env.NODE_ENV !== "production") {
|
|
392
|
+
if (selection.kind === SCALAR_FIELD) {
|
|
393
|
+
this._validateConflictingFieldsWithIdenticalId(record, storageKey, fieldValue);
|
|
394
|
+
}
|
|
371
395
|
}
|
|
372
396
|
|
|
373
397
|
RelayModernRecord.setValue(record, storageKey, null);
|
|
@@ -375,7 +399,9 @@ var RelayResponseNormalizer = /*#__PURE__*/function () {
|
|
|
375
399
|
}
|
|
376
400
|
|
|
377
401
|
if (selection.kind === SCALAR_FIELD) {
|
|
378
|
-
|
|
402
|
+
if (process.env.NODE_ENV !== "production") {
|
|
403
|
+
this._validateConflictingFieldsWithIdenticalId(record, storageKey, fieldValue);
|
|
404
|
+
}
|
|
379
405
|
|
|
380
406
|
RelayModernRecord.setValue(record, storageKey, fieldValue);
|
|
381
407
|
} else if (selection.kind === LINKED_FIELD) {
|
|
@@ -394,6 +420,70 @@ var RelayResponseNormalizer = /*#__PURE__*/function () {
|
|
|
394
420
|
}
|
|
395
421
|
};
|
|
396
422
|
|
|
423
|
+
_proto._normalizeFlightField = function _normalizeFlightField(parent, selection, record, data) {
|
|
424
|
+
var responseKey = selection.alias || selection.name;
|
|
425
|
+
var storageKey = getStorageKey(selection, this._variables);
|
|
426
|
+
var fieldValue = data[responseKey];
|
|
427
|
+
|
|
428
|
+
if (fieldValue == null) {
|
|
429
|
+
RelayModernRecord.setValue(record, storageKey, null);
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
var reactFlightPayload = refineToReactFlightPayloadData(fieldValue);
|
|
434
|
+
!(reactFlightPayload != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayResponseNormalizer(): Expected React Flight payload data ' + 'to be an object with `tree` and `queries` properties, got `%s`.', fieldValue) : invariant(false) : void 0;
|
|
435
|
+
!(typeof this._reactFlightPayloadDeserializer === 'function') ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayResponseNormalizer: Expected reactFlightPayloadDeserializer to ' + 'be a function, got `%s`.', this._reactFlightPayloadDeserializer) : invariant(false) : void 0; // We store the deserialized reactFlightClientResponse in a separate
|
|
436
|
+
// record and link it to the parent record. This is so we can GC the Flight
|
|
437
|
+
// tree later even if the parent record is still reachable.
|
|
438
|
+
|
|
439
|
+
var reactFlightClientResponse = this._reactFlightPayloadDeserializer(reactFlightPayload.tree);
|
|
440
|
+
|
|
441
|
+
var reactFlightID = generateClientID(RelayModernRecord.getDataID(record), getStorageKey(selection, this._variables));
|
|
442
|
+
|
|
443
|
+
var reactFlightClientResponseRecord = this._recordSource.get(reactFlightID);
|
|
444
|
+
|
|
445
|
+
if (reactFlightClientResponseRecord == null) {
|
|
446
|
+
reactFlightClientResponseRecord = RelayModernRecord.create(reactFlightID, REACT_FLIGHT_TYPE_NAME);
|
|
447
|
+
|
|
448
|
+
this._recordSource.set(reactFlightID, reactFlightClientResponseRecord);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
RelayModernRecord.setValue(reactFlightClientResponseRecord, REACT_FLIGHT_TREE_STORAGE_KEY, reactFlightClientResponse);
|
|
452
|
+
var reachableQueries = [];
|
|
453
|
+
|
|
454
|
+
var _iterator = (0, _createForOfIteratorHelper2["default"])(reactFlightPayload.queries),
|
|
455
|
+
_step;
|
|
456
|
+
|
|
457
|
+
try {
|
|
458
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
459
|
+
var query = _step.value;
|
|
460
|
+
|
|
461
|
+
if (query.response.data != null) {
|
|
462
|
+
this._moduleImportPayloads.push({
|
|
463
|
+
data: query.response.data,
|
|
464
|
+
dataID: ROOT_ID,
|
|
465
|
+
operationReference: query.module,
|
|
466
|
+
path: [],
|
|
467
|
+
typeName: ROOT_TYPE,
|
|
468
|
+
variables: query.variables
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
reachableQueries.push({
|
|
473
|
+
module: query.module,
|
|
474
|
+
variables: query.variables
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
} catch (err) {
|
|
478
|
+
_iterator.e(err);
|
|
479
|
+
} finally {
|
|
480
|
+
_iterator.f();
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
RelayModernRecord.setValue(reactFlightClientResponseRecord, REACT_FLIGHT_QUERIES_STORAGE_KEY, reachableQueries);
|
|
484
|
+
RelayModernRecord.setLinkedRecordID(record, storageKey, reactFlightID);
|
|
485
|
+
};
|
|
486
|
+
|
|
397
487
|
_proto._normalizeLink = function _normalizeLink(field, record, storageKey, fieldValue) {
|
|
398
488
|
var _field$concreteType;
|
|
399
489
|
|
|
@@ -463,10 +553,14 @@ var RelayResponseNormalizer = /*#__PURE__*/function () {
|
|
|
463
553
|
_this._recordSource.set(nextID, nextRecord);
|
|
464
554
|
} else if (process.env.NODE_ENV !== "production") {
|
|
465
555
|
_this._validateRecordType(nextRecord, field, item);
|
|
466
|
-
}
|
|
556
|
+
} // NOTE: the check to strip __DEV__ code only works for simple
|
|
557
|
+
// `if (__DEV__)`
|
|
467
558
|
|
|
468
|
-
|
|
469
|
-
|
|
559
|
+
|
|
560
|
+
if (process.env.NODE_ENV !== "production") {
|
|
561
|
+
if (prevIDs) {
|
|
562
|
+
_this._validateConflictingLinkedFieldsWithIdenticalId(record, prevIDs[nextIndex], nextID, storageKey);
|
|
563
|
+
}
|
|
470
564
|
} // $FlowFixMe[incompatible-variance]
|
|
471
565
|
|
|
472
566
|
|
|
@@ -494,10 +588,11 @@ var RelayResponseNormalizer = /*#__PURE__*/function () {
|
|
|
494
588
|
;
|
|
495
589
|
|
|
496
590
|
_proto._validateConflictingFieldsWithIdenticalId = function _validateConflictingFieldsWithIdenticalId(record, storageKey, fieldValue) {
|
|
591
|
+
// NOTE: Only call this function in DEV
|
|
497
592
|
if (process.env.NODE_ENV !== "production") {
|
|
498
593
|
var dataID = RelayModernRecord.getDataID(record);
|
|
499
594
|
var previousValue = RelayModernRecord.getValue(record, storageKey);
|
|
500
|
-
process.env.NODE_ENV !== "production" ? warning(storageKey === TYPENAME_KEY || previousValue === undefined || previousValue
|
|
595
|
+
process.env.NODE_ENV !== "production" ? warning(storageKey === TYPENAME_KEY || previousValue === undefined || areEqual(previousValue, fieldValue), 'RelayResponseNormalizer: Invalid record. The record contains two ' + 'instances of the same id: `%s` with conflicting field, %s and its values: %s and %s. ' + 'If two fields are different but share ' + 'the same id, one field will overwrite the other.', dataID, storageKey, previousValue, fieldValue) : void 0;
|
|
501
596
|
}
|
|
502
597
|
}
|
|
503
598
|
/**
|
|
@@ -506,6 +601,7 @@ var RelayResponseNormalizer = /*#__PURE__*/function () {
|
|
|
506
601
|
;
|
|
507
602
|
|
|
508
603
|
_proto._validateConflictingLinkedFieldsWithIdenticalId = function _validateConflictingLinkedFieldsWithIdenticalId(record, prevID, nextID, storageKey) {
|
|
604
|
+
// NOTE: Only call this function in DEV
|
|
509
605
|
if (process.env.NODE_ENV !== "production") {
|
|
510
606
|
process.env.NODE_ENV !== "production" ? warning(prevID === undefined || prevID === nextID, 'RelayResponseNormalizer: Invalid record. The record contains ' + 'references to the conflicting field, %s and its id values: %s and %s. ' + 'We need to make sure that the record the field points ' + 'to remains consistent or one field will overwrite the other.', storageKey, prevID, nextID) : void 0;
|
|
511
607
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
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
|
+
*
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
// flowlint ambiguous-object-type:error
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
var invariant = require("fbjs/lib/invariant");
|
|
14
|
+
|
|
15
|
+
var _require = require('./RelayModernRecord'),
|
|
16
|
+
getType = _require.getType;
|
|
17
|
+
|
|
18
|
+
var REACT_FLIGHT_QUERIES_STORAGE_KEY = 'queries';
|
|
19
|
+
var REACT_FLIGHT_TREE_STORAGE_KEY = 'tree';
|
|
20
|
+
var REACT_FLIGHT_TYPE_NAME = 'ReactFlightComponent';
|
|
21
|
+
|
|
22
|
+
function refineToReactFlightPayloadData(payload) {
|
|
23
|
+
if (payload == null || typeof payload !== 'object' || !Array.isArray(payload.tree) || !Array.isArray(payload.queries)) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return payload;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getReactFlightClientResponse(record) {
|
|
31
|
+
!(getType(record) === REACT_FLIGHT_TYPE_NAME) ? process.env.NODE_ENV !== "production" ? invariant(false, 'getReactFlightClientResponse(): Expected a ReactFlightComponentRecord, ' + 'got %s.', record) : invariant(false) : void 0;
|
|
32
|
+
var response = record[REACT_FLIGHT_TREE_STORAGE_KEY];
|
|
33
|
+
|
|
34
|
+
if (response != null) {
|
|
35
|
+
return response;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = {
|
|
42
|
+
REACT_FLIGHT_QUERIES_STORAGE_KEY: REACT_FLIGHT_QUERIES_STORAGE_KEY,
|
|
43
|
+
REACT_FLIGHT_TREE_STORAGE_KEY: REACT_FLIGHT_TREE_STORAGE_KEY,
|
|
44
|
+
REACT_FLIGHT_TYPE_NAME: REACT_FLIGHT_TYPE_NAME,
|
|
45
|
+
getReactFlightClientResponse: getReactFlightClientResponse,
|
|
46
|
+
refineToReactFlightPayloadData: refineToReactFlightPayloadData
|
|
47
|
+
};
|
|
@@ -0,0 +1,162 @@
|
|
|
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
|
+
*
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
// flowlint ambiguous-object-type:error
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
var RelayReader = require('./RelayReader');
|
|
14
|
+
|
|
15
|
+
var deepFreeze = require('../util/deepFreeze');
|
|
16
|
+
|
|
17
|
+
var hasOverlappingIDs = require('./hasOverlappingIDs');
|
|
18
|
+
|
|
19
|
+
var isEmptyObject = require('../util/isEmptyObject');
|
|
20
|
+
|
|
21
|
+
var recycleNodesInto = require('../util/recycleNodesInto');
|
|
22
|
+
|
|
23
|
+
var RelayStoreSubscriptions = /*#__PURE__*/function () {
|
|
24
|
+
function RelayStoreSubscriptions() {
|
|
25
|
+
this._subscriptions = new Set();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var _proto = RelayStoreSubscriptions.prototype;
|
|
29
|
+
|
|
30
|
+
_proto.subscribe = function subscribe(snapshot, callback) {
|
|
31
|
+
var _this = this;
|
|
32
|
+
|
|
33
|
+
var subscription = {
|
|
34
|
+
backup: null,
|
|
35
|
+
callback: callback,
|
|
36
|
+
snapshot: snapshot,
|
|
37
|
+
stale: false
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
var dispose = function dispose() {
|
|
41
|
+
_this._subscriptions["delete"](subscription);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
this._subscriptions.add(subscription);
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
dispose: dispose
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
_proto.snapshotSubscriptions = function snapshotSubscriptions(source) {
|
|
52
|
+
this._subscriptions.forEach(function (subscription) {
|
|
53
|
+
// Backup occurs after writing a new "final" payload(s) and before (re)applying
|
|
54
|
+
// optimistic changes. Each subscription's `snapshot` represents what was *last
|
|
55
|
+
// published to the subscriber*, which notably may include previous optimistic
|
|
56
|
+
// updates. Therefore a subscription can be in any of the following states:
|
|
57
|
+
// - stale=true: This subscription was restored to a different value than
|
|
58
|
+
// `snapshot`. That means this subscription has changes relative to its base,
|
|
59
|
+
// but its base has changed (we just applied a final payload): recompute
|
|
60
|
+
// a backup so that we can later restore to the state the subscription
|
|
61
|
+
// should be in.
|
|
62
|
+
// - stale=false: This subscription was restored to the same value than
|
|
63
|
+
// `snapshot`. That means this subscription does *not* have changes relative
|
|
64
|
+
// to its base, so the current `snapshot` is valid to use as a backup.
|
|
65
|
+
if (!subscription.stale) {
|
|
66
|
+
subscription.backup = subscription.snapshot;
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
var snapshot = subscription.snapshot;
|
|
71
|
+
var backup = RelayReader.read(source, snapshot.selector);
|
|
72
|
+
var nextData = recycleNodesInto(snapshot.data, backup.data);
|
|
73
|
+
backup.data = nextData; // backup owns the snapshot and can safely mutate
|
|
74
|
+
|
|
75
|
+
subscription.backup = backup;
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
_proto.restoreSubscriptions = function restoreSubscriptions() {
|
|
80
|
+
this._subscriptions.forEach(function (subscription) {
|
|
81
|
+
var backup = subscription.backup;
|
|
82
|
+
subscription.backup = null;
|
|
83
|
+
|
|
84
|
+
if (backup) {
|
|
85
|
+
if (backup.data !== subscription.snapshot.data) {
|
|
86
|
+
subscription.stale = true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
subscription.snapshot = {
|
|
90
|
+
data: subscription.snapshot.data,
|
|
91
|
+
isMissingData: backup.isMissingData,
|
|
92
|
+
seenRecords: backup.seenRecords,
|
|
93
|
+
selector: backup.selector,
|
|
94
|
+
missingRequiredFields: backup.missingRequiredFields
|
|
95
|
+
};
|
|
96
|
+
} else {
|
|
97
|
+
subscription.stale = true;
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
_proto.updateSubscriptions = function updateSubscriptions(source, updatedRecordIDs, updatedOwners) {
|
|
103
|
+
var _this2 = this;
|
|
104
|
+
|
|
105
|
+
var hasUpdatedRecords = !isEmptyObject(updatedRecordIDs);
|
|
106
|
+
|
|
107
|
+
this._subscriptions.forEach(function (subscription) {
|
|
108
|
+
var owner = _this2._updateSubscription(source, subscription, updatedRecordIDs, hasUpdatedRecords);
|
|
109
|
+
|
|
110
|
+
if (owner != null) {
|
|
111
|
+
updatedOwners.push(owner);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Notifies the callback for the subscription if the data for the associated
|
|
117
|
+
* snapshot has changed.
|
|
118
|
+
* Additionally, updates the subscription snapshot with the latest snapshot,
|
|
119
|
+
* and marks it as not stale.
|
|
120
|
+
* Returns the owner (RequestDescriptor) if the subscription was affected by the
|
|
121
|
+
* latest update, or null if it was not affected.
|
|
122
|
+
*/
|
|
123
|
+
;
|
|
124
|
+
|
|
125
|
+
_proto._updateSubscription = function _updateSubscription(source, subscription, updatedRecordIDs, hasUpdatedRecords) {
|
|
126
|
+
var backup = subscription.backup,
|
|
127
|
+
callback = subscription.callback,
|
|
128
|
+
snapshot = subscription.snapshot,
|
|
129
|
+
stale = subscription.stale;
|
|
130
|
+
var hasOverlappingUpdates = hasUpdatedRecords && hasOverlappingIDs(snapshot.seenRecords, updatedRecordIDs);
|
|
131
|
+
|
|
132
|
+
if (!stale && !hasOverlappingUpdates) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
var nextSnapshot = hasOverlappingUpdates || !backup ? RelayReader.read(source, snapshot.selector) : backup;
|
|
137
|
+
var nextData = recycleNodesInto(snapshot.data, nextSnapshot.data);
|
|
138
|
+
nextSnapshot = {
|
|
139
|
+
data: nextData,
|
|
140
|
+
isMissingData: nextSnapshot.isMissingData,
|
|
141
|
+
seenRecords: nextSnapshot.seenRecords,
|
|
142
|
+
selector: nextSnapshot.selector,
|
|
143
|
+
missingRequiredFields: nextSnapshot.missingRequiredFields
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
if (process.env.NODE_ENV !== "production") {
|
|
147
|
+
deepFreeze(nextSnapshot);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
subscription.snapshot = nextSnapshot;
|
|
151
|
+
subscription.stale = false;
|
|
152
|
+
|
|
153
|
+
if (nextSnapshot.data !== snapshot.data) {
|
|
154
|
+
callback(nextSnapshot);
|
|
155
|
+
return snapshot.selector.owner;
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
return RelayStoreSubscriptions;
|
|
160
|
+
}();
|
|
161
|
+
|
|
162
|
+
module.exports = RelayStoreSubscriptions;
|
|
@@ -0,0 +1,258 @@
|
|
|
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
|
+
*
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
// flowlint ambiguous-object-type:error
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
var RelayReader = require('./RelayReader');
|
|
14
|
+
|
|
15
|
+
var deepFreeze = require('../util/deepFreeze');
|
|
16
|
+
|
|
17
|
+
var recycleNodesInto = require('../util/recycleNodesInto');
|
|
18
|
+
|
|
19
|
+
var RelayStoreSubscriptionsUsingMapByID = /*#__PURE__*/function () {
|
|
20
|
+
function RelayStoreSubscriptionsUsingMapByID() {
|
|
21
|
+
this._notifiedRevision = 0;
|
|
22
|
+
this._snapshotRevision = 0;
|
|
23
|
+
this._subscriptionsByDataId = new Map();
|
|
24
|
+
this._staleSubscriptions = new Set();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var _proto = RelayStoreSubscriptionsUsingMapByID.prototype;
|
|
28
|
+
|
|
29
|
+
_proto.subscribe = function subscribe(snapshot, callback) {
|
|
30
|
+
var _this = this;
|
|
31
|
+
|
|
32
|
+
var subscription = {
|
|
33
|
+
backup: null,
|
|
34
|
+
callback: callback,
|
|
35
|
+
notifiedRevision: this._notifiedRevision,
|
|
36
|
+
snapshotRevision: this._snapshotRevision,
|
|
37
|
+
snapshot: snapshot
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
var dispose = function dispose() {
|
|
41
|
+
for (var dataId in snapshot.seenRecords) {
|
|
42
|
+
var subscriptionsForDataId = _this._subscriptionsByDataId.get(dataId);
|
|
43
|
+
|
|
44
|
+
if (subscriptionsForDataId != null) {
|
|
45
|
+
subscriptionsForDataId["delete"](subscription);
|
|
46
|
+
|
|
47
|
+
if (subscriptionsForDataId.size === 0) {
|
|
48
|
+
_this._subscriptionsByDataId["delete"](dataId);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
for (var dataId in snapshot.seenRecords) {
|
|
55
|
+
var subscriptionsForDataId = this._subscriptionsByDataId.get(dataId);
|
|
56
|
+
|
|
57
|
+
if (subscriptionsForDataId != null) {
|
|
58
|
+
subscriptionsForDataId.add(subscription);
|
|
59
|
+
} else {
|
|
60
|
+
this._subscriptionsByDataId.set(dataId, new Set([subscription]));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
dispose: dispose
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
_proto.snapshotSubscriptions = function snapshotSubscriptions(source) {
|
|
70
|
+
var _this2 = this;
|
|
71
|
+
|
|
72
|
+
this._snapshotRevision++;
|
|
73
|
+
|
|
74
|
+
this._subscriptionsByDataId.forEach(function (subscriptions) {
|
|
75
|
+
subscriptions.forEach(function (subscription) {
|
|
76
|
+
if (subscription.snapshotRevision === _this2._snapshotRevision) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
subscription.snapshotRevision = _this2._snapshotRevision; // Backup occurs after writing a new "final" payload(s) and before (re)applying
|
|
81
|
+
// optimistic changes. Each subscription's `snapshot` represents what was *last
|
|
82
|
+
// published to the subscriber*, which notably may include previous optimistic
|
|
83
|
+
// updates. Therefore a subscription can be in any of the following states:
|
|
84
|
+
// - stale=true: This subscription was restored to a different value than
|
|
85
|
+
// `snapshot`. That means this subscription has changes relative to its base,
|
|
86
|
+
// but its base has changed (we just applied a final payload): recompute
|
|
87
|
+
// a backup so that we can later restore to the state the subscription
|
|
88
|
+
// should be in.
|
|
89
|
+
// - stale=false: This subscription was restored to the same value than
|
|
90
|
+
// `snapshot`. That means this subscription does *not* have changes relative
|
|
91
|
+
// to its base, so the current `snapshot` is valid to use as a backup.
|
|
92
|
+
|
|
93
|
+
if (!_this2._staleSubscriptions.has(subscription)) {
|
|
94
|
+
subscription.backup = subscription.snapshot;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
var snapshot = subscription.snapshot;
|
|
99
|
+
var backup = RelayReader.read(source, snapshot.selector);
|
|
100
|
+
var nextData = recycleNodesInto(snapshot.data, backup.data);
|
|
101
|
+
backup.data = nextData; // backup owns the snapshot and can safely mutate
|
|
102
|
+
|
|
103
|
+
subscription.backup = backup;
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
_proto.restoreSubscriptions = function restoreSubscriptions() {
|
|
109
|
+
var _this3 = this;
|
|
110
|
+
|
|
111
|
+
this._snapshotRevision++;
|
|
112
|
+
|
|
113
|
+
this._subscriptionsByDataId.forEach(function (subscriptions) {
|
|
114
|
+
subscriptions.forEach(function (subscription) {
|
|
115
|
+
if (subscription.snapshotRevision === _this3._snapshotRevision) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
subscription.snapshotRevision = _this3._snapshotRevision;
|
|
120
|
+
var backup = subscription.backup;
|
|
121
|
+
subscription.backup = null;
|
|
122
|
+
|
|
123
|
+
if (backup) {
|
|
124
|
+
if (backup.data !== subscription.snapshot.data) {
|
|
125
|
+
_this3._staleSubscriptions.add(subscription);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
var prevSeenRecords = subscription.snapshot.seenRecords;
|
|
129
|
+
subscription.snapshot = {
|
|
130
|
+
data: subscription.snapshot.data,
|
|
131
|
+
isMissingData: backup.isMissingData,
|
|
132
|
+
seenRecords: backup.seenRecords,
|
|
133
|
+
selector: backup.selector,
|
|
134
|
+
missingRequiredFields: backup.missingRequiredFields
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
_this3._updateSubscriptionsMap(subscription, prevSeenRecords);
|
|
138
|
+
} else {
|
|
139
|
+
_this3._staleSubscriptions.add(subscription);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
_proto.updateSubscriptions = function updateSubscriptions(source, updatedRecordIDs, updatedOwners) {
|
|
146
|
+
var _this4 = this;
|
|
147
|
+
|
|
148
|
+
this._notifiedRevision++;
|
|
149
|
+
Object.keys(updatedRecordIDs).forEach(function (updatedRecordId) {
|
|
150
|
+
var subcriptionsForDataId = _this4._subscriptionsByDataId.get(updatedRecordId);
|
|
151
|
+
|
|
152
|
+
if (subcriptionsForDataId == null) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
subcriptionsForDataId.forEach(function (subscription) {
|
|
157
|
+
if (subscription.notifiedRevision === _this4._notifiedRevision) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
var owner = _this4._updateSubscription(source, subscription, false);
|
|
162
|
+
|
|
163
|
+
if (owner != null) {
|
|
164
|
+
updatedOwners.push(owner);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
this._staleSubscriptions.forEach(function (subscription) {
|
|
170
|
+
if (subscription.notifiedRevision === _this4._notifiedRevision) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
var owner = _this4._updateSubscription(source, subscription, true);
|
|
175
|
+
|
|
176
|
+
if (owner != null) {
|
|
177
|
+
updatedOwners.push(owner);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
this._staleSubscriptions.clear();
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Notifies the callback for the subscription if the data for the associated
|
|
185
|
+
* snapshot has changed.
|
|
186
|
+
* Additionally, updates the subscription snapshot with the latest snapshot,
|
|
187
|
+
* amarks it as not stale, and updates the subscription tracking for any
|
|
188
|
+
* any new ids observed in the latest data snapshot.
|
|
189
|
+
* Returns the owner (RequestDescriptor) if the subscription was affected by the
|
|
190
|
+
* latest update, or null if it was not affected.
|
|
191
|
+
*/
|
|
192
|
+
;
|
|
193
|
+
|
|
194
|
+
_proto._updateSubscription = function _updateSubscription(source, subscription, stale) {
|
|
195
|
+
var backup = subscription.backup,
|
|
196
|
+
callback = subscription.callback,
|
|
197
|
+
snapshot = subscription.snapshot;
|
|
198
|
+
var nextSnapshot = stale && backup != null ? backup : RelayReader.read(source, snapshot.selector);
|
|
199
|
+
var nextData = recycleNodesInto(snapshot.data, nextSnapshot.data);
|
|
200
|
+
nextSnapshot = {
|
|
201
|
+
data: nextData,
|
|
202
|
+
isMissingData: nextSnapshot.isMissingData,
|
|
203
|
+
seenRecords: nextSnapshot.seenRecords,
|
|
204
|
+
selector: nextSnapshot.selector,
|
|
205
|
+
missingRequiredFields: nextSnapshot.missingRequiredFields
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
if (process.env.NODE_ENV !== "production") {
|
|
209
|
+
deepFreeze(nextSnapshot);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
var prevSeenRecords = subscription.snapshot.seenRecords;
|
|
213
|
+
subscription.snapshot = nextSnapshot;
|
|
214
|
+
subscription.notifiedRevision = this._notifiedRevision;
|
|
215
|
+
|
|
216
|
+
this._updateSubscriptionsMap(subscription, prevSeenRecords);
|
|
217
|
+
|
|
218
|
+
if (nextSnapshot.data !== snapshot.data) {
|
|
219
|
+
callback(nextSnapshot);
|
|
220
|
+
return snapshot.selector.owner;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Updates the Map that tracks subscriptions by id.
|
|
225
|
+
* Given an updated subscription and the records that where seen
|
|
226
|
+
* on the previous subscription snapshot, updates our tracking
|
|
227
|
+
* to track the subscription for the newly and no longer seen ids.
|
|
228
|
+
*/
|
|
229
|
+
;
|
|
230
|
+
|
|
231
|
+
_proto._updateSubscriptionsMap = function _updateSubscriptionsMap(subscription, prevSeenRecords) {
|
|
232
|
+
for (var dataId in prevSeenRecords) {
|
|
233
|
+
var subscriptionsForDataId = this._subscriptionsByDataId.get(dataId);
|
|
234
|
+
|
|
235
|
+
if (subscriptionsForDataId != null) {
|
|
236
|
+
subscriptionsForDataId["delete"](subscription);
|
|
237
|
+
|
|
238
|
+
if (subscriptionsForDataId.size === 0) {
|
|
239
|
+
this._subscriptionsByDataId["delete"](dataId);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
for (var _dataId in subscription.snapshot.seenRecords) {
|
|
245
|
+
var _subscriptionsForDataId = this._subscriptionsByDataId.get(_dataId);
|
|
246
|
+
|
|
247
|
+
if (_subscriptionsForDataId != null) {
|
|
248
|
+
_subscriptionsForDataId.add(subscription);
|
|
249
|
+
} else {
|
|
250
|
+
this._subscriptionsByDataId.set(_dataId, new Set([subscription]));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
return RelayStoreSubscriptionsUsingMapByID;
|
|
256
|
+
}();
|
|
257
|
+
|
|
258
|
+
module.exports = RelayStoreSubscriptionsUsingMapByID;
|