relay-runtime 0.0.0-main-f16f5613 → 0.0.0-main-df676950
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/experimental.js +1 -1
- package/index.js +1 -1
- package/lib/store/RelayReader.js +32 -32
- package/lib/store/ResolverCache.js +7 -0
- package/lib/store/experimental-live-resolvers/LiveResolverCache.js +7 -0
- package/lib/util/RelayFeatureFlags.js +2 -1
- package/package.json +1 -1
- package/relay-runtime-experimental.js +1 -1
- package/relay-runtime-experimental.min.js +1 -1
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +2 -2
- package/store/RelayErrorTrie.js.flow +1 -0
- package/store/RelayPublishQueue.js.flow +1 -0
- package/store/RelayReader.js.flow +34 -34
- package/store/ResolverCache.js.flow +17 -0
- package/store/experimental-live-resolvers/LiveResolverCache.js.flow +17 -0
- package/util/RelayFeatureFlags.js.flow +4 -0
|
@@ -210,6 +210,7 @@ class RelayPublishQueue implements PublishQueue {
|
|
|
210
210
|
sourceOperation?: OperationDescriptor,
|
|
211
211
|
): $ReadOnlyArray<RequestDescriptor> {
|
|
212
212
|
const runWillClearGcHold =
|
|
213
|
+
// $FlowFixMe[incompatible-type]
|
|
213
214
|
this._appliedOptimisticUpdates === 0 && !!this._gcHold;
|
|
214
215
|
const runIsANoop =
|
|
215
216
|
// this._pendingBackupRebase is true if an applied optimistic
|
|
@@ -353,12 +353,12 @@ class RelayReader {
|
|
|
353
353
|
) {
|
|
354
354
|
const {to} = selection;
|
|
355
355
|
const field = selection.field?.backingField ?? selection.field;
|
|
356
|
-
const
|
|
356
|
+
const fieldName = field?.alias ?? field?.name;
|
|
357
357
|
|
|
358
358
|
// ReaderClientExtension doesn't have `alias` or `name`
|
|
359
359
|
// so we don't support this yet
|
|
360
360
|
invariant(
|
|
361
|
-
|
|
361
|
+
fieldName != null,
|
|
362
362
|
"Couldn't determine field name for this field. It might be a ReaderClientExtension - which is not yet supported.",
|
|
363
363
|
);
|
|
364
364
|
|
|
@@ -399,14 +399,14 @@ class RelayReader {
|
|
|
399
399
|
if (this._errorResponseFields != null) {
|
|
400
400
|
const errors = this._errorResponseFields.map(error => error.error);
|
|
401
401
|
|
|
402
|
-
data[
|
|
402
|
+
data[fieldName] = {
|
|
403
403
|
ok: false,
|
|
404
404
|
errors,
|
|
405
405
|
};
|
|
406
406
|
return;
|
|
407
407
|
}
|
|
408
408
|
|
|
409
|
-
data[
|
|
409
|
+
data[fieldName] = {
|
|
410
410
|
ok: true,
|
|
411
411
|
value,
|
|
412
412
|
};
|
|
@@ -662,8 +662,8 @@ class RelayReader {
|
|
|
662
662
|
const parentRecordID = RelayModernRecord.getDataID(record);
|
|
663
663
|
const result = this._readResolverFieldImpl(field, parentRecordID);
|
|
664
664
|
|
|
665
|
-
const
|
|
666
|
-
data[
|
|
665
|
+
const fieldName = field.alias ?? field.name;
|
|
666
|
+
data[fieldName] = result;
|
|
667
667
|
return result;
|
|
668
668
|
}
|
|
669
669
|
|
|
@@ -856,24 +856,24 @@ class RelayReader {
|
|
|
856
856
|
const backingField = field.backingField;
|
|
857
857
|
|
|
858
858
|
// Because ReaderClientExtension doesn't have `alias` or `name` and so I don't know
|
|
859
|
-
// how to get its
|
|
859
|
+
// how to get its fieldName or storageKey yet:
|
|
860
860
|
invariant(
|
|
861
861
|
backingField.kind !== 'ClientExtension',
|
|
862
862
|
'Client extension client edges are not yet implemented.',
|
|
863
863
|
);
|
|
864
864
|
|
|
865
|
-
const
|
|
865
|
+
const fieldName = backingField.alias ?? backingField.name;
|
|
866
866
|
const backingFieldData = {};
|
|
867
867
|
this._traverseSelections([backingField], record, backingFieldData);
|
|
868
|
-
// At this point, backingFieldData is an object with a single key (
|
|
868
|
+
// At this point, backingFieldData is an object with a single key (fieldName)
|
|
869
869
|
// whose value is the value returned from the resolver, or a suspense sentinel.
|
|
870
870
|
|
|
871
|
-
const clientEdgeResolverResponse = backingFieldData[
|
|
871
|
+
const clientEdgeResolverResponse = backingFieldData[fieldName];
|
|
872
872
|
if (
|
|
873
873
|
clientEdgeResolverResponse == null ||
|
|
874
874
|
isSuspenseSentinel(clientEdgeResolverResponse)
|
|
875
875
|
) {
|
|
876
|
-
data[
|
|
876
|
+
data[fieldName] = clientEdgeResolverResponse;
|
|
877
877
|
return clientEdgeResolverResponse;
|
|
878
878
|
}
|
|
879
879
|
|
|
@@ -925,7 +925,7 @@ class RelayReader {
|
|
|
925
925
|
data,
|
|
926
926
|
);
|
|
927
927
|
this._clientEdgeTraversalPath.pop();
|
|
928
|
-
data[
|
|
928
|
+
data[fieldName] = edgeValues;
|
|
929
929
|
return edgeValues;
|
|
930
930
|
} else {
|
|
931
931
|
const id = extractIdFromResponse(clientEdgeResolverResponse);
|
|
@@ -970,18 +970,18 @@ class RelayReader {
|
|
|
970
970
|
if (model == null) {
|
|
971
971
|
// If the model resolver returns undefined, we should still return null
|
|
972
972
|
// to match GQL behavior.
|
|
973
|
-
data[
|
|
973
|
+
data[fieldName] = null;
|
|
974
974
|
return null;
|
|
975
975
|
}
|
|
976
976
|
}
|
|
977
977
|
this._clientEdgeTraversalPath.push(traversalPathSegment);
|
|
978
978
|
|
|
979
|
-
const prevData = data[
|
|
979
|
+
const prevData = data[fieldName];
|
|
980
980
|
invariant(
|
|
981
981
|
prevData == null || typeof prevData === 'object',
|
|
982
982
|
'RelayReader(): Expected data for field `%s` on record `%s` ' +
|
|
983
983
|
'to be an object, got `%s`.',
|
|
984
|
-
|
|
984
|
+
fieldName,
|
|
985
985
|
RelayModernRecord.getDataID(record),
|
|
986
986
|
prevData,
|
|
987
987
|
);
|
|
@@ -992,7 +992,7 @@ class RelayReader {
|
|
|
992
992
|
prevData,
|
|
993
993
|
);
|
|
994
994
|
this._clientEdgeTraversalPath.pop();
|
|
995
|
-
data[
|
|
995
|
+
data[fieldName] = edgeValue;
|
|
996
996
|
return edgeValue;
|
|
997
997
|
}
|
|
998
998
|
}
|
|
@@ -1002,7 +1002,7 @@ class RelayReader {
|
|
|
1002
1002
|
record: Record,
|
|
1003
1003
|
data: SelectorData,
|
|
1004
1004
|
): ?mixed {
|
|
1005
|
-
const
|
|
1005
|
+
const fieldName = field.alias ?? field.name;
|
|
1006
1006
|
const storageKey = getStorageKey(field, this._variables);
|
|
1007
1007
|
const value = RelayModernRecord.getValue(record, storageKey);
|
|
1008
1008
|
if (value === null) {
|
|
@@ -1010,7 +1010,7 @@ class RelayReader {
|
|
|
1010
1010
|
} else if (value === undefined) {
|
|
1011
1011
|
this._markDataAsMissing();
|
|
1012
1012
|
}
|
|
1013
|
-
data[
|
|
1013
|
+
data[fieldName] = value;
|
|
1014
1014
|
return value;
|
|
1015
1015
|
}
|
|
1016
1016
|
|
|
@@ -1019,11 +1019,11 @@ class RelayReader {
|
|
|
1019
1019
|
record: Record,
|
|
1020
1020
|
data: SelectorData,
|
|
1021
1021
|
): ?mixed {
|
|
1022
|
-
const
|
|
1022
|
+
const fieldName = field.alias ?? field.name;
|
|
1023
1023
|
const storageKey = getStorageKey(field, this._variables);
|
|
1024
1024
|
const linkedID = RelayModernRecord.getLinkedRecordID(record, storageKey);
|
|
1025
1025
|
if (linkedID == null) {
|
|
1026
|
-
data[
|
|
1026
|
+
data[fieldName] = linkedID;
|
|
1027
1027
|
if (linkedID === null) {
|
|
1028
1028
|
this._maybeAddErrorResponseFields(record, storageKey);
|
|
1029
1029
|
} else if (linkedID === undefined) {
|
|
@@ -1032,18 +1032,18 @@ class RelayReader {
|
|
|
1032
1032
|
return linkedID;
|
|
1033
1033
|
}
|
|
1034
1034
|
|
|
1035
|
-
const prevData = data[
|
|
1035
|
+
const prevData = data[fieldName];
|
|
1036
1036
|
invariant(
|
|
1037
1037
|
prevData == null || typeof prevData === 'object',
|
|
1038
1038
|
'RelayReader(): Expected data for field `%s` on record `%s` ' +
|
|
1039
1039
|
'to be an object, got `%s`.',
|
|
1040
|
-
|
|
1040
|
+
fieldName,
|
|
1041
1041
|
RelayModernRecord.getDataID(record),
|
|
1042
1042
|
prevData,
|
|
1043
1043
|
);
|
|
1044
1044
|
// $FlowFixMe[incompatible-variance]
|
|
1045
1045
|
const value = this._traverse(field, linkedID, prevData);
|
|
1046
|
-
data[
|
|
1046
|
+
data[fieldName] = value;
|
|
1047
1047
|
return value;
|
|
1048
1048
|
}
|
|
1049
1049
|
|
|
@@ -1052,7 +1052,7 @@ class RelayReader {
|
|
|
1052
1052
|
record: Record,
|
|
1053
1053
|
data: SelectorData,
|
|
1054
1054
|
): ?mixed {
|
|
1055
|
-
const
|
|
1055
|
+
const fieldName = field.alias ?? field.name;
|
|
1056
1056
|
const storageKey = getStorageKey(field, this._variables);
|
|
1057
1057
|
const externalRef = RelayModernRecord.getActorLinkedRecordID(
|
|
1058
1058
|
record,
|
|
@@ -1060,13 +1060,13 @@ class RelayReader {
|
|
|
1060
1060
|
);
|
|
1061
1061
|
|
|
1062
1062
|
if (externalRef == null) {
|
|
1063
|
-
data[
|
|
1063
|
+
data[fieldName] = externalRef;
|
|
1064
1064
|
if (externalRef === undefined) {
|
|
1065
1065
|
this._markDataAsMissing();
|
|
1066
1066
|
} else if (externalRef === null) {
|
|
1067
1067
|
this._maybeAddErrorResponseFields(record, storageKey);
|
|
1068
1068
|
}
|
|
1069
|
-
return data[
|
|
1069
|
+
return data[fieldName];
|
|
1070
1070
|
}
|
|
1071
1071
|
const [actorIdentifier, dataID] = externalRef;
|
|
1072
1072
|
|
|
@@ -1078,11 +1078,11 @@ class RelayReader {
|
|
|
1078
1078
|
}),
|
|
1079
1079
|
fragmentRef,
|
|
1080
1080
|
);
|
|
1081
|
-
data[
|
|
1081
|
+
data[fieldName] = {
|
|
1082
1082
|
__fragmentRef: fragmentRef,
|
|
1083
1083
|
__viewer: actorIdentifier,
|
|
1084
1084
|
};
|
|
1085
|
-
return data[
|
|
1085
|
+
return data[fieldName];
|
|
1086
1086
|
}
|
|
1087
1087
|
|
|
1088
1088
|
_readPluralLink(
|
|
@@ -1104,22 +1104,22 @@ class RelayReader {
|
|
|
1104
1104
|
record: Record,
|
|
1105
1105
|
data: SelectorData,
|
|
1106
1106
|
): ?mixed {
|
|
1107
|
-
const
|
|
1107
|
+
const fieldName = field.alias ?? field.name;
|
|
1108
1108
|
|
|
1109
1109
|
if (linkedIDs == null) {
|
|
1110
|
-
data[
|
|
1110
|
+
data[fieldName] = linkedIDs;
|
|
1111
1111
|
if (linkedIDs === undefined) {
|
|
1112
1112
|
this._markDataAsMissing();
|
|
1113
1113
|
}
|
|
1114
1114
|
return linkedIDs;
|
|
1115
1115
|
}
|
|
1116
1116
|
|
|
1117
|
-
const prevData = data[
|
|
1117
|
+
const prevData = data[fieldName];
|
|
1118
1118
|
invariant(
|
|
1119
1119
|
prevData == null || Array.isArray(prevData),
|
|
1120
1120
|
'RelayReader(): Expected data for field `%s` on record `%s` ' +
|
|
1121
1121
|
'to be an array, got `%s`.',
|
|
1122
|
-
|
|
1122
|
+
fieldName,
|
|
1123
1123
|
RelayModernRecord.getDataID(record),
|
|
1124
1124
|
prevData,
|
|
1125
1125
|
);
|
|
@@ -1138,7 +1138,7 @@ class RelayReader {
|
|
|
1138
1138
|
prevItem == null || typeof prevItem === 'object',
|
|
1139
1139
|
'RelayReader(): Expected data for field `%s` on record `%s` ' +
|
|
1140
1140
|
'to be an object, got `%s`.',
|
|
1141
|
-
|
|
1141
|
+
fieldName,
|
|
1142
1142
|
RelayModernRecord.getDataID(record),
|
|
1143
1143
|
prevItem,
|
|
1144
1144
|
);
|
|
@@ -1146,7 +1146,7 @@ class RelayReader {
|
|
|
1146
1146
|
// $FlowFixMe[incompatible-variance]
|
|
1147
1147
|
linkedArray[nextIndex] = this._traverse(field, linkedID, prevItem);
|
|
1148
1148
|
});
|
|
1149
|
-
data[
|
|
1149
|
+
data[fieldName] = linkedArray;
|
|
1150
1150
|
return linkedArray;
|
|
1151
1151
|
}
|
|
1152
1152
|
|
|
@@ -26,6 +26,7 @@ import type {
|
|
|
26
26
|
|
|
27
27
|
const recycleNodesInto = require('../util/recycleNodesInto');
|
|
28
28
|
const {RELAY_LIVE_RESOLVER} = require('../util/RelayConcreteNode');
|
|
29
|
+
const RelayFeatureFlags = require('../util/RelayFeatureFlags');
|
|
29
30
|
const shallowFreeze = require('../util/shallowFreeze');
|
|
30
31
|
const {generateClientID} = require('./ClientID');
|
|
31
32
|
const RelayModernRecord = require('./RelayModernRecord');
|
|
@@ -325,6 +326,22 @@ class RecordResolverCache implements ResolverCache {
|
|
|
325
326
|
if (recycled !== originalInputs) {
|
|
326
327
|
return true;
|
|
327
328
|
}
|
|
329
|
+
|
|
330
|
+
if (RelayFeatureFlags.MARK_RESOLVER_VALUES_AS_CLEAN_AFTER_FRAGMENT_REREAD) {
|
|
331
|
+
// This record does not need to be recomputed, we can reuse the cached value.
|
|
332
|
+
// For subsequent reads we can mark this record as "clean" so that they will
|
|
333
|
+
// not need to re-read the fragment.
|
|
334
|
+
const nextRecord = RelayModernRecord.clone(record);
|
|
335
|
+
RelayModernRecord.setValue(
|
|
336
|
+
nextRecord,
|
|
337
|
+
RELAY_RESOLVER_INVALIDATION_KEY,
|
|
338
|
+
false,
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
const recordSource = this._getRecordSource();
|
|
342
|
+
recordSource.set(RelayModernRecord.getDataID(record), nextRecord);
|
|
343
|
+
}
|
|
344
|
+
|
|
328
345
|
return false;
|
|
329
346
|
}
|
|
330
347
|
|
|
@@ -35,6 +35,7 @@ import type {LiveState} from 'relay-runtime';
|
|
|
35
35
|
|
|
36
36
|
const recycleNodesInto = require('../../util/recycleNodesInto');
|
|
37
37
|
const {RELAY_LIVE_RESOLVER} = require('../../util/RelayConcreteNode');
|
|
38
|
+
const RelayFeatureFlags = require('../../util/RelayFeatureFlags');
|
|
38
39
|
const shallowFreeze = require('../../util/shallowFreeze');
|
|
39
40
|
const {generateClientID, generateClientObjectClientID} = require('../ClientID');
|
|
40
41
|
const RelayModernRecord = require('../RelayModernRecord');
|
|
@@ -699,6 +700,22 @@ class LiveResolverCache implements ResolverCache {
|
|
|
699
700
|
if (recycled !== originalInputs) {
|
|
700
701
|
return true;
|
|
701
702
|
}
|
|
703
|
+
|
|
704
|
+
if (RelayFeatureFlags.MARK_RESOLVER_VALUES_AS_CLEAN_AFTER_FRAGMENT_REREAD) {
|
|
705
|
+
// This record does not need to be recomputed, we can reuse the cached value.
|
|
706
|
+
// For subsequent reads we can mark this record as "clean" so that they will
|
|
707
|
+
// not need to re-read the fragment.
|
|
708
|
+
const nextRecord = RelayModernRecord.clone(record);
|
|
709
|
+
RelayModernRecord.setValue(
|
|
710
|
+
nextRecord,
|
|
711
|
+
RELAY_RESOLVER_INVALIDATION_KEY,
|
|
712
|
+
false,
|
|
713
|
+
);
|
|
714
|
+
|
|
715
|
+
const recordSource = this._getRecordSource();
|
|
716
|
+
recordSource.set(RelayModernRecord.getDataID(record), nextRecord);
|
|
717
|
+
}
|
|
718
|
+
|
|
702
719
|
return false;
|
|
703
720
|
}
|
|
704
721
|
|
|
@@ -48,6 +48,9 @@ export type FeatureFlags = {
|
|
|
48
48
|
ENABLE_FIELD_ERROR_HANDLING_CATCH_DIRECTIVE: boolean,
|
|
49
49
|
|
|
50
50
|
PROCESS_OPTIMISTIC_UPDATE_BEFORE_SUBSCRIPTION: boolean,
|
|
51
|
+
|
|
52
|
+
// Temporary flag to enable a gradual rollout of the fix for T185969900
|
|
53
|
+
MARK_RESOLVER_VALUES_AS_CLEAN_AFTER_FRAGMENT_REREAD: boolean,
|
|
51
54
|
};
|
|
52
55
|
|
|
53
56
|
const RelayFeatureFlags: FeatureFlags = {
|
|
@@ -71,6 +74,7 @@ const RelayFeatureFlags: FeatureFlags = {
|
|
|
71
74
|
ENABLE_FIELD_ERROR_HANDLING_THROW_BY_DEFAULT: false,
|
|
72
75
|
ENABLE_FIELD_ERROR_HANDLING_CATCH_DIRECTIVE: false,
|
|
73
76
|
PROCESS_OPTIMISTIC_UPDATE_BEFORE_SUBSCRIPTION: false,
|
|
77
|
+
MARK_RESOLVER_VALUES_AS_CLEAN_AFTER_FRAGMENT_REREAD: false,
|
|
74
78
|
};
|
|
75
79
|
|
|
76
80
|
module.exports = RelayFeatureFlags;
|