relay-runtime 0.0.0-main-3064e18c → 0.0.0-main-84218519
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 +47 -12
- 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/RelayReader.js.flow +87 -12
- package/store/RelayStoreTypes.js.flow +2 -2
|
@@ -217,7 +217,7 @@ class RelayReader {
|
|
|
217
217
|
}
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
-
_markDataAsMissing(): void {
|
|
220
|
+
_markDataAsMissing(fieldName: string): void {
|
|
221
221
|
if (this._isWithinUnmatchedTypeRefinement) {
|
|
222
222
|
return;
|
|
223
223
|
}
|
|
@@ -226,7 +226,6 @@ class RelayReader {
|
|
|
226
226
|
}
|
|
227
227
|
|
|
228
228
|
// we will add the path later
|
|
229
|
-
const fieldPath = '';
|
|
230
229
|
const owner = this._fragmentName;
|
|
231
230
|
|
|
232
231
|
this._errorResponseFields.push(
|
|
@@ -234,10 +233,10 @@ class RelayReader {
|
|
|
234
233
|
? {
|
|
235
234
|
kind: 'missing_expected_data.throw',
|
|
236
235
|
owner,
|
|
237
|
-
fieldPath,
|
|
236
|
+
fieldPath: fieldName,
|
|
238
237
|
handled: false,
|
|
239
238
|
}
|
|
240
|
-
: {kind: 'missing_expected_data.log', owner, fieldPath},
|
|
239
|
+
: {kind: 'missing_expected_data.log', owner, fieldPath: fieldName},
|
|
241
240
|
);
|
|
242
241
|
|
|
243
242
|
this._isMissingData = true;
|
|
@@ -266,7 +265,7 @@ class RelayReader {
|
|
|
266
265
|
this._seenRecords.add(dataID);
|
|
267
266
|
if (record == null) {
|
|
268
267
|
if (record === undefined) {
|
|
269
|
-
this._markDataAsMissing();
|
|
268
|
+
this._markDataAsMissing('<record>');
|
|
270
269
|
}
|
|
271
270
|
return record;
|
|
272
271
|
}
|
|
@@ -489,12 +488,15 @@ class RelayReader {
|
|
|
489
488
|
this._createFragmentPointer(selection, record, data);
|
|
490
489
|
break;
|
|
491
490
|
case 'AliasedInlineFragmentSpread': {
|
|
491
|
+
const prevErrors = this._errorResponseFields;
|
|
492
|
+
this._errorResponseFields = null;
|
|
492
493
|
let fieldValue = this._readInlineFragment(
|
|
493
494
|
selection.fragment,
|
|
494
495
|
record,
|
|
495
496
|
{},
|
|
496
497
|
true,
|
|
497
498
|
);
|
|
499
|
+
this._prependPreviousErrors(prevErrors, selection.name);
|
|
498
500
|
if (fieldValue === false) {
|
|
499
501
|
fieldValue = null;
|
|
500
502
|
}
|
|
@@ -601,9 +603,12 @@ class RelayReader {
|
|
|
601
603
|
data: SelectorData,
|
|
602
604
|
): mixed {
|
|
603
605
|
const parentRecordID = RelayModernRecord.getDataID(record);
|
|
606
|
+
const prevErrors = this._errorResponseFields;
|
|
607
|
+
this._errorResponseFields = null;
|
|
604
608
|
const result = this._readResolverFieldImpl(field, parentRecordID);
|
|
605
609
|
|
|
606
610
|
const fieldName = field.alias ?? field.name;
|
|
611
|
+
this._prependPreviousErrors(prevErrors, fieldName);
|
|
607
612
|
data[fieldName] = result;
|
|
608
613
|
return result;
|
|
609
614
|
}
|
|
@@ -982,12 +987,15 @@ class RelayReader {
|
|
|
982
987
|
RelayModernRecord.getDataID(record),
|
|
983
988
|
prevData,
|
|
984
989
|
);
|
|
990
|
+
const prevErrors = this._errorResponseFields;
|
|
991
|
+
this._errorResponseFields = null;
|
|
985
992
|
const edgeValue = this._traverse(
|
|
986
993
|
field.linkedField,
|
|
987
994
|
storeID,
|
|
988
995
|
// $FlowFixMe[incompatible-variance]
|
|
989
996
|
prevData,
|
|
990
997
|
);
|
|
998
|
+
this._prependPreviousErrors(prevErrors, fieldName);
|
|
991
999
|
this._clientEdgeTraversalPath.pop();
|
|
992
1000
|
data[fieldName] = edgeValue;
|
|
993
1001
|
return edgeValue;
|
|
@@ -1005,7 +1013,7 @@ class RelayReader {
|
|
|
1005
1013
|
if (value === null) {
|
|
1006
1014
|
this._maybeAddErrorResponseFields(record, storageKey);
|
|
1007
1015
|
} else if (value === undefined) {
|
|
1008
|
-
this._markDataAsMissing();
|
|
1016
|
+
this._markDataAsMissing(fieldName);
|
|
1009
1017
|
}
|
|
1010
1018
|
data[fieldName] = value;
|
|
1011
1019
|
return value;
|
|
@@ -1024,7 +1032,7 @@ class RelayReader {
|
|
|
1024
1032
|
if (linkedID === null) {
|
|
1025
1033
|
this._maybeAddErrorResponseFields(record, storageKey);
|
|
1026
1034
|
} else if (linkedID === undefined) {
|
|
1027
|
-
this._markDataAsMissing();
|
|
1035
|
+
this._markDataAsMissing(fieldName);
|
|
1028
1036
|
}
|
|
1029
1037
|
return linkedID;
|
|
1030
1038
|
}
|
|
@@ -1039,12 +1047,73 @@ class RelayReader {
|
|
|
1039
1047
|
RelayModernRecord.getDataID(record),
|
|
1040
1048
|
prevData,
|
|
1041
1049
|
);
|
|
1050
|
+
const prevErrors = this._errorResponseFields;
|
|
1051
|
+
this._errorResponseFields = null;
|
|
1042
1052
|
// $FlowFixMe[incompatible-variance]
|
|
1043
1053
|
const value = this._traverse(field, linkedID, prevData);
|
|
1054
|
+
|
|
1055
|
+
this._prependPreviousErrors(prevErrors, fieldName);
|
|
1044
1056
|
data[fieldName] = value;
|
|
1045
1057
|
return value;
|
|
1046
1058
|
}
|
|
1047
1059
|
|
|
1060
|
+
/**
|
|
1061
|
+
* Adds a set of field errors to `this._errorResponseFields`, ensuring the
|
|
1062
|
+
* `fieldPath` property of existing field errors are prefixed with the given
|
|
1063
|
+
* `fieldNameOrIndex`.
|
|
1064
|
+
*
|
|
1065
|
+
* In order to make field errors maximally useful in logs/errors, we want to
|
|
1066
|
+
* include the path to the field that caused the error. A naive approach would
|
|
1067
|
+
* be to maintain a path property on RelayReader which we push/pop field names
|
|
1068
|
+
* to as we traverse into fields/etc. However, this would be expensive to
|
|
1069
|
+
* maintain, and in the common case where there are no field errors, the work
|
|
1070
|
+
* would go unused.
|
|
1071
|
+
*
|
|
1072
|
+
* Instead, we take a lazy approach where as we exit the recurison into a
|
|
1073
|
+
* field/etc we prepend any errors encountered while traversing that field
|
|
1074
|
+
* with the field name. This is somewhat more expensive in the error case, but
|
|
1075
|
+
* ~free in the common case where there are no errors.
|
|
1076
|
+
*
|
|
1077
|
+
* To achieve this, named field readers must do the following to correctly
|
|
1078
|
+
* track error filePaths:
|
|
1079
|
+
*
|
|
1080
|
+
* 1. Stash the value of `this._errorResponseFields` in a local variable
|
|
1081
|
+
* 2. Set `this._errorResponseFields` to `null`
|
|
1082
|
+
* 3. Traverse into the field
|
|
1083
|
+
* 4. Call this method with the stashed errors and the field's name
|
|
1084
|
+
*
|
|
1085
|
+
* Similarly, when creating field errors, we simply initialize the `fieldPath`
|
|
1086
|
+
* as the direct field name.
|
|
1087
|
+
*
|
|
1088
|
+
* Today we only use this apporach for `missing_expected_data` errors, but we
|
|
1089
|
+
* intend to broaden it to handle all field error paths.
|
|
1090
|
+
*/
|
|
1091
|
+
_prependPreviousErrors(
|
|
1092
|
+
prevErrors: ?Array<ErrorResponseField>,
|
|
1093
|
+
fieldNameOrIndex: string | number,
|
|
1094
|
+
): void {
|
|
1095
|
+
if (this._errorResponseFields != null) {
|
|
1096
|
+
for (let i = 0; i < this._errorResponseFields.length; i++) {
|
|
1097
|
+
const event = this._errorResponseFields[i];
|
|
1098
|
+
if (
|
|
1099
|
+
event.owner === this._fragmentName &&
|
|
1100
|
+
(event.kind === 'missing_expected_data.throw' ||
|
|
1101
|
+
event.kind === 'missing_expected_data.log')
|
|
1102
|
+
) {
|
|
1103
|
+
event.fieldPath = `${fieldNameOrIndex}.${event.fieldPath}`;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
if (prevErrors != null) {
|
|
1107
|
+
for (let i = this._errorResponseFields.length - 1; i >= 0; i--) {
|
|
1108
|
+
prevErrors.push(this._errorResponseFields[i]);
|
|
1109
|
+
}
|
|
1110
|
+
this._errorResponseFields = prevErrors;
|
|
1111
|
+
}
|
|
1112
|
+
} else {
|
|
1113
|
+
this._errorResponseFields = prevErrors;
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1048
1117
|
_readActorChange(
|
|
1049
1118
|
field: ReaderActorChange,
|
|
1050
1119
|
record: Record,
|
|
@@ -1060,7 +1129,7 @@ class RelayReader {
|
|
|
1060
1129
|
if (externalRef == null) {
|
|
1061
1130
|
data[fieldName] = externalRef;
|
|
1062
1131
|
if (externalRef === undefined) {
|
|
1063
|
-
this._markDataAsMissing();
|
|
1132
|
+
this._markDataAsMissing(fieldName);
|
|
1064
1133
|
} else if (externalRef === null) {
|
|
1065
1134
|
this._maybeAddErrorResponseFields(record, storageKey);
|
|
1066
1135
|
}
|
|
@@ -1107,7 +1176,7 @@ class RelayReader {
|
|
|
1107
1176
|
if (linkedIDs == null) {
|
|
1108
1177
|
data[fieldName] = linkedIDs;
|
|
1109
1178
|
if (linkedIDs === undefined) {
|
|
1110
|
-
this._markDataAsMissing();
|
|
1179
|
+
this._markDataAsMissing(fieldName);
|
|
1111
1180
|
}
|
|
1112
1181
|
return linkedIDs;
|
|
1113
1182
|
}
|
|
@@ -1121,11 +1190,13 @@ class RelayReader {
|
|
|
1121
1190
|
RelayModernRecord.getDataID(record),
|
|
1122
1191
|
prevData,
|
|
1123
1192
|
);
|
|
1193
|
+
const prevErrors = this._errorResponseFields;
|
|
1194
|
+
this._errorResponseFields = null;
|
|
1124
1195
|
const linkedArray = prevData || [];
|
|
1125
1196
|
linkedIDs.forEach((linkedID, nextIndex) => {
|
|
1126
1197
|
if (linkedID == null) {
|
|
1127
1198
|
if (linkedID === undefined) {
|
|
1128
|
-
this._markDataAsMissing();
|
|
1199
|
+
this._markDataAsMissing(String(nextIndex));
|
|
1129
1200
|
}
|
|
1130
1201
|
// $FlowFixMe[cannot-write]
|
|
1131
1202
|
linkedArray[nextIndex] = linkedID;
|
|
@@ -1140,10 +1211,14 @@ class RelayReader {
|
|
|
1140
1211
|
RelayModernRecord.getDataID(record),
|
|
1141
1212
|
prevItem,
|
|
1142
1213
|
);
|
|
1214
|
+
const prevErrors = this._errorResponseFields;
|
|
1215
|
+
this._errorResponseFields = null;
|
|
1143
1216
|
// $FlowFixMe[cannot-write]
|
|
1144
1217
|
// $FlowFixMe[incompatible-variance]
|
|
1145
1218
|
linkedArray[nextIndex] = this._traverse(field, linkedID, prevItem);
|
|
1219
|
+
this._prependPreviousErrors(prevErrors, nextIndex);
|
|
1146
1220
|
});
|
|
1221
|
+
this._prependPreviousErrors(prevErrors, fieldName);
|
|
1147
1222
|
data[fieldName] = linkedArray;
|
|
1148
1223
|
return linkedArray;
|
|
1149
1224
|
}
|
|
@@ -1166,7 +1241,7 @@ class RelayReader {
|
|
|
1166
1241
|
RelayModernRecord.getValue(record, componentKey);
|
|
1167
1242
|
if (component == null) {
|
|
1168
1243
|
if (component === undefined) {
|
|
1169
|
-
this._markDataAsMissing();
|
|
1244
|
+
this._markDataAsMissing('<module-import>');
|
|
1170
1245
|
}
|
|
1171
1246
|
return;
|
|
1172
1247
|
}
|
|
@@ -1398,7 +1473,7 @@ class RelayReader {
|
|
|
1398
1473
|
// fetched the `__is[AbstractType]` flag for this concrete type. In this
|
|
1399
1474
|
// case we need to report that we are missing data, in case that field is
|
|
1400
1475
|
// still in flight.
|
|
1401
|
-
this._markDataAsMissing();
|
|
1476
|
+
this._markDataAsMissing('<abstract-type-hint>');
|
|
1402
1477
|
}
|
|
1403
1478
|
// $FlowFixMe Casting record value
|
|
1404
1479
|
return implementsInterface;
|
|
@@ -1274,7 +1274,7 @@ export type MissingFieldHandler =
|
|
|
1274
1274
|
export type MissingExpectedDataLogEvent = {
|
|
1275
1275
|
+kind: 'missing_expected_data.log',
|
|
1276
1276
|
+owner: string,
|
|
1277
|
-
|
|
1277
|
+
fieldPath: string, // Purposefully mutable to allow lazy construction in RelayReader
|
|
1278
1278
|
};
|
|
1279
1279
|
|
|
1280
1280
|
/**
|
|
@@ -1300,7 +1300,7 @@ export type MissingExpectedDataLogEvent = {
|
|
|
1300
1300
|
export type MissingExpectedDataThrowEvent = {
|
|
1301
1301
|
+kind: 'missing_expected_data.throw',
|
|
1302
1302
|
+owner: string,
|
|
1303
|
-
|
|
1303
|
+
fieldPath: string, // Purposefully mutable to allow lazy construction in RelayReader
|
|
1304
1304
|
+handled: boolean,
|
|
1305
1305
|
};
|
|
1306
1306
|
|