relay-runtime 11.0.1 → 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.
- package/index.js +1 -1
- package/index.js.flow +4 -2
- package/lib/handlers/RelayDefaultHandlerProvider.js +1 -1
- package/lib/handlers/connection/ConnectionHandler.js +1 -1
- package/lib/handlers/connection/MutationHandlers.js +1 -1
- package/lib/multi-actor-environment/ActorIdentifier.js +23 -0
- package/lib/multi-actor-environment/ActorSpecificEnvironment.js +108 -0
- package/lib/multi-actor-environment/MultiActorEnvironment.js +156 -0
- package/lib/multi-actor-environment/MultiActorEnvironmentTypes.js +11 -0
- package/lib/multi-actor-environment/index.js +17 -0
- package/lib/mutations/RelayRecordProxy.js +1 -1
- package/lib/mutations/RelayRecordSourceMutator.js +1 -1
- package/lib/mutations/RelayRecordSourceProxy.js +1 -1
- package/lib/mutations/RelayRecordSourceSelectorProxy.js +1 -1
- package/lib/mutations/applyOptimisticMutation.js +1 -1
- package/lib/mutations/commitMutation.js +1 -1
- package/lib/network/RelayNetwork.js +1 -1
- package/lib/network/RelayQueryResponseCache.js +1 -1
- package/lib/query/GraphQLTag.js +1 -1
- package/lib/query/fetchQuery.js +1 -1
- package/lib/query/fetchQueryInternal.js +1 -1
- package/lib/store/DataChecker.js +1 -1
- package/lib/store/{RelayModernQueryExecutor.js → OperationExecutor.js} +81 -37
- package/lib/store/RelayConcreteVariables.js +1 -1
- package/lib/store/RelayModernEnvironment.js +99 -144
- package/lib/store/RelayModernFragmentSpecResolver.js +1 -1
- package/lib/store/RelayModernRecord.js +1 -1
- package/lib/store/RelayModernSelector.js +1 -1
- package/lib/store/RelayModernStore.js +1 -6
- package/lib/store/RelayOperationTracker.js +1 -1
- package/lib/store/RelayPublishQueue.js +9 -5
- package/lib/store/RelayReader.js +63 -10
- package/lib/store/RelayReferenceMarker.js +1 -1
- package/lib/store/RelayResponseNormalizer.js +47 -22
- package/lib/store/RelayStoreReactFlightUtils.js +1 -1
- package/lib/store/RelayStoreUtils.js +1 -1
- package/lib/store/ResolverFragments.js +57 -0
- package/lib/store/cloneRelayHandleSourceField.js +1 -1
- package/lib/store/cloneRelayScalarHandleSourceField.js +1 -1
- package/lib/store/createRelayContext.js +1 -1
- package/lib/store/readInlineData.js +1 -1
- package/lib/subscription/requestSubscription.js +18 -7
- package/lib/util/RelayConcreteNode.js +1 -0
- package/lib/util/RelayFeatureFlags.js +3 -1
- package/lib/util/RelayProfiler.js +17 -187
- package/lib/util/RelayReplaySubject.js +1 -1
- package/lib/util/getRelayHandleKey.js +1 -1
- package/lib/util/getRequestIdentifier.js +1 -1
- package/multi-actor-environment/ActorIdentifier.js.flow +27 -0
- package/multi-actor-environment/ActorSpecificEnvironment.js.flow +189 -0
- package/multi-actor-environment/MultiActorEnvironment.js.flow +233 -0
- package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +196 -0
- package/multi-actor-environment/index.js.flow +24 -0
- package/network/RelayNetworkTypes.js.flow +5 -4
- package/package.json +3 -2
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +2 -2
- package/store/{RelayModernQueryExecutor.js.flow → OperationExecutor.js.flow} +82 -35
- package/store/RelayModernEnvironment.js.flow +88 -131
- package/store/RelayModernStore.js.flow +0 -5
- package/store/RelayPublishQueue.js.flow +7 -4
- package/store/RelayReader.js.flow +57 -5
- package/store/RelayResponseNormalizer.js.flow +67 -26
- package/store/RelayStoreTypes.js.flow +15 -8
- package/store/ResolverFragments.js.flow +125 -0
- package/subscription/requestSubscription.js.flow +15 -7
- package/util/ReaderNode.js.flow +14 -1
- package/util/RelayConcreteNode.js.flow +1 -0
- package/util/RelayFeatureFlags.js.flow +4 -0
- package/util/RelayProfiler.js.flow +22 -194
- package/util/RelayRuntimeTypes.js.flow +3 -1
|
@@ -28,6 +28,7 @@ const {
|
|
|
28
28
|
LINKED_FIELD,
|
|
29
29
|
MODULE_IMPORT,
|
|
30
30
|
REQUIRED_FIELD,
|
|
31
|
+
RELAY_RESOLVER,
|
|
31
32
|
SCALAR_FIELD,
|
|
32
33
|
STREAM,
|
|
33
34
|
} = require('../util/RelayConcreteNode');
|
|
@@ -44,15 +45,18 @@ const {
|
|
|
44
45
|
getStorageKey,
|
|
45
46
|
getModuleComponentKey,
|
|
46
47
|
} = require('./RelayStoreUtils');
|
|
48
|
+
const {withResolverContext} = require('./ResolverFragments');
|
|
47
49
|
const {generateTypeID} = require('./TypeID');
|
|
48
50
|
|
|
49
51
|
import type {
|
|
50
52
|
ReaderFlightField,
|
|
53
|
+
ReaderFragment,
|
|
51
54
|
ReaderFragmentSpread,
|
|
52
55
|
ReaderInlineDataFragmentSpread,
|
|
53
56
|
ReaderLinkedField,
|
|
54
57
|
ReaderModuleImport,
|
|
55
58
|
ReaderNode,
|
|
59
|
+
ReaderRelayResolver,
|
|
56
60
|
ReaderRequiredField,
|
|
57
61
|
ReaderScalarField,
|
|
58
62
|
ReaderSelection,
|
|
@@ -327,6 +331,13 @@ class RelayReader {
|
|
|
327
331
|
}
|
|
328
332
|
break;
|
|
329
333
|
}
|
|
334
|
+
case RELAY_RESOLVER: {
|
|
335
|
+
if (!RelayFeatureFlags.ENABLE_RELAY_RESOLVERS) {
|
|
336
|
+
throw new Error('Relay Resolver fields are not yet supported.');
|
|
337
|
+
}
|
|
338
|
+
this._readResolverField(selection, record, data);
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
330
341
|
case FRAGMENT_SPREAD:
|
|
331
342
|
this._createFragmentPointer(selection, record, data);
|
|
332
343
|
break;
|
|
@@ -334,7 +345,11 @@ class RelayReader {
|
|
|
334
345
|
this._readModuleImport(selection, record, data);
|
|
335
346
|
break;
|
|
336
347
|
case INLINE_DATA_FRAGMENT_SPREAD:
|
|
337
|
-
this.
|
|
348
|
+
this._createInlineDataOrResolverFragmentPointer(
|
|
349
|
+
selection,
|
|
350
|
+
record,
|
|
351
|
+
data,
|
|
352
|
+
);
|
|
338
353
|
break;
|
|
339
354
|
case DEFER:
|
|
340
355
|
case CLIENT_EXTENSION: {
|
|
@@ -404,6 +419,43 @@ class RelayReader {
|
|
|
404
419
|
}
|
|
405
420
|
}
|
|
406
421
|
|
|
422
|
+
_readResolverField(
|
|
423
|
+
selection: ReaderRelayResolver,
|
|
424
|
+
record: Record,
|
|
425
|
+
data: SelectorData,
|
|
426
|
+
): ?mixed {
|
|
427
|
+
const {name, alias, resolverModule, fragment} = selection;
|
|
428
|
+
const key = {
|
|
429
|
+
__id: RelayModernRecord.getDataID(record),
|
|
430
|
+
__fragmentOwner: this._owner,
|
|
431
|
+
__fragments: {
|
|
432
|
+
[fragment.name]: {}, // Arguments to this fragment; not yet supported.
|
|
433
|
+
},
|
|
434
|
+
};
|
|
435
|
+
const resolverContext = {
|
|
436
|
+
getDataForResolverFragment: singularReaderSelector => {
|
|
437
|
+
const resolverFragmentData = {};
|
|
438
|
+
this._createInlineDataOrResolverFragmentPointer(
|
|
439
|
+
singularReaderSelector.node,
|
|
440
|
+
record,
|
|
441
|
+
resolverFragmentData,
|
|
442
|
+
);
|
|
443
|
+
const answer = resolverFragmentData[FRAGMENTS_KEY]?.[fragment.name];
|
|
444
|
+
invariant(
|
|
445
|
+
typeof answer === 'object' && answer !== null,
|
|
446
|
+
`Expected reader data to contain a __fragments property with a property for the fragment named ${fragment.name}, but it is missing.`,
|
|
447
|
+
);
|
|
448
|
+
return answer;
|
|
449
|
+
},
|
|
450
|
+
};
|
|
451
|
+
const resolverResult = withResolverContext(resolverContext, () =>
|
|
452
|
+
// $FlowFixMe[prop-missing] - resolver module's type signature is a lie
|
|
453
|
+
resolverModule(key),
|
|
454
|
+
);
|
|
455
|
+
data[alias ?? name] = resolverResult;
|
|
456
|
+
return resolverResult;
|
|
457
|
+
}
|
|
458
|
+
|
|
407
459
|
_readFlightField(
|
|
408
460
|
field: ReaderFlightField,
|
|
409
461
|
record: Record,
|
|
@@ -607,8 +659,8 @@ class RelayReader {
|
|
|
607
659
|
}
|
|
608
660
|
}
|
|
609
661
|
|
|
610
|
-
|
|
611
|
-
|
|
662
|
+
_createInlineDataOrResolverFragmentPointer(
|
|
663
|
+
fragmentSpreadOrFragment: ReaderInlineDataFragmentSpread | ReaderFragment,
|
|
612
664
|
record: Record,
|
|
613
665
|
data: SelectorData,
|
|
614
666
|
): void {
|
|
@@ -626,12 +678,12 @@ class RelayReader {
|
|
|
626
678
|
}
|
|
627
679
|
const inlineData = {};
|
|
628
680
|
this._traverseSelections(
|
|
629
|
-
|
|
681
|
+
fragmentSpreadOrFragment.selections,
|
|
630
682
|
record,
|
|
631
683
|
inlineData,
|
|
632
684
|
);
|
|
633
685
|
// $FlowFixMe[cannot-write] - writing into read-only field
|
|
634
|
-
fragmentPointers[
|
|
686
|
+
fragmentPointers[fragmentSpreadOrFragment.name] = inlineData;
|
|
635
687
|
}
|
|
636
688
|
}
|
|
637
689
|
|
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
|
|
15
15
|
const RelayFeatureFlags = require('../util/RelayFeatureFlags');
|
|
16
16
|
const RelayModernRecord = require('./RelayModernRecord');
|
|
17
|
-
const RelayProfiler = require('../util/RelayProfiler');
|
|
18
17
|
|
|
19
18
|
const areEqual = require('areEqual');
|
|
20
19
|
const invariant = require('invariant');
|
|
@@ -535,11 +534,40 @@ class RelayResponseNormalizer {
|
|
|
535
534
|
const fieldValue = data[responseKey];
|
|
536
535
|
|
|
537
536
|
if (fieldValue == null) {
|
|
537
|
+
if (fieldValue === undefined) {
|
|
538
|
+
// Flight field may be missing in the response if:
|
|
539
|
+
// - It is inside an abstract type refinement where the concrete type does
|
|
540
|
+
// not conform to the interface/union.
|
|
541
|
+
// However an otherwise-required field may also be missing if the server
|
|
542
|
+
// is configured to skip fields with `null` values, in which case the
|
|
543
|
+
// client is assumed to be correctly configured with
|
|
544
|
+
// treatMissingFieldsAsNull=true.
|
|
545
|
+
if (this._isUnmatchedAbstractType) {
|
|
546
|
+
// Field not expected to exist regardless of whether the server is pruning null
|
|
547
|
+
// fields or not.
|
|
548
|
+
return;
|
|
549
|
+
} else if (!this._treatMissingFieldsAsNull) {
|
|
550
|
+
// Not optional and the server is not pruning null fields: field is expected
|
|
551
|
+
// to be present
|
|
552
|
+
if (__DEV__) {
|
|
553
|
+
warning(
|
|
554
|
+
false,
|
|
555
|
+
'RelayResponseNormalizer: Payload did not contain a value ' +
|
|
556
|
+
'for field `%s: %s`. Check that you are parsing with the same ' +
|
|
557
|
+
'query that was used to fetch the payload.',
|
|
558
|
+
responseKey,
|
|
559
|
+
storageKey,
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
538
565
|
RelayModernRecord.setValue(record, storageKey, null);
|
|
539
566
|
return;
|
|
540
567
|
}
|
|
541
568
|
|
|
542
569
|
const reactFlightPayload = refineToReactFlightPayloadData(fieldValue);
|
|
570
|
+
const reactFlightPayloadDeserializer = this._reactFlightPayloadDeserializer;
|
|
543
571
|
|
|
544
572
|
invariant(
|
|
545
573
|
reactFlightPayload != null,
|
|
@@ -549,10 +577,10 @@ class RelayResponseNormalizer {
|
|
|
549
577
|
fieldValue,
|
|
550
578
|
);
|
|
551
579
|
invariant(
|
|
552
|
-
typeof
|
|
580
|
+
typeof reactFlightPayloadDeserializer === 'function',
|
|
553
581
|
'RelayResponseNormalizer: Expected reactFlightPayloadDeserializer to ' +
|
|
554
582
|
'be a function, got `%s`.',
|
|
555
|
-
|
|
583
|
+
reactFlightPayloadDeserializer,
|
|
556
584
|
);
|
|
557
585
|
|
|
558
586
|
if (reactFlightPayload.errors.length > 0) {
|
|
@@ -573,44 +601,60 @@ class RelayResponseNormalizer {
|
|
|
573
601
|
}
|
|
574
602
|
}
|
|
575
603
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
604
|
+
const reactFlightID = generateClientID(
|
|
605
|
+
RelayModernRecord.getDataID(record),
|
|
606
|
+
getStorageKey(selection, this._variables),
|
|
607
|
+
);
|
|
608
|
+
let reactFlightClientResponseRecord = this._recordSource.get(reactFlightID);
|
|
609
|
+
if (reactFlightClientResponseRecord == null) {
|
|
610
|
+
reactFlightClientResponseRecord = RelayModernRecord.create(
|
|
611
|
+
reactFlightID,
|
|
612
|
+
REACT_FLIGHT_TYPE_NAME,
|
|
613
|
+
);
|
|
614
|
+
this._recordSource.set(reactFlightID, reactFlightClientResponseRecord);
|
|
615
|
+
}
|
|
616
|
+
|
|
581
617
|
if (reactFlightPayload.tree == null) {
|
|
618
|
+
// This typically indicates that a fatal server error prevented rows from
|
|
619
|
+
// being written. When this occurs, we should not continue normalization of
|
|
620
|
+
// the Flight field because the row response is malformed.
|
|
621
|
+
//
|
|
622
|
+
// Receiving empty rows is OK because it can indicate the start of a stream.
|
|
582
623
|
warning(
|
|
583
624
|
false,
|
|
584
625
|
'RelayResponseNormalizer: Expected `tree` not to be null. This ' +
|
|
585
626
|
'typically indicates that a fatal server error prevented any Server ' +
|
|
586
627
|
'Component rows from being written.',
|
|
587
628
|
);
|
|
629
|
+
// We create the flight record with a null value for the tree
|
|
630
|
+
// and empty reachable definitions
|
|
631
|
+
RelayModernRecord.setValue(
|
|
632
|
+
reactFlightClientResponseRecord,
|
|
633
|
+
REACT_FLIGHT_TREE_STORAGE_KEY,
|
|
634
|
+
null,
|
|
635
|
+
);
|
|
636
|
+
RelayModernRecord.setValue(
|
|
637
|
+
reactFlightClientResponseRecord,
|
|
638
|
+
REACT_FLIGHT_EXECUTABLE_DEFINITIONS_STORAGE_KEY,
|
|
639
|
+
[],
|
|
640
|
+
);
|
|
641
|
+
RelayModernRecord.setLinkedRecordID(record, storageKey, reactFlightID);
|
|
588
642
|
return;
|
|
589
643
|
}
|
|
590
644
|
|
|
591
645
|
// We store the deserialized reactFlightClientResponse in a separate
|
|
592
646
|
// record and link it to the parent record. This is so we can GC the Flight
|
|
593
647
|
// tree later even if the parent record is still reachable.
|
|
594
|
-
const reactFlightClientResponse =
|
|
648
|
+
const reactFlightClientResponse = reactFlightPayloadDeserializer(
|
|
595
649
|
reactFlightPayload.tree,
|
|
596
650
|
);
|
|
597
|
-
|
|
598
|
-
RelayModernRecord.getDataID(record),
|
|
599
|
-
getStorageKey(selection, this._variables),
|
|
600
|
-
);
|
|
601
|
-
let reactFlightClientResponseRecord = this._recordSource.get(reactFlightID);
|
|
602
|
-
if (reactFlightClientResponseRecord == null) {
|
|
603
|
-
reactFlightClientResponseRecord = RelayModernRecord.create(
|
|
604
|
-
reactFlightID,
|
|
605
|
-
REACT_FLIGHT_TYPE_NAME,
|
|
606
|
-
);
|
|
607
|
-
this._recordSource.set(reactFlightID, reactFlightClientResponseRecord);
|
|
608
|
-
}
|
|
651
|
+
|
|
609
652
|
RelayModernRecord.setValue(
|
|
610
653
|
reactFlightClientResponseRecord,
|
|
611
654
|
REACT_FLIGHT_TREE_STORAGE_KEY,
|
|
612
655
|
reactFlightClientResponse,
|
|
613
656
|
);
|
|
657
|
+
|
|
614
658
|
const reachableExecutableDefinitions: Array<ReactFlightReachableExecutableDefinitions> = [];
|
|
615
659
|
for (const query of reactFlightPayload.queries) {
|
|
616
660
|
if (query.response.data != null) {
|
|
@@ -853,9 +897,6 @@ class RelayResponseNormalizer {
|
|
|
853
897
|
}
|
|
854
898
|
}
|
|
855
899
|
|
|
856
|
-
|
|
857
|
-
'RelayResponseNormalizer.normalize',
|
|
900
|
+
module.exports = {
|
|
858
901
|
normalize,
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
module.exports = {normalize: instrumentedNormalize};
|
|
902
|
+
};
|
|
@@ -658,13 +658,9 @@ export interface IEnvironment {
|
|
|
658
658
|
* the result is subscribed to:
|
|
659
659
|
* environment.executeMutation({...}).subscribe({...}).
|
|
660
660
|
*/
|
|
661
|
-
executeMutation(
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
optimisticResponse?: ?Object,
|
|
665
|
-
updater?: ?SelectorStoreUpdater,
|
|
666
|
-
uploadables?: ?UploadableMap,
|
|
667
|
-
|}): RelayObservable<GraphQLResponse>;
|
|
661
|
+
executeMutation(
|
|
662
|
+
config: ExecuteMutationConfig,
|
|
663
|
+
): RelayObservable<GraphQLResponse>;
|
|
668
664
|
|
|
669
665
|
/**
|
|
670
666
|
* Returns an Observable of GraphQLResponse resulting from executing the
|
|
@@ -936,7 +932,18 @@ export type RelayResponsePayload = {|
|
|
|
936
932
|
|};
|
|
937
933
|
|
|
938
934
|
/**
|
|
939
|
-
*
|
|
935
|
+
* Configuration on the executeMutation(...).
|
|
936
|
+
*/
|
|
937
|
+
export type ExecuteMutationConfig = {|
|
|
938
|
+
operation: OperationDescriptor,
|
|
939
|
+
optimisticUpdater?: ?SelectorStoreUpdater,
|
|
940
|
+
optimisticResponse?: ?Object,
|
|
941
|
+
updater?: ?SelectorStoreUpdater,
|
|
942
|
+
uploadables?: ?UploadableMap,
|
|
943
|
+
|};
|
|
944
|
+
|
|
945
|
+
/**
|
|
946
|
+
* Public interface for Publish Queue.
|
|
940
947
|
*/
|
|
941
948
|
export interface PublishQueue {
|
|
942
949
|
/**
|
|
@@ -0,0 +1,125 @@
|
|
|
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
|
+
* @flow strict-local
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// flowlint ambiguous-object-type:error
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
const invariant = require('invariant');
|
|
16
|
+
|
|
17
|
+
const {getFragment} = require('../query/GraphQLTag');
|
|
18
|
+
const {getSelector} = require('./RelayModernSelector');
|
|
19
|
+
|
|
20
|
+
import type {GraphQLTaggedNode} from '../query/GraphQLTag';
|
|
21
|
+
import type {
|
|
22
|
+
FragmentReference,
|
|
23
|
+
SingularReaderSelector,
|
|
24
|
+
} from './RelayStoreTypes';
|
|
25
|
+
|
|
26
|
+
// When we call the user-supplied resolver function, it will in turn call
|
|
27
|
+
// `readFragment`, but that's a global function -- it needs information
|
|
28
|
+
// about what resolver is being executed, which is supplied by putting the
|
|
29
|
+
// info on this stack before we call the resolver function.
|
|
30
|
+
type ResolverContext = {|
|
|
31
|
+
getDataForResolverFragment: SingularReaderSelector => mixed,
|
|
32
|
+
|};
|
|
33
|
+
const contextStack: Array<ResolverContext> = [];
|
|
34
|
+
|
|
35
|
+
function withResolverContext<T>(context: ResolverContext, cb: () => T): T {
|
|
36
|
+
contextStack.push(context);
|
|
37
|
+
try {
|
|
38
|
+
return cb();
|
|
39
|
+
} finally {
|
|
40
|
+
contextStack.pop();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// NOTE: these declarations are copied from 'useFragment'; it would be good
|
|
45
|
+
// to figure out how to share the same type signature between the two functions.
|
|
46
|
+
// The declarations ensure that the type of the returned data is:
|
|
47
|
+
// - non-nullable if the provided ref type is non-nullable
|
|
48
|
+
// - nullable if the provided ref type is nullable
|
|
49
|
+
// - array of non-nullable if the privoided ref type is an array of
|
|
50
|
+
// non-nullable refs
|
|
51
|
+
// - array of nullable if the privoided ref type is an array of nullable refs
|
|
52
|
+
|
|
53
|
+
declare function readFragment<
|
|
54
|
+
TKey: {+$data?: mixed, +$fragmentRefs: FragmentReference, ...},
|
|
55
|
+
>(
|
|
56
|
+
fragmentInput: GraphQLTaggedNode,
|
|
57
|
+
fragmentRef: TKey,
|
|
58
|
+
): $Call<<TFragmentData>({+$data?: TFragmentData, ...}) => TFragmentData, TKey>;
|
|
59
|
+
|
|
60
|
+
declare function readFragment<
|
|
61
|
+
TKey: ?{+$data?: mixed, +$fragmentRefs: FragmentReference, ...},
|
|
62
|
+
>(
|
|
63
|
+
fragmentInput: GraphQLTaggedNode,
|
|
64
|
+
fragmentRef: TKey,
|
|
65
|
+
): $Call<
|
|
66
|
+
<TFragmentData>(?{+$data?: TFragmentData, ...}) => ?TFragmentData,
|
|
67
|
+
TKey,
|
|
68
|
+
>;
|
|
69
|
+
|
|
70
|
+
declare function readFragment<
|
|
71
|
+
TKey: $ReadOnlyArray<{
|
|
72
|
+
+$data?: mixed,
|
|
73
|
+
+$fragmentRefs: FragmentReference,
|
|
74
|
+
...
|
|
75
|
+
}>,
|
|
76
|
+
>(
|
|
77
|
+
fragmentInput: GraphQLTaggedNode,
|
|
78
|
+
fragmentRef: TKey,
|
|
79
|
+
): $Call<
|
|
80
|
+
<TFragmentData>(
|
|
81
|
+
$ReadOnlyArray<{+$data?: TFragmentData, ...}>,
|
|
82
|
+
) => TFragmentData,
|
|
83
|
+
TKey,
|
|
84
|
+
>;
|
|
85
|
+
|
|
86
|
+
declare function readFragment<
|
|
87
|
+
TKey: ?$ReadOnlyArray<{
|
|
88
|
+
+$data?: mixed,
|
|
89
|
+
+$fragmentRefs: FragmentReference,
|
|
90
|
+
...
|
|
91
|
+
}>,
|
|
92
|
+
>(
|
|
93
|
+
fragmentInput: GraphQLTaggedNode,
|
|
94
|
+
fragmentRef: TKey,
|
|
95
|
+
): $Call<
|
|
96
|
+
<TFragmentData>(
|
|
97
|
+
?$ReadOnlyArray<{+$data?: TFragmentData, ...}>,
|
|
98
|
+
) => ?TFragmentData,
|
|
99
|
+
TKey,
|
|
100
|
+
>;
|
|
101
|
+
|
|
102
|
+
function readFragment(
|
|
103
|
+
fragmentInput: GraphQLTaggedNode,
|
|
104
|
+
fragmentRef: mixed,
|
|
105
|
+
): mixed {
|
|
106
|
+
if (!contextStack.length) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
'readFragment should be called only from within a Relay Resolver function.',
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
const context = contextStack[contextStack.length - 1];
|
|
112
|
+
const fragmentNode = getFragment(fragmentInput);
|
|
113
|
+
const fragmentSelector = getSelector(fragmentNode, fragmentRef);
|
|
114
|
+
invariant(
|
|
115
|
+
fragmentSelector != null,
|
|
116
|
+
`Expected a selector for the fragment of the resolver ${fragmentNode.name}, but got null.`,
|
|
117
|
+
);
|
|
118
|
+
invariant(
|
|
119
|
+
fragmentSelector.kind === 'SingularReaderSelector',
|
|
120
|
+
`Expected a singular reader selector for the fragment of the resolver ${fragmentNode.name}, but it was plural.`,
|
|
121
|
+
);
|
|
122
|
+
return context.getDataForResolverFragment(fragmentSelector);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
module.exports = {readFragment, withResolverContext};
|
|
@@ -22,6 +22,7 @@ const {generateUniqueClientID} = require('../store/ClientID');
|
|
|
22
22
|
const {
|
|
23
23
|
createOperationDescriptor,
|
|
24
24
|
} = require('../store/RelayModernOperationDescriptor');
|
|
25
|
+
const {createReaderSelector} = require('../store/RelayModernSelector');
|
|
25
26
|
|
|
26
27
|
import type {DeclarativeMutationConfig} from '../mutations/RelayDeclarativeMutationConfig';
|
|
27
28
|
import type {GraphQLTaggedNode} from '../query/GraphQLTag';
|
|
@@ -91,17 +92,24 @@ function requestSubscription<TSubscriptionPayload>(
|
|
|
91
92
|
updater,
|
|
92
93
|
})
|
|
93
94
|
.map(responses => {
|
|
95
|
+
let selector = operation.fragment;
|
|
94
96
|
if (RelayFeatureFlags.ENABLE_UNIQUE_SUBSCRIPTION_ROOT) {
|
|
97
|
+
let nextID;
|
|
95
98
|
if (Array.isArray(responses)) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
nextID = responses[0]?.extensions?.__relay_subscription_root_id;
|
|
100
|
+
} else {
|
|
101
|
+
nextID = responses.extensions?.__relay_subscription_root_id;
|
|
102
|
+
}
|
|
103
|
+
if (typeof nextID === 'string') {
|
|
104
|
+
selector = createReaderSelector(
|
|
105
|
+
selector.node,
|
|
106
|
+
nextID,
|
|
107
|
+
selector.variables,
|
|
108
|
+
selector.owner,
|
|
109
|
+
);
|
|
100
110
|
}
|
|
101
|
-
// $FlowFixMe[incompatible-cast]
|
|
102
|
-
return (responses.data: TSubscriptionPayload);
|
|
103
111
|
}
|
|
104
|
-
const data = environment.lookup(
|
|
112
|
+
const data = environment.lookup(selector).data;
|
|
105
113
|
// $FlowFixMe[incompatible-cast]
|
|
106
114
|
return (data: TSubscriptionPayload);
|
|
107
115
|
})
|
package/util/ReaderNode.js.flow
CHANGED
|
@@ -206,6 +206,18 @@ export type ReaderRequiredField = {|
|
|
|
206
206
|
+path: string,
|
|
207
207
|
|};
|
|
208
208
|
|
|
209
|
+
export type ReaderRelayResolver = {|
|
|
210
|
+
+kind: 'RelayResolver',
|
|
211
|
+
+alias: ?string,
|
|
212
|
+
+name: string,
|
|
213
|
+
+fragment: ReaderFragmentSpread,
|
|
214
|
+
+resolverModule: (rootKey: {
|
|
215
|
+
+$data?: any, // flowlint-line unclear-type:off
|
|
216
|
+
+$fragmentRefs: any, // flowlint-line unclear-type:off
|
|
217
|
+
...
|
|
218
|
+
}) => mixed,
|
|
219
|
+
|};
|
|
220
|
+
|
|
209
221
|
export type ReaderSelection =
|
|
210
222
|
| ReaderCondition
|
|
211
223
|
| ReaderClientExtension
|
|
@@ -217,7 +229,8 @@ export type ReaderSelection =
|
|
|
217
229
|
| ReaderInlineFragment
|
|
218
230
|
| ReaderModuleImport
|
|
219
231
|
| ReaderStream
|
|
220
|
-
| ReaderRequiredField
|
|
232
|
+
| ReaderRequiredField
|
|
233
|
+
| ReaderRelayResolver;
|
|
221
234
|
|
|
222
235
|
export type ReaderVariableArgument = {|
|
|
223
236
|
+kind: 'Variable',
|
|
@@ -19,6 +19,7 @@ type FeatureFlags = {|
|
|
|
19
19
|
ENABLE_PRECISE_TYPE_REFINEMENT: boolean,
|
|
20
20
|
ENABLE_REACT_FLIGHT_COMPONENT_FIELD: boolean,
|
|
21
21
|
ENABLE_REQUIRED_DIRECTIVES: boolean | string,
|
|
22
|
+
ENABLE_RELAY_RESOLVERS: boolean,
|
|
22
23
|
ENABLE_GETFRAGMENTIDENTIFIER_OPTIMIZATION: boolean,
|
|
23
24
|
ENABLE_FRIENDLY_QUERY_NAME_GQL_URL: boolean,
|
|
24
25
|
ENABLE_STORE_SUBSCRIPTIONS_REFACTOR: boolean,
|
|
@@ -26,6 +27,7 @@ type FeatureFlags = {|
|
|
|
26
27
|
ENABLE_DO_NOT_WRAP_LIVE_QUERY: boolean,
|
|
27
28
|
ENABLE_NOTIFY_SUBSCRIPTION: boolean,
|
|
28
29
|
ENABLE_UNIQUE_SUBSCRIPTION_ROOT: boolean,
|
|
30
|
+
ENABLE_BATCHED_STORE_UPDATES: boolean,
|
|
29
31
|
|};
|
|
30
32
|
|
|
31
33
|
const RelayFeatureFlags: FeatureFlags = {
|
|
@@ -35,6 +37,7 @@ const RelayFeatureFlags: FeatureFlags = {
|
|
|
35
37
|
ENABLE_PRECISE_TYPE_REFINEMENT: false,
|
|
36
38
|
ENABLE_REACT_FLIGHT_COMPONENT_FIELD: false,
|
|
37
39
|
ENABLE_REQUIRED_DIRECTIVES: false,
|
|
40
|
+
ENABLE_RELAY_RESOLVERS: false,
|
|
38
41
|
ENABLE_GETFRAGMENTIDENTIFIER_OPTIMIZATION: false,
|
|
39
42
|
ENABLE_FRIENDLY_QUERY_NAME_GQL_URL: false,
|
|
40
43
|
ENABLE_STORE_SUBSCRIPTIONS_REFACTOR: false,
|
|
@@ -42,6 +45,7 @@ const RelayFeatureFlags: FeatureFlags = {
|
|
|
42
45
|
ENABLE_DO_NOT_WRAP_LIVE_QUERY: false,
|
|
43
46
|
ENABLE_NOTIFY_SUBSCRIPTION: false,
|
|
44
47
|
ENABLE_UNIQUE_SUBSCRIPTION_ROOT: false,
|
|
48
|
+
ENABLE_BATCHED_STORE_UPDATES: false,
|
|
45
49
|
};
|
|
46
50
|
|
|
47
51
|
module.exports = RelayFeatureFlags;
|