relay-runtime 13.0.3 → 13.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +1 -1
- package/index.js.flow +4 -2
- package/lib/index.js +3 -3
- package/lib/mutations/readUpdatableQuery_EXPERIMENTAL.js +3 -4
- package/lib/query/GraphQLTag.js +13 -0
- package/lib/query/fetchQuery.js +2 -5
- package/lib/store/RelayModernEnvironment.js +3 -3
- package/lib/store/RelayModernFragmentSpecResolver.js +6 -6
- package/lib/store/RelayModernSelector.js +16 -2
- package/lib/store/RelayReader.js +71 -6
- package/lib/store/RelayStoreSubscriptions.js +4 -2
- package/lib/store/RelayStoreUtils.js +1 -0
- package/lib/store/ResolverCache.js +25 -13
- package/lib/store/experimental-live-resolvers/LiveResolverCache.js +316 -0
- package/lib/store/experimental-live-resolvers/LiveResolverStore.js +787 -0
- package/lib/store/hasOverlappingIDs.js +1 -1
- package/lib/util/RelayConcreteNode.js +2 -0
- package/lib/util/RelayFeatureFlags.js +0 -3
- package/lib/util/handlePotentialSnapshotErrors.js +73 -0
- package/mutations/RelayRecordSourceProxy.js.flow +7 -3
- package/mutations/RelayRecordSourceSelectorProxy.js.flow +7 -3
- package/mutations/readUpdatableQuery_EXPERIMENTAL.js.flow +14 -12
- package/network/RelayNetworkTypes.js.flow +1 -1
- package/package.json +1 -1
- package/query/GraphQLTag.js.flow +38 -3
- package/query/fetchQuery.js.flow +6 -4
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +2 -2
- package/store/RelayModernEnvironment.js.flow +3 -3
- package/store/RelayModernFragmentSpecResolver.js.flow +11 -7
- package/store/RelayModernSelector.js.flow +32 -8
- package/store/RelayReader.js.flow +65 -23
- package/store/RelayResponseNormalizer.js.flow +1 -1
- package/store/RelayStoreSubscriptions.js.flow +2 -0
- package/store/RelayStoreTypes.js.flow +22 -8
- package/store/RelayStoreUtils.js.flow +2 -1
- package/store/ResolverCache.js.flow +45 -10
- package/store/defaultGetDataID.js.flow +1 -1
- package/store/experimental-live-resolvers/LiveResolverCache.js.flow +410 -0
- package/store/experimental-live-resolvers/LiveResolverStore.js.flow +822 -0
- package/store/hasOverlappingIDs.js.flow +1 -1
- package/util/ReaderNode.js.flow +17 -1
- package/util/RelayConcreteNode.js.flow +9 -1
- package/util/RelayFeatureFlags.js.flow +0 -6
- package/util/RelayRuntimeTypes.js.flow +20 -1
- package/util/deepFreeze.js.flow +1 -1
- package/util/handlePotentialSnapshotErrors.js.flow +63 -0
- package/util/isEmptyObject.js.flow +1 -1
- package/lib/util/reportMissingRequiredFields.js +0 -48
- package/util/reportMissingRequiredFields.js.flow +0 -51
|
@@ -342,7 +342,7 @@ class RelayModernEnvironment implements IEnvironment {
|
|
|
342
342
|
|}): RelayObservable<GraphQLResponse> {
|
|
343
343
|
return this._execute({
|
|
344
344
|
createSource: () =>
|
|
345
|
-
this.
|
|
345
|
+
this.getNetwork().execute(
|
|
346
346
|
operation.request.node.params,
|
|
347
347
|
operation.request.variables,
|
|
348
348
|
operation.request.cacheConfig || {},
|
|
@@ -372,7 +372,7 @@ class RelayModernEnvironment implements IEnvironment {
|
|
|
372
372
|
|}): RelayObservable<GraphQLResponse> {
|
|
373
373
|
return this._execute({
|
|
374
374
|
createSource: () =>
|
|
375
|
-
this.
|
|
375
|
+
this.getNetwork().execute(
|
|
376
376
|
operation.request.node.params,
|
|
377
377
|
operation.request.variables,
|
|
378
378
|
operation.request.cacheConfig || {},
|
|
@@ -412,7 +412,7 @@ class RelayModernEnvironment implements IEnvironment {
|
|
|
412
412
|
}
|
|
413
413
|
return this._execute({
|
|
414
414
|
createSource: () =>
|
|
415
|
-
this.
|
|
415
|
+
this.getNetwork().execute(
|
|
416
416
|
operation.request.node.params,
|
|
417
417
|
operation.request.variables,
|
|
418
418
|
{
|
|
@@ -22,16 +22,17 @@ import type {
|
|
|
22
22
|
MissingRequiredFields,
|
|
23
23
|
PluralReaderSelector,
|
|
24
24
|
RelayContext,
|
|
25
|
+
RelayResolverErrors,
|
|
25
26
|
SelectorData,
|
|
26
27
|
SingularReaderSelector,
|
|
27
28
|
Snapshot,
|
|
28
29
|
} from './RelayStoreTypes';
|
|
29
30
|
|
|
30
31
|
const getPendingOperationsForFragment = require('../util/getPendingOperationsForFragment');
|
|
32
|
+
const handlePotentialSnapshotErrors = require('../util/handlePotentialSnapshotErrors');
|
|
31
33
|
const isScalarAndEqual = require('../util/isScalarAndEqual');
|
|
32
34
|
const recycleNodesInto = require('../util/recycleNodesInto');
|
|
33
35
|
const RelayFeatureFlags = require('../util/RelayFeatureFlags');
|
|
34
|
-
const reportMissingRequiredFields = require('../util/reportMissingRequiredFields');
|
|
35
36
|
const {createRequestDescriptor} = require('./RelayModernOperationDescriptor');
|
|
36
37
|
const {
|
|
37
38
|
areEqualSelectors,
|
|
@@ -228,6 +229,7 @@ class SelectorResolver {
|
|
|
228
229
|
_environment: IEnvironment;
|
|
229
230
|
_isMissingData: boolean;
|
|
230
231
|
_missingRequiredFields: ?MissingRequiredFields;
|
|
232
|
+
_relayResolverErrors: RelayResolverErrors;
|
|
231
233
|
_rootIsQueryRenderer: boolean;
|
|
232
234
|
_selector: SingularReaderSelector;
|
|
233
235
|
_subscription: ?Disposable;
|
|
@@ -244,6 +246,7 @@ class SelectorResolver {
|
|
|
244
246
|
this._data = snapshot.data;
|
|
245
247
|
this._isMissingData = snapshot.isMissingData;
|
|
246
248
|
this._missingRequiredFields = snapshot.missingRequiredFields;
|
|
249
|
+
this._relayResolverErrors = snapshot.relayResolverErrors;
|
|
247
250
|
this._environment = environment;
|
|
248
251
|
this._rootIsQueryRenderer = rootIsQueryRenderer;
|
|
249
252
|
this._selector = selector;
|
|
@@ -324,12 +327,11 @@ class SelectorResolver {
|
|
|
324
327
|
}
|
|
325
328
|
}
|
|
326
329
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
330
|
+
handlePotentialSnapshotErrors(
|
|
331
|
+
this._environment,
|
|
332
|
+
this._missingRequiredFields,
|
|
333
|
+
this._relayResolverErrors,
|
|
334
|
+
);
|
|
333
335
|
return this._data;
|
|
334
336
|
}
|
|
335
337
|
|
|
@@ -345,6 +347,7 @@ class SelectorResolver {
|
|
|
345
347
|
this._data = recycleNodesInto(this._data, snapshot.data);
|
|
346
348
|
this._isMissingData = snapshot.isMissingData;
|
|
347
349
|
this._missingRequiredFields = snapshot.missingRequiredFields;
|
|
350
|
+
this._relayResolverErrors = snapshot.relayResolverErrors;
|
|
348
351
|
this._selector = selector;
|
|
349
352
|
this._subscription = this._environment.subscribe(snapshot, this._onChange);
|
|
350
353
|
}
|
|
@@ -381,6 +384,7 @@ class SelectorResolver {
|
|
|
381
384
|
this._data = snapshot.data;
|
|
382
385
|
this._isMissingData = snapshot.isMissingData;
|
|
383
386
|
this._missingRequiredFields = snapshot.missingRequiredFields;
|
|
387
|
+
this._relayResolverErrors = snapshot.relayResolverErrors;
|
|
384
388
|
this._callback();
|
|
385
389
|
};
|
|
386
390
|
}
|
|
@@ -402,14 +402,7 @@ function getVariablesFromPluralFragment(
|
|
|
402
402
|
return variables;
|
|
403
403
|
}
|
|
404
404
|
|
|
405
|
-
|
|
406
|
-
* @public
|
|
407
|
-
*
|
|
408
|
-
* Determine if two selectors are equal (represent the same selection). Note
|
|
409
|
-
* that this function returns `false` when the two queries/fragments are
|
|
410
|
-
* different objects, even if they select the same fields.
|
|
411
|
-
*/
|
|
412
|
-
function areEqualSelectors(
|
|
405
|
+
function areEqualSingularSelectors(
|
|
413
406
|
thisSelector: SingularReaderSelector,
|
|
414
407
|
thatSelector: SingularReaderSelector,
|
|
415
408
|
): boolean {
|
|
@@ -421,6 +414,37 @@ function areEqualSelectors(
|
|
|
421
414
|
);
|
|
422
415
|
}
|
|
423
416
|
|
|
417
|
+
/**
|
|
418
|
+
* @public
|
|
419
|
+
*
|
|
420
|
+
* Determine if two selectors are equal (represent the same selection). Note
|
|
421
|
+
* that this function returns `false` when the two queries/fragments are
|
|
422
|
+
* different objects, even if they select the same fields.
|
|
423
|
+
*/
|
|
424
|
+
function areEqualSelectors(
|
|
425
|
+
a: ?(SingularReaderSelector | PluralReaderSelector),
|
|
426
|
+
b: ?(SingularReaderSelector | PluralReaderSelector),
|
|
427
|
+
): boolean {
|
|
428
|
+
if (
|
|
429
|
+
a?.kind === 'SingularReaderSelector' &&
|
|
430
|
+
b?.kind === 'SingularReaderSelector'
|
|
431
|
+
) {
|
|
432
|
+
return areEqualSingularSelectors(a, b);
|
|
433
|
+
} else if (
|
|
434
|
+
a?.kind === 'PluralReaderSelector' &&
|
|
435
|
+
b?.kind === 'PluralReaderSelector'
|
|
436
|
+
) {
|
|
437
|
+
return (
|
|
438
|
+
a.selectors.length === b.selectors.length &&
|
|
439
|
+
a.selectors.every((s, i) => areEqualSingularSelectors(s, b.selectors[i]))
|
|
440
|
+
);
|
|
441
|
+
} else if (a == null && b == null) {
|
|
442
|
+
return true;
|
|
443
|
+
} else {
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
424
448
|
function createReaderSelector(
|
|
425
449
|
fragment: ReaderFragment,
|
|
426
450
|
dataID: DataID,
|
|
@@ -22,6 +22,7 @@ import type {
|
|
|
22
22
|
ReaderLinkedField,
|
|
23
23
|
ReaderModuleImport,
|
|
24
24
|
ReaderNode,
|
|
25
|
+
ReaderRelayLiveResolver,
|
|
25
26
|
ReaderRelayResolver,
|
|
26
27
|
ReaderRequiredField,
|
|
27
28
|
ReaderScalarField,
|
|
@@ -35,6 +36,7 @@ import type {
|
|
|
35
36
|
MissingRequiredFields,
|
|
36
37
|
Record,
|
|
37
38
|
RecordSource,
|
|
39
|
+
RelayResolverErrors,
|
|
38
40
|
RequestDescriptor,
|
|
39
41
|
SelectorData,
|
|
40
42
|
SingularReaderSelector,
|
|
@@ -54,6 +56,7 @@ const {
|
|
|
54
56
|
INLINE_FRAGMENT,
|
|
55
57
|
LINKED_FIELD,
|
|
56
58
|
MODULE_IMPORT,
|
|
59
|
+
RELAY_LIVE_RESOLVER,
|
|
57
60
|
RELAY_RESOLVER,
|
|
58
61
|
REQUIRED_FIELD,
|
|
59
62
|
SCALAR_FIELD,
|
|
@@ -109,6 +112,7 @@ class RelayReader {
|
|
|
109
112
|
_selector: SingularReaderSelector;
|
|
110
113
|
_variables: Variables;
|
|
111
114
|
_resolverCache: ResolverCache;
|
|
115
|
+
_resolverErrors: RelayResolverErrors;
|
|
112
116
|
_fragmentName: string;
|
|
113
117
|
|
|
114
118
|
constructor(
|
|
@@ -131,6 +135,7 @@ class RelayReader {
|
|
|
131
135
|
this._selector = selector;
|
|
132
136
|
this._variables = selector.variables;
|
|
133
137
|
this._resolverCache = resolverCache;
|
|
138
|
+
this._resolverErrors = [];
|
|
134
139
|
this._fragmentName = selector.node.name;
|
|
135
140
|
}
|
|
136
141
|
|
|
@@ -204,6 +209,7 @@ class RelayReader {
|
|
|
204
209
|
seenRecords: this._seenRecords,
|
|
205
210
|
selector: this._selector,
|
|
206
211
|
missingRequiredFields: this._missingRequiredFields,
|
|
212
|
+
relayResolverErrors: this._resolverErrors,
|
|
207
213
|
};
|
|
208
214
|
}
|
|
209
215
|
|
|
@@ -391,6 +397,13 @@ class RelayReader {
|
|
|
391
397
|
}
|
|
392
398
|
break;
|
|
393
399
|
}
|
|
400
|
+
case RELAY_LIVE_RESOLVER: {
|
|
401
|
+
if (!RelayFeatureFlags.ENABLE_RELAY_RESOLVERS) {
|
|
402
|
+
throw new Error('Relay Resolver fields are not yet supported.');
|
|
403
|
+
}
|
|
404
|
+
this._readResolverField(selection, record, data);
|
|
405
|
+
break;
|
|
406
|
+
}
|
|
394
407
|
case RELAY_RESOLVER: {
|
|
395
408
|
if (!RelayFeatureFlags.ENABLE_RELAY_RESOLVERS) {
|
|
396
409
|
throw new Error('Relay Resolver fields are not yet supported.');
|
|
@@ -496,6 +509,11 @@ class RelayReader {
|
|
|
496
509
|
throw new Error('Relay Resolver fields are not yet supported.');
|
|
497
510
|
}
|
|
498
511
|
return this._readResolverField(selection.field, record, data);
|
|
512
|
+
case RELAY_LIVE_RESOLVER:
|
|
513
|
+
if (!RelayFeatureFlags.ENABLE_RELAY_RESOLVERS) {
|
|
514
|
+
throw new Error('Relay Resolver fields are not yet supported.');
|
|
515
|
+
}
|
|
516
|
+
return this._readResolverField(selection.field, record, data);
|
|
499
517
|
default:
|
|
500
518
|
(selection.field.kind: empty);
|
|
501
519
|
invariant(
|
|
@@ -507,7 +525,7 @@ class RelayReader {
|
|
|
507
525
|
}
|
|
508
526
|
|
|
509
527
|
_readResolverField(
|
|
510
|
-
field: ReaderRelayResolver,
|
|
528
|
+
field: ReaderRelayResolver | ReaderRelayLiveResolver,
|
|
511
529
|
record: Record,
|
|
512
530
|
data: SelectorData,
|
|
513
531
|
): mixed {
|
|
@@ -525,6 +543,9 @@ class RelayReader {
|
|
|
525
543
|
let fragmentReaderSelector;
|
|
526
544
|
let fragmentMissingRequiredFields: ?MissingRequiredFields;
|
|
527
545
|
let previousMissingRequriedFields: ?MissingRequiredFields;
|
|
546
|
+
|
|
547
|
+
let currentResolverErrors: RelayResolverErrors;
|
|
548
|
+
let previousResolverErrors: RelayResolverErrors;
|
|
528
549
|
const fragmentSeenRecordIDs = new Set();
|
|
529
550
|
|
|
530
551
|
const getDataForResolverFragment = singularReaderSelector => {
|
|
@@ -541,12 +562,16 @@ class RelayReader {
|
|
|
541
562
|
const resolverFragmentData = {};
|
|
542
563
|
previousMissingRequriedFields = this._missingRequiredFields;
|
|
543
564
|
this._missingRequiredFields = null;
|
|
565
|
+
|
|
566
|
+
previousResolverErrors = this._resolverErrors;
|
|
567
|
+
this._resolverErrors = [];
|
|
544
568
|
this._createInlineDataOrResolverFragmentPointer(
|
|
545
569
|
singularReaderSelector.node,
|
|
546
570
|
record,
|
|
547
571
|
resolverFragmentData,
|
|
548
572
|
);
|
|
549
573
|
fragmentMissingRequiredFields = this._missingRequiredFields;
|
|
574
|
+
currentResolverErrors = this._resolverErrors;
|
|
550
575
|
fragmentValue = resolverFragmentData[FRAGMENTS_KEY]?.[fragment.name];
|
|
551
576
|
invariant(
|
|
552
577
|
typeof fragmentValue === 'object' && fragmentValue !== null,
|
|
@@ -556,39 +581,56 @@ class RelayReader {
|
|
|
556
581
|
} finally {
|
|
557
582
|
this._seenRecords = existingSeenRecords;
|
|
558
583
|
this._missingRequiredFields = previousMissingRequriedFields;
|
|
584
|
+
this._resolverErrors = previousResolverErrors;
|
|
559
585
|
}
|
|
560
586
|
};
|
|
561
587
|
const resolverContext = {getDataForResolverFragment};
|
|
562
588
|
|
|
563
|
-
const
|
|
589
|
+
const evaluate = () => {
|
|
590
|
+
const key = {
|
|
591
|
+
__id: RelayModernRecord.getDataID(record),
|
|
592
|
+
__fragmentOwner: this._owner,
|
|
593
|
+
__fragments: {
|
|
594
|
+
[fragment.name]: {}, // Arguments to this fragment; not yet supported.
|
|
595
|
+
},
|
|
596
|
+
};
|
|
597
|
+
return withResolverContext(resolverContext, () => {
|
|
598
|
+
let resolverResult = null;
|
|
599
|
+
try {
|
|
600
|
+
// $FlowFixMe[prop-missing] - resolver module's type signature is a lie
|
|
601
|
+
resolverResult = resolverModule(key);
|
|
602
|
+
} catch (e) {
|
|
603
|
+
// `field.path` is typed as nullable while we rollout compiler changes.
|
|
604
|
+
const path = field.path ?? '[UNKNOWN]';
|
|
605
|
+
currentResolverErrors.push({
|
|
606
|
+
field: {path, owner: this._fragmentName},
|
|
607
|
+
error: e,
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
return {
|
|
611
|
+
resolverResult,
|
|
612
|
+
errors: currentResolverErrors,
|
|
613
|
+
fragmentValue,
|
|
614
|
+
resolverID,
|
|
615
|
+
seenRecordIDs: fragmentSeenRecordIDs,
|
|
616
|
+
readerSelector: fragmentReaderSelector,
|
|
617
|
+
missingRequiredFields: fragmentMissingRequiredFields,
|
|
618
|
+
};
|
|
619
|
+
});
|
|
620
|
+
};
|
|
621
|
+
|
|
622
|
+
const [result, seenRecord, resolverErrors, missingRequiredFields] =
|
|
564
623
|
this._resolverCache.readFromCacheOrEvaluate(
|
|
565
624
|
record,
|
|
566
625
|
field,
|
|
567
626
|
this._variables,
|
|
568
|
-
|
|
569
|
-
const key = {
|
|
570
|
-
__id: RelayModernRecord.getDataID(record),
|
|
571
|
-
__fragmentOwner: this._owner,
|
|
572
|
-
__fragments: {
|
|
573
|
-
[fragment.name]: {}, // Arguments to this fragment; not yet supported.
|
|
574
|
-
},
|
|
575
|
-
};
|
|
576
|
-
return withResolverContext(resolverContext, () => {
|
|
577
|
-
// $FlowFixMe[prop-missing] - resolver module's type signature is a lie
|
|
578
|
-
const resolverResult = resolverModule(key);
|
|
579
|
-
return {
|
|
580
|
-
resolverResult,
|
|
581
|
-
fragmentValue,
|
|
582
|
-
resolverID,
|
|
583
|
-
seenRecordIDs: fragmentSeenRecordIDs,
|
|
584
|
-
readerSelector: fragmentReaderSelector,
|
|
585
|
-
missingRequiredFields: fragmentMissingRequiredFields,
|
|
586
|
-
};
|
|
587
|
-
});
|
|
588
|
-
},
|
|
627
|
+
evaluate,
|
|
589
628
|
getDataForResolverFragment,
|
|
590
629
|
);
|
|
591
630
|
|
|
631
|
+
for (const resolverError of resolverErrors) {
|
|
632
|
+
this._resolverErrors.push(resolverError);
|
|
633
|
+
}
|
|
592
634
|
if (missingRequiredFields != null) {
|
|
593
635
|
this._addMissingRequiredFields(missingRequiredFields);
|
|
594
636
|
}
|
|
@@ -105,6 +105,7 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
|
|
|
105
105
|
seenRecords: backup.seenRecords,
|
|
106
106
|
selector: backup.selector,
|
|
107
107
|
missingRequiredFields: backup.missingRequiredFields,
|
|
108
|
+
relayResolverErrors: backup.relayResolverErrors,
|
|
108
109
|
};
|
|
109
110
|
} else {
|
|
110
111
|
subscription.stale = true;
|
|
@@ -167,6 +168,7 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
|
|
|
167
168
|
seenRecords: nextSnapshot.seenRecords,
|
|
168
169
|
selector: nextSnapshot.selector,
|
|
169
170
|
missingRequiredFields: nextSnapshot.missingRequiredFields,
|
|
171
|
+
relayResolverErrors: nextSnapshot.relayResolverErrors,
|
|
170
172
|
}: Snapshot);
|
|
171
173
|
if (__DEV__) {
|
|
172
174
|
deepFreeze(nextSnapshot);
|
|
@@ -26,7 +26,6 @@ import type {
|
|
|
26
26
|
UploadableMap,
|
|
27
27
|
} from '../network/RelayNetworkTypes';
|
|
28
28
|
import type RelayObservable from '../network/RelayObservable';
|
|
29
|
-
import type {GraphQLTaggedNode} from '../query/GraphQLTag';
|
|
30
29
|
import type {RequestIdentifier} from '../util/getRequestIdentifier';
|
|
31
30
|
import type {
|
|
32
31
|
NormalizationArgument,
|
|
@@ -44,8 +43,9 @@ import type {
|
|
|
44
43
|
CacheConfig,
|
|
45
44
|
DataID,
|
|
46
45
|
Disposable,
|
|
47
|
-
OperationType,
|
|
48
46
|
RenderPolicy,
|
|
47
|
+
UpdatableQuery,
|
|
48
|
+
UpdatableQueryType,
|
|
49
49
|
Variables,
|
|
50
50
|
} from '../util/RelayRuntimeTypes';
|
|
51
51
|
import type {InvalidationState} from './RelayModernStore';
|
|
@@ -57,7 +57,7 @@ export type OperationTracker = RelayOperationTracker;
|
|
|
57
57
|
|
|
58
58
|
export type MutationParameters = {|
|
|
59
59
|
+response: {...},
|
|
60
|
-
+variables:
|
|
60
|
+
+variables: {...},
|
|
61
61
|
+rawResponse?: {...},
|
|
62
62
|
|};
|
|
63
63
|
|
|
@@ -112,14 +112,14 @@ export type NormalizationSelector = {|
|
|
|
112
112
|
+variables: Variables,
|
|
113
113
|
|};
|
|
114
114
|
|
|
115
|
-
type
|
|
115
|
+
type FieldLocation = {|
|
|
116
116
|
path: string,
|
|
117
117
|
owner: string,
|
|
118
118
|
|};
|
|
119
119
|
|
|
120
120
|
export type MissingRequiredFields = $ReadOnly<
|
|
121
|
-
| {|action: 'THROW', field:
|
|
122
|
-
| {|action: 'LOG', fields: Array<
|
|
121
|
+
| {|action: 'THROW', field: FieldLocation|}
|
|
122
|
+
| {|action: 'LOG', fields: Array<FieldLocation>|},
|
|
123
123
|
>;
|
|
124
124
|
|
|
125
125
|
export type ClientEdgeTraversalInfo = {|
|
|
@@ -135,6 +135,13 @@ export type MissingClientEdgeRequestInfo = {|
|
|
|
135
135
|
+clientEdgeDestinationID: DataID,
|
|
136
136
|
|};
|
|
137
137
|
|
|
138
|
+
export type RelayResolverError = {|
|
|
139
|
+
field: FieldLocation,
|
|
140
|
+
error: Error,
|
|
141
|
+
|};
|
|
142
|
+
|
|
143
|
+
export type RelayResolverErrors = Array<RelayResolverError>;
|
|
144
|
+
|
|
138
145
|
/**
|
|
139
146
|
* A representation of a selector and its results at a particular point in time.
|
|
140
147
|
*/
|
|
@@ -145,6 +152,7 @@ export type Snapshot = {|
|
|
|
145
152
|
+seenRecords: DataIDSet,
|
|
146
153
|
+selector: SingularReaderSelector,
|
|
147
154
|
+missingRequiredFields: ?MissingRequiredFields,
|
|
155
|
+
+relayResolverErrors: RelayResolverErrors,
|
|
148
156
|
|};
|
|
149
157
|
|
|
150
158
|
/**
|
|
@@ -466,8 +474,8 @@ export interface RecordSourceProxy {
|
|
|
466
474
|
get(dataID: DataID): ?RecordProxy;
|
|
467
475
|
getRoot(): RecordProxy;
|
|
468
476
|
invalidateStore(): void;
|
|
469
|
-
readUpdatableQuery_EXPERIMENTAL<TQuery:
|
|
470
|
-
query:
|
|
477
|
+
readUpdatableQuery_EXPERIMENTAL<TQuery: UpdatableQueryType>(
|
|
478
|
+
query: UpdatableQuery<TQuery['variables'], TQuery['response']>,
|
|
471
479
|
variables: TQuery['variables'],
|
|
472
480
|
): TQuery['response'];
|
|
473
481
|
}
|
|
@@ -1072,6 +1080,12 @@ export type RequiredFieldLogger = (
|
|
|
1072
1080
|
+kind: 'missing_field.throw',
|
|
1073
1081
|
+owner: string,
|
|
1074
1082
|
+fieldPath: string,
|
|
1083
|
+
|}
|
|
1084
|
+
| {|
|
|
1085
|
+
+kind: 'relay_resolver.error',
|
|
1086
|
+
+owner: string,
|
|
1087
|
+
+fieldPath: string,
|
|
1088
|
+
+error: Error,
|
|
1075
1089
|
|},
|
|
1076
1090
|
) => void;
|
|
1077
1091
|
|
|
@@ -29,7 +29,7 @@ const RelayConcreteNode = require('../util/RelayConcreteNode');
|
|
|
29
29
|
const stableCopy = require('../util/stableCopy');
|
|
30
30
|
const invariant = require('invariant');
|
|
31
31
|
|
|
32
|
-
export type Arguments =
|
|
32
|
+
export type Arguments = {+[string]: mixed};
|
|
33
33
|
|
|
34
34
|
const {VARIABLE, LITERAL, OBJECT_VALUE, LIST_VALUE} = RelayConcreteNode;
|
|
35
35
|
|
|
@@ -220,6 +220,7 @@ const RelayStoreUtils = {
|
|
|
220
220
|
RELAY_RESOLVER_INPUTS_KEY: '__resolverInputValues',
|
|
221
221
|
RELAY_RESOLVER_READER_SELECTOR_KEY: '__resolverReaderSelector',
|
|
222
222
|
RELAY_RESOLVER_MISSING_REQUIRED_FIELDS_KEY: '__resolverMissingRequiredFields',
|
|
223
|
+
RELAY_RESOLVER_ERROR_KEY: '__resolverError',
|
|
223
224
|
|
|
224
225
|
formatStorageKey,
|
|
225
226
|
getArgumentValue,
|
|
@@ -12,19 +12,25 @@
|
|
|
12
12
|
|
|
13
13
|
'use strict';
|
|
14
14
|
|
|
15
|
-
import type {
|
|
15
|
+
import type {
|
|
16
|
+
ReaderRelayLiveResolver,
|
|
17
|
+
ReaderRelayResolver,
|
|
18
|
+
} from '../util/ReaderNode';
|
|
16
19
|
import type {DataID, Variables} from '../util/RelayRuntimeTypes';
|
|
17
20
|
import type {
|
|
18
21
|
MissingRequiredFields,
|
|
19
22
|
MutableRecordSource,
|
|
20
23
|
Record,
|
|
24
|
+
RelayResolverErrors,
|
|
21
25
|
SingularReaderSelector,
|
|
22
26
|
} from './RelayStoreTypes';
|
|
23
27
|
|
|
24
28
|
const recycleNodesInto = require('../util/recycleNodesInto');
|
|
29
|
+
const {RELAY_LIVE_RESOLVER} = require('../util/RelayConcreteNode');
|
|
25
30
|
const {generateClientID} = require('./ClientID');
|
|
26
31
|
const RelayModernRecord = require('./RelayModernRecord');
|
|
27
32
|
const {
|
|
33
|
+
RELAY_RESOLVER_ERROR_KEY,
|
|
28
34
|
RELAY_RESOLVER_INPUTS_KEY,
|
|
29
35
|
RELAY_RESOLVER_INVALIDATION_KEY,
|
|
30
36
|
RELAY_RESOLVER_MISSING_REQUIRED_FIELDS_KEY,
|
|
@@ -32,6 +38,7 @@ const {
|
|
|
32
38
|
RELAY_RESOLVER_VALUE_KEY,
|
|
33
39
|
getStorageKey,
|
|
34
40
|
} = require('./RelayStoreUtils');
|
|
41
|
+
const invariant = require('invariant');
|
|
35
42
|
const warning = require('warning');
|
|
36
43
|
|
|
37
44
|
type ResolverID = string;
|
|
@@ -42,17 +49,23 @@ type EvaluationResult<T> = {|
|
|
|
42
49
|
resolverID: ResolverID,
|
|
43
50
|
seenRecordIDs: Set<DataID>,
|
|
44
51
|
readerSelector: SingularReaderSelector,
|
|
52
|
+
errors: RelayResolverErrors,
|
|
45
53
|
missingRequiredFields: ?MissingRequiredFields,
|
|
46
54
|
|};
|
|
47
55
|
|
|
48
56
|
export interface ResolverCache {
|
|
49
57
|
readFromCacheOrEvaluate<T>(
|
|
50
58
|
record: Record,
|
|
51
|
-
field: ReaderRelayResolver,
|
|
59
|
+
field: ReaderRelayResolver | ReaderRelayLiveResolver,
|
|
52
60
|
variables: Variables,
|
|
53
61
|
evaluate: () => EvaluationResult<T>,
|
|
54
62
|
getDataForResolverFragment: (SingularReaderSelector) => mixed,
|
|
55
|
-
): [
|
|
63
|
+
): [
|
|
64
|
+
T /* Answer */,
|
|
65
|
+
?DataID /* Seen record */,
|
|
66
|
+
RelayResolverErrors,
|
|
67
|
+
?MissingRequiredFields,
|
|
68
|
+
];
|
|
56
69
|
invalidateDataIDs(
|
|
57
70
|
updatedDataIDs: Set<DataID>, // Mutated in place
|
|
58
71
|
): void;
|
|
@@ -64,13 +77,22 @@ const emptySet: $ReadOnlySet<any> = new Set();
|
|
|
64
77
|
class NoopResolverCache implements ResolverCache {
|
|
65
78
|
readFromCacheOrEvaluate<T>(
|
|
66
79
|
record: Record,
|
|
67
|
-
field: ReaderRelayResolver,
|
|
80
|
+
field: ReaderRelayResolver | ReaderRelayLiveResolver,
|
|
68
81
|
variables: Variables,
|
|
69
82
|
evaluate: () => EvaluationResult<T>,
|
|
70
83
|
getDataForResolverFragment: SingularReaderSelector => mixed,
|
|
71
|
-
): [
|
|
72
|
-
|
|
73
|
-
|
|
84
|
+
): [
|
|
85
|
+
T /* Answer */,
|
|
86
|
+
?DataID /* Seen record */,
|
|
87
|
+
RelayResolverErrors,
|
|
88
|
+
?MissingRequiredFields,
|
|
89
|
+
] {
|
|
90
|
+
invariant(
|
|
91
|
+
field.kind !== RELAY_LIVE_RESOLVER,
|
|
92
|
+
'This store does not support Live Resolvers',
|
|
93
|
+
);
|
|
94
|
+
const {resolverResult, missingRequiredFields, errors} = evaluate();
|
|
95
|
+
return [resolverResult, undefined, errors, missingRequiredFields];
|
|
74
96
|
}
|
|
75
97
|
invalidateDataIDs(updatedDataIDs: Set<DataID>): void {}
|
|
76
98
|
}
|
|
@@ -102,11 +124,16 @@ class RecordResolverCache implements ResolverCache {
|
|
|
102
124
|
|
|
103
125
|
readFromCacheOrEvaluate<T>(
|
|
104
126
|
record: Record,
|
|
105
|
-
field: ReaderRelayResolver,
|
|
127
|
+
field: ReaderRelayResolver | ReaderRelayLiveResolver,
|
|
106
128
|
variables: Variables,
|
|
107
129
|
evaluate: () => EvaluationResult<T>,
|
|
108
130
|
getDataForResolverFragment: SingularReaderSelector => mixed,
|
|
109
|
-
): [
|
|
131
|
+
): [
|
|
132
|
+
T /* Answer */,
|
|
133
|
+
?DataID /* Seen record */,
|
|
134
|
+
RelayResolverErrors,
|
|
135
|
+
?MissingRequiredFields,
|
|
136
|
+
] {
|
|
110
137
|
const recordSource = this._getRecordSource();
|
|
111
138
|
const recordID = RelayModernRecord.getDataID(record);
|
|
112
139
|
|
|
@@ -142,6 +169,11 @@ class RecordResolverCache implements ResolverCache {
|
|
|
142
169
|
RELAY_RESOLVER_MISSING_REQUIRED_FIELDS_KEY,
|
|
143
170
|
evaluationResult.missingRequiredFields,
|
|
144
171
|
);
|
|
172
|
+
RelayModernRecord.setValue(
|
|
173
|
+
linkedRecord,
|
|
174
|
+
RELAY_RESOLVER_ERROR_KEY,
|
|
175
|
+
evaluationResult.errors,
|
|
176
|
+
);
|
|
145
177
|
recordSource.set(linkedID, linkedRecord);
|
|
146
178
|
|
|
147
179
|
// Link the resolver value record to the resolver field of the record being read:
|
|
@@ -168,7 +200,10 @@ class RecordResolverCache implements ResolverCache {
|
|
|
168
200
|
const missingRequiredFields: ?MissingRequiredFields =
|
|
169
201
|
// $FlowFixMe[incompatible-type] - casting mixed
|
|
170
202
|
linkedRecord[RELAY_RESOLVER_MISSING_REQUIRED_FIELDS_KEY];
|
|
171
|
-
|
|
203
|
+
|
|
204
|
+
// $FlowFixMe[incompatible-type] - casting mixed
|
|
205
|
+
const errors: RelayResolverErrors = linkedRecord[RELAY_RESOLVER_ERROR_KEY];
|
|
206
|
+
return [answer, linkedID, errors, missingRequiredFields];
|
|
172
207
|
}
|
|
173
208
|
|
|
174
209
|
invalidateDataIDs(
|