relay-runtime 13.0.0-rc.2 → 13.0.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/LICENSE +1 -1
- package/README.md +1 -4
- package/index.js +2 -2
- package/index.js.flow +4 -0
- package/lib/index.js +7 -1
- package/lib/mutations/readUpdatableQuery_EXPERIMENTAL.js +22 -17
- package/lib/mutations/validateMutation.js +11 -1
- package/lib/network/RelayNetwork.js +7 -3
- package/lib/query/fetchQuery.js +3 -0
- package/lib/store/RelayConcreteVariables.js +12 -3
- package/lib/store/RelayExperimentalGraphResponseTransform.js +34 -2
- package/lib/store/RelayModernOperationDescriptor.js +1 -1
- package/lib/store/RelayPublishQueue.js +4 -2
- package/lib/store/RelayReader.js +55 -13
- package/lib/store/RelayStoreUtils.js +1 -0
- package/lib/store/ResolverCache.js +10 -2
- package/lib/store/ResolverFragments.js +2 -2
- package/lib/subscription/requestSubscription.js +0 -2
- package/lib/util/withProvidedVariables.js +49 -0
- package/mutations/RelayDeclarativeMutationConfig.js.flow +0 -1
- package/mutations/commitMutation.js.flow +8 -19
- package/mutations/readUpdatableQuery_EXPERIMENTAL.js.flow +47 -49
- package/mutations/validateMutation.js.flow +14 -2
- package/network/RelayNetwork.js.flow +10 -3
- package/network/RelayNetworkTypes.js.flow +1 -1
- package/package.json +6 -2
- package/query/fetchQuery.js.flow +9 -7
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +3 -3
- package/store/RelayConcreteVariables.js.flow +12 -2
- package/store/RelayExperimentalGraphResponseTransform.js.flow +35 -1
- package/store/RelayModernOperationDescriptor.js.flow +5 -1
- package/store/RelayModernStore.js.flow +0 -1
- package/store/RelayPublishQueue.js.flow +8 -1
- package/store/RelayReader.js.flow +78 -31
- package/store/RelayStoreTypes.js.flow +3 -2
- package/store/RelayStoreUtils.js.flow +1 -0
- package/store/ResolverCache.js.flow +18 -5
- package/store/ResolverFragments.js.flow +2 -2
- package/subscription/requestSubscription.js.flow +7 -13
- package/util/NormalizationNode.js.flow +16 -16
- package/util/ReaderNode.js.flow +15 -15
- package/util/RelayConcreteNode.js.flow +4 -2
- package/util/withProvidedVariables.js.flow +64 -0
- package/lib/util/getAllRootVariables.js +0 -29
- package/util/getAllRootVariables.js.flow +0 -36
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
NormalizationOperation,
|
|
19
19
|
} from '../util/NormalizationNode';
|
|
20
20
|
import type {ReaderFragment} from '../util/ReaderNode';
|
|
21
|
+
import type {ProvidedVariablesType} from '../util/RelayConcreteNode';
|
|
21
22
|
import type {Variables} from '../util/RelayRuntimeTypes';
|
|
22
23
|
|
|
23
24
|
const {getArgumentValues} = require('./RelayStoreUtils');
|
|
@@ -76,12 +77,15 @@ function getFragmentVariables(
|
|
|
76
77
|
|
|
77
78
|
/**
|
|
78
79
|
* Determines the variables that are in scope for a given operation given values
|
|
79
|
-
* for some/all of its arguments.
|
|
80
|
-
*
|
|
80
|
+
* for some/all of its arguments.
|
|
81
|
+
* - extraneous input variables are filtered from the output
|
|
82
|
+
* - missing variables are set to default values (if given in the
|
|
81
83
|
* operation's definition).
|
|
84
|
+
* - variables with provider modules are added
|
|
82
85
|
*/
|
|
83
86
|
function getOperationVariables(
|
|
84
87
|
operation: NormalizationOperation,
|
|
88
|
+
providedVariables: ?ProvidedVariablesType,
|
|
85
89
|
variables: Variables,
|
|
86
90
|
): Variables {
|
|
87
91
|
const operationVariables = {};
|
|
@@ -92,6 +96,12 @@ function getOperationVariables(
|
|
|
92
96
|
}
|
|
93
97
|
operationVariables[def.name] = value;
|
|
94
98
|
});
|
|
99
|
+
|
|
100
|
+
if (providedVariables != null) {
|
|
101
|
+
Object.keys(providedVariables).forEach((varName: string) => {
|
|
102
|
+
operationVariables[varName] = providedVariables[varName].get();
|
|
103
|
+
});
|
|
104
|
+
}
|
|
95
105
|
return operationVariables;
|
|
96
106
|
}
|
|
97
107
|
|
|
@@ -31,7 +31,9 @@ const {
|
|
|
31
31
|
FRAGMENT_SPREAD,
|
|
32
32
|
INLINE_FRAGMENT,
|
|
33
33
|
LINKED_FIELD,
|
|
34
|
+
LINKED_HANDLE,
|
|
34
35
|
SCALAR_FIELD,
|
|
36
|
+
SCALAR_HANDLE,
|
|
35
37
|
} = require('../util/RelayConcreteNode');
|
|
36
38
|
const {getLocalVariables} = require('./RelayConcreteVariables');
|
|
37
39
|
const {createNormalizationSelector} = require('./RelayModernSelector');
|
|
@@ -91,6 +93,10 @@ export type GraphModeChunk = DataChunk | CompleteChunk;
|
|
|
91
93
|
|
|
92
94
|
export type GraphModeResponse = Iterable<GraphModeChunk>;
|
|
93
95
|
|
|
96
|
+
export type TransformMetadata = {
|
|
97
|
+
duplicateFieldsAvoided: number,
|
|
98
|
+
};
|
|
99
|
+
|
|
94
100
|
/**
|
|
95
101
|
* Converts a JSON response (and Normalization AST) into a stream of GraphMode chunks
|
|
96
102
|
*
|
|
@@ -128,7 +134,20 @@ export function normalizeResponse(
|
|
|
128
134
|
return normalizer.normalizeResponse(node, dataID, response);
|
|
129
135
|
}
|
|
130
136
|
|
|
131
|
-
|
|
137
|
+
export function normalizeResponseWithMetadata(
|
|
138
|
+
response: PayloadData,
|
|
139
|
+
selector: NormalizationSelector,
|
|
140
|
+
options: NormalizationOptions,
|
|
141
|
+
): [Array<GraphModeChunk>, TransformMetadata] {
|
|
142
|
+
const {node, variables, dataID} = selector;
|
|
143
|
+
const normalizer = new GraphModeNormalizer(variables, options);
|
|
144
|
+
const chunks = Array.from(
|
|
145
|
+
normalizer.normalizeResponse(node, dataID, response),
|
|
146
|
+
);
|
|
147
|
+
return [chunks, {duplicateFieldsAvoided: normalizer.duplicateFieldsAvoided}];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export class GraphModeNormalizer {
|
|
132
151
|
_cacheKeyToStreamID: Map<string, number>;
|
|
133
152
|
_sentFields: Map<string, Set<string>>;
|
|
134
153
|
_getDataId: GetDataID;
|
|
@@ -138,6 +157,7 @@ class GraphModeNormalizer {
|
|
|
138
157
|
_path: Array<string>;
|
|
139
158
|
_incrementalPlaceholders: Array<IncrementalDataPlaceholder>;
|
|
140
159
|
_actorIdentifier: ?ActorIdentifier;
|
|
160
|
+
duplicateFieldsAvoided: number;
|
|
141
161
|
constructor(variables: Variables, options: NormalizationOptions) {
|
|
142
162
|
this._actorIdentifier = options.actorIdentifier;
|
|
143
163
|
this._path = options.path ? [...options.path] : [];
|
|
@@ -146,6 +166,7 @@ class GraphModeNormalizer {
|
|
|
146
166
|
this._sentFields = new Map();
|
|
147
167
|
this._nextStreamID = 0;
|
|
148
168
|
this._variables = variables;
|
|
169
|
+
this.duplicateFieldsAvoided = 0;
|
|
149
170
|
}
|
|
150
171
|
|
|
151
172
|
_getStreamID() {
|
|
@@ -266,6 +287,7 @@ class GraphModeNormalizer {
|
|
|
266
287
|
// TODO: We could also opt to confirm that this matches the previously
|
|
267
288
|
// seen value.
|
|
268
289
|
if (sentFields.has(storageKey)) {
|
|
290
|
+
this.duplicateFieldsAvoided++;
|
|
269
291
|
break;
|
|
270
292
|
}
|
|
271
293
|
|
|
@@ -281,6 +303,7 @@ class GraphModeNormalizer {
|
|
|
281
303
|
// TODO: We could also opt to confirm that this matches the previously
|
|
282
304
|
// seen value.
|
|
283
305
|
if (sentFields.has(storageKey)) {
|
|
306
|
+
this.duplicateFieldsAvoided++;
|
|
284
307
|
break;
|
|
285
308
|
}
|
|
286
309
|
const fieldData = ((data[responseKey]: any): ChunkField);
|
|
@@ -374,6 +397,17 @@ class GraphModeNormalizer {
|
|
|
374
397
|
// Since we are only expecting to handle server responses, we can skip
|
|
375
398
|
// over client extensions.
|
|
376
399
|
break;
|
|
400
|
+
case SCALAR_HANDLE:
|
|
401
|
+
case LINKED_HANDLE:
|
|
402
|
+
// Handles allow us to record information that will be needed to
|
|
403
|
+
// perform additional process when we insert data into the store. For
|
|
404
|
+
// example, connection edges need to be prepended/appended to the
|
|
405
|
+
// pre-existing values.
|
|
406
|
+
//
|
|
407
|
+
// GraphMode will eventually need some replacement for this, but it is
|
|
408
|
+
// not nessesary in order to measure things like response size, so we
|
|
409
|
+
// can ignore these for now.
|
|
410
|
+
break;
|
|
377
411
|
default:
|
|
378
412
|
throw new Error(`Unexpected selection type: ${selection.kind}`);
|
|
379
413
|
}
|
|
@@ -44,7 +44,11 @@ function createOperationDescriptor<TQuery: OperationType>(
|
|
|
44
44
|
dataID?: DataID = ROOT_ID,
|
|
45
45
|
): OperationDescriptor {
|
|
46
46
|
const operation = request.operation;
|
|
47
|
-
const operationVariables = getOperationVariables(
|
|
47
|
+
const operationVariables = getOperationVariables(
|
|
48
|
+
operation,
|
|
49
|
+
request.params.providedVariables,
|
|
50
|
+
variables,
|
|
51
|
+
);
|
|
48
52
|
const requestDescriptor = createRequestDescriptor(
|
|
49
53
|
request,
|
|
50
54
|
operationVariables,
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
|
|
13
13
|
'use strict';
|
|
14
14
|
|
|
15
|
-
import type {ActorIdentifier} from '../multi-actor-environment/ActorIdentifier';
|
|
16
15
|
import type {DataID, Disposable} from '../util/RelayRuntimeTypes';
|
|
17
16
|
import type {Availability} from './DataChecker';
|
|
18
17
|
import type {GetDataID} from './RelayResponseNormalizer';
|
|
@@ -57,8 +57,15 @@ type PendingUpdater = {|
|
|
|
57
57
|
+updater: StoreUpdater,
|
|
58
58
|
|};
|
|
59
59
|
|
|
60
|
+
const _global: typeof global | $FlowFixMe =
|
|
61
|
+
typeof global !== 'undefined'
|
|
62
|
+
? global
|
|
63
|
+
: typeof window !== 'undefined'
|
|
64
|
+
? window
|
|
65
|
+
: undefined;
|
|
66
|
+
|
|
60
67
|
const applyWithGuard =
|
|
61
|
-
|
|
68
|
+
_global?.ErrorUtils?.applyWithGuard ??
|
|
62
69
|
((callback, context, args, onError, name) => callback.apply(context, args));
|
|
63
70
|
|
|
64
71
|
/**
|
|
@@ -109,6 +109,7 @@ class RelayReader {
|
|
|
109
109
|
_selector: SingularReaderSelector;
|
|
110
110
|
_variables: Variables;
|
|
111
111
|
_resolverCache: ResolverCache;
|
|
112
|
+
_fragmentName: string;
|
|
112
113
|
|
|
113
114
|
constructor(
|
|
114
115
|
recordSource: RecordSource,
|
|
@@ -130,6 +131,7 @@ class RelayReader {
|
|
|
130
131
|
this._selector = selector;
|
|
131
132
|
this._variables = selector.variables;
|
|
132
133
|
this._resolverCache = resolverCache;
|
|
134
|
+
this._fragmentName = selector.node.name;
|
|
133
135
|
}
|
|
134
136
|
|
|
135
137
|
read(): Snapshot {
|
|
@@ -267,7 +269,7 @@ class RelayReader {
|
|
|
267
269
|
// encounter is likely to be the root cause of the error.
|
|
268
270
|
return;
|
|
269
271
|
}
|
|
270
|
-
const owner = this.
|
|
272
|
+
const owner = this._fragmentName;
|
|
271
273
|
|
|
272
274
|
switch (action) {
|
|
273
275
|
case 'THROW':
|
|
@@ -275,9 +277,19 @@ class RelayReader {
|
|
|
275
277
|
return;
|
|
276
278
|
case 'LOG':
|
|
277
279
|
if (this._missingRequiredFields == null) {
|
|
278
|
-
this._missingRequiredFields = {
|
|
280
|
+
this._missingRequiredFields = {
|
|
281
|
+
action,
|
|
282
|
+
fields: [{path: fieldPath, owner}],
|
|
283
|
+
};
|
|
284
|
+
} else {
|
|
285
|
+
this._missingRequiredFields = {
|
|
286
|
+
action,
|
|
287
|
+
fields: [
|
|
288
|
+
...this._missingRequiredFields.fields,
|
|
289
|
+
{path: fieldPath, owner},
|
|
290
|
+
],
|
|
291
|
+
};
|
|
279
292
|
}
|
|
280
|
-
this._missingRequiredFields.fields.push({path: fieldPath, owner});
|
|
281
293
|
return;
|
|
282
294
|
default:
|
|
283
295
|
(action: empty);
|
|
@@ -483,8 +495,7 @@ class RelayReader {
|
|
|
483
495
|
if (!RelayFeatureFlags.ENABLE_RELAY_RESOLVERS) {
|
|
484
496
|
throw new Error('Relay Resolver fields are not yet supported.');
|
|
485
497
|
}
|
|
486
|
-
this._readResolverField(selection.field, record, data);
|
|
487
|
-
break;
|
|
498
|
+
return this._readResolverField(selection.field, record, data);
|
|
488
499
|
default:
|
|
489
500
|
(selection.field.kind: empty);
|
|
490
501
|
invariant(
|
|
@@ -499,7 +510,7 @@ class RelayReader {
|
|
|
499
510
|
field: ReaderRelayResolver,
|
|
500
511
|
record: Record,
|
|
501
512
|
data: SelectorData,
|
|
502
|
-
):
|
|
513
|
+
): mixed {
|
|
503
514
|
const {resolverModule, fragment} = field;
|
|
504
515
|
const storageKey = getStorageKey(field, this._variables);
|
|
505
516
|
const resolverID = ClientID.generateClientID(
|
|
@@ -512,6 +523,8 @@ class RelayReader {
|
|
|
512
523
|
// inputs have changed since a previous evaluation:
|
|
513
524
|
let fragmentValue;
|
|
514
525
|
let fragmentReaderSelector;
|
|
526
|
+
let fragmentMissingRequiredFields: ?MissingRequiredFields;
|
|
527
|
+
let previousMissingRequriedFields: ?MissingRequiredFields;
|
|
515
528
|
const fragmentSeenRecordIDs = new Set();
|
|
516
529
|
|
|
517
530
|
const getDataForResolverFragment = singularReaderSelector => {
|
|
@@ -526,11 +539,14 @@ class RelayReader {
|
|
|
526
539
|
try {
|
|
527
540
|
this._seenRecords = fragmentSeenRecordIDs;
|
|
528
541
|
const resolverFragmentData = {};
|
|
542
|
+
previousMissingRequriedFields = this._missingRequiredFields;
|
|
543
|
+
this._missingRequiredFields = null;
|
|
529
544
|
this._createInlineDataOrResolverFragmentPointer(
|
|
530
545
|
singularReaderSelector.node,
|
|
531
546
|
record,
|
|
532
547
|
resolverFragmentData,
|
|
533
548
|
);
|
|
549
|
+
fragmentMissingRequiredFields = this._missingRequiredFields;
|
|
534
550
|
fragmentValue = resolverFragmentData[FRAGMENTS_KEY]?.[fragment.name];
|
|
535
551
|
invariant(
|
|
536
552
|
typeof fragmentValue === 'object' && fragmentValue !== null,
|
|
@@ -539,42 +555,50 @@ class RelayReader {
|
|
|
539
555
|
return fragmentValue;
|
|
540
556
|
} finally {
|
|
541
557
|
this._seenRecords = existingSeenRecords;
|
|
558
|
+
this._missingRequiredFields = previousMissingRequriedFields;
|
|
542
559
|
}
|
|
543
560
|
};
|
|
544
561
|
const resolverContext = {getDataForResolverFragment};
|
|
545
562
|
|
|
546
|
-
const [result, seenRecord] =
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
return withResolverContext(resolverContext, () => {
|
|
559
|
-
// $FlowFixMe[prop-missing] - resolver module's type signature is a lie
|
|
560
|
-
const resolverResult = resolverModule(key);
|
|
561
|
-
return {
|
|
562
|
-
resolverResult,
|
|
563
|
-
fragmentValue,
|
|
564
|
-
resolverID,
|
|
565
|
-
seenRecordIDs: fragmentSeenRecordIDs,
|
|
566
|
-
readerSelector: fragmentReaderSelector,
|
|
563
|
+
const [result, seenRecord, missingRequiredFields] =
|
|
564
|
+
this._resolverCache.readFromCacheOrEvaluate(
|
|
565
|
+
record,
|
|
566
|
+
field,
|
|
567
|
+
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
|
+
},
|
|
567
575
|
};
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
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
|
+
},
|
|
589
|
+
getDataForResolverFragment,
|
|
590
|
+
);
|
|
591
|
+
|
|
592
|
+
if (missingRequiredFields != null) {
|
|
593
|
+
this._addMissingRequiredFields(missingRequiredFields);
|
|
594
|
+
}
|
|
572
595
|
if (seenRecord != null) {
|
|
573
596
|
this._seenRecords.add(seenRecord);
|
|
574
597
|
}
|
|
575
598
|
|
|
576
599
|
const applicationName = field.alias ?? field.name;
|
|
577
600
|
data[applicationName] = result;
|
|
601
|
+
return result;
|
|
578
602
|
}
|
|
579
603
|
|
|
580
604
|
_readClientEdge(
|
|
@@ -896,14 +920,37 @@ class RelayReader {
|
|
|
896
920
|
data[ID_KEY] = RelayModernRecord.getDataID(record);
|
|
897
921
|
}
|
|
898
922
|
const inlineData = {};
|
|
923
|
+
const parentFragmentName = this._fragmentName;
|
|
924
|
+
this._fragmentName = fragmentSpreadOrFragment.name;
|
|
899
925
|
this._traverseSelections(
|
|
900
926
|
fragmentSpreadOrFragment.selections,
|
|
901
927
|
record,
|
|
902
928
|
inlineData,
|
|
903
929
|
);
|
|
930
|
+
this._fragmentName = parentFragmentName;
|
|
904
931
|
// $FlowFixMe[cannot-write] - writing into read-only field
|
|
905
932
|
fragmentPointers[fragmentSpreadOrFragment.name] = inlineData;
|
|
906
933
|
}
|
|
934
|
+
|
|
935
|
+
_addMissingRequiredFields(additional: MissingRequiredFields) {
|
|
936
|
+
if (this._missingRequiredFields == null) {
|
|
937
|
+
this._missingRequiredFields = additional;
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
if (this._missingRequiredFields.action === 'THROW') {
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
if (additional.action === 'THROW') {
|
|
945
|
+
this._missingRequiredFields = additional;
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
this._missingRequiredFields = {
|
|
950
|
+
action: 'LOG',
|
|
951
|
+
fields: [...this._missingRequiredFields.fields, ...additional.fields],
|
|
952
|
+
};
|
|
953
|
+
}
|
|
907
954
|
}
|
|
908
955
|
|
|
909
956
|
module.exports = {read};
|
|
@@ -117,9 +117,10 @@ type MissingRequiredField = {|
|
|
|
117
117
|
owner: string,
|
|
118
118
|
|};
|
|
119
119
|
|
|
120
|
-
export type MissingRequiredFields =
|
|
120
|
+
export type MissingRequiredFields = $ReadOnly<
|
|
121
121
|
| {|action: 'THROW', field: MissingRequiredField|}
|
|
122
|
-
| {|action: 'LOG', fields: Array<MissingRequiredField>|}
|
|
122
|
+
| {|action: 'LOG', fields: Array<MissingRequiredField>|},
|
|
123
|
+
>;
|
|
123
124
|
|
|
124
125
|
export type ClientEdgeTraversalInfo = {|
|
|
125
126
|
+readerClientEdge: ReaderClientEdge,
|
|
@@ -219,6 +219,7 @@ const RelayStoreUtils = {
|
|
|
219
219
|
RELAY_RESOLVER_INVALIDATION_KEY: '__resolverValueMayBeInvalid',
|
|
220
220
|
RELAY_RESOLVER_INPUTS_KEY: '__resolverInputValues',
|
|
221
221
|
RELAY_RESOLVER_READER_SELECTOR_KEY: '__resolverReaderSelector',
|
|
222
|
+
RELAY_RESOLVER_MISSING_REQUIRED_FIELDS_KEY: '__resolverMissingRequiredFields',
|
|
222
223
|
|
|
223
224
|
formatStorageKey,
|
|
224
225
|
getArgumentValue,
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import type {ReaderRelayResolver} from '../util/ReaderNode';
|
|
16
16
|
import type {DataID, Variables} from '../util/RelayRuntimeTypes';
|
|
17
17
|
import type {
|
|
18
|
+
MissingRequiredFields,
|
|
18
19
|
MutableRecordSource,
|
|
19
20
|
Record,
|
|
20
21
|
SingularReaderSelector,
|
|
@@ -26,6 +27,7 @@ const RelayModernRecord = require('./RelayModernRecord');
|
|
|
26
27
|
const {
|
|
27
28
|
RELAY_RESOLVER_INPUTS_KEY,
|
|
28
29
|
RELAY_RESOLVER_INVALIDATION_KEY,
|
|
30
|
+
RELAY_RESOLVER_MISSING_REQUIRED_FIELDS_KEY,
|
|
29
31
|
RELAY_RESOLVER_READER_SELECTOR_KEY,
|
|
30
32
|
RELAY_RESOLVER_VALUE_KEY,
|
|
31
33
|
getStorageKey,
|
|
@@ -40,6 +42,7 @@ type EvaluationResult<T> = {|
|
|
|
40
42
|
resolverID: ResolverID,
|
|
41
43
|
seenRecordIDs: Set<DataID>,
|
|
42
44
|
readerSelector: SingularReaderSelector,
|
|
45
|
+
missingRequiredFields: ?MissingRequiredFields,
|
|
43
46
|
|};
|
|
44
47
|
|
|
45
48
|
export interface ResolverCache {
|
|
@@ -49,7 +52,7 @@ export interface ResolverCache {
|
|
|
49
52
|
variables: Variables,
|
|
50
53
|
evaluate: () => EvaluationResult<T>,
|
|
51
54
|
getDataForResolverFragment: (SingularReaderSelector) => mixed,
|
|
52
|
-
): [T /* Answer */, ?DataID /* Seen record
|
|
55
|
+
): [T /* Answer */, ?DataID /* Seen record */, ?MissingRequiredFields];
|
|
53
56
|
invalidateDataIDs(
|
|
54
57
|
updatedDataIDs: Set<DataID>, // Mutated in place
|
|
55
58
|
): void;
|
|
@@ -65,8 +68,9 @@ class NoopResolverCache implements ResolverCache {
|
|
|
65
68
|
variables: Variables,
|
|
66
69
|
evaluate: () => EvaluationResult<T>,
|
|
67
70
|
getDataForResolverFragment: SingularReaderSelector => mixed,
|
|
68
|
-
): [T /* Answer */, ?DataID /* Seen record
|
|
69
|
-
|
|
71
|
+
): [T /* Answer */, ?DataID /* Seen record */, ?MissingRequiredFields] {
|
|
72
|
+
const {resolverResult, missingRequiredFields} = evaluate();
|
|
73
|
+
return [resolverResult, undefined, missingRequiredFields];
|
|
70
74
|
}
|
|
71
75
|
invalidateDataIDs(updatedDataIDs: Set<DataID>): void {}
|
|
72
76
|
}
|
|
@@ -102,7 +106,7 @@ class RecordResolverCache implements ResolverCache {
|
|
|
102
106
|
variables: Variables,
|
|
103
107
|
evaluate: () => EvaluationResult<T>,
|
|
104
108
|
getDataForResolverFragment: SingularReaderSelector => mixed,
|
|
105
|
-
): [T /* Answer */, ?DataID /* Seen record
|
|
109
|
+
): [T /* Answer */, ?DataID /* Seen record */, ?MissingRequiredFields] {
|
|
106
110
|
const recordSource = this._getRecordSource();
|
|
107
111
|
const recordID = RelayModernRecord.getDataID(record);
|
|
108
112
|
|
|
@@ -133,6 +137,11 @@ class RecordResolverCache implements ResolverCache {
|
|
|
133
137
|
RELAY_RESOLVER_READER_SELECTOR_KEY,
|
|
134
138
|
evaluationResult.readerSelector,
|
|
135
139
|
);
|
|
140
|
+
RelayModernRecord.setValue(
|
|
141
|
+
linkedRecord,
|
|
142
|
+
RELAY_RESOLVER_MISSING_REQUIRED_FIELDS_KEY,
|
|
143
|
+
evaluationResult.missingRequiredFields,
|
|
144
|
+
);
|
|
136
145
|
recordSource.set(linkedID, linkedRecord);
|
|
137
146
|
|
|
138
147
|
// Link the resolver value record to the resolver field of the record being read:
|
|
@@ -155,7 +164,11 @@ class RecordResolverCache implements ResolverCache {
|
|
|
155
164
|
|
|
156
165
|
// $FlowFixMe[incompatible-type] - will always be empty
|
|
157
166
|
const answer: T = linkedRecord[RELAY_RESOLVER_VALUE_KEY];
|
|
158
|
-
|
|
167
|
+
|
|
168
|
+
const missingRequiredFields: ?MissingRequiredFields =
|
|
169
|
+
// $FlowFixMe[incompatible-type] - casting mixed
|
|
170
|
+
linkedRecord[RELAY_RESOLVER_MISSING_REQUIRED_FIELDS_KEY];
|
|
171
|
+
return [answer, linkedID, missingRequiredFields];
|
|
159
172
|
}
|
|
160
173
|
|
|
161
174
|
invalidateDataIDs(
|
|
@@ -42,9 +42,9 @@ function withResolverContext<T>(context: ResolverContext, cb: () => T): T {
|
|
|
42
42
|
// The declarations ensure that the type of the returned data is:
|
|
43
43
|
// - non-nullable if the provided ref type is non-nullable
|
|
44
44
|
// - nullable if the provided ref type is nullable
|
|
45
|
-
// - array of non-nullable if the
|
|
45
|
+
// - array of non-nullable if the provided ref type is an array of
|
|
46
46
|
// non-nullable refs
|
|
47
|
-
// - array of nullable if the
|
|
47
|
+
// - array of nullable if the provided ref type is an array of nullable refs
|
|
48
48
|
|
|
49
49
|
declare function readFragment<
|
|
50
50
|
TKey: {+$data?: mixed, +$fragmentSpreads: FragmentType, ...},
|
|
@@ -30,12 +30,11 @@ const {
|
|
|
30
30
|
createOperationDescriptor,
|
|
31
31
|
} = require('../store/RelayModernOperationDescriptor');
|
|
32
32
|
const {createReaderSelector} = require('../store/RelayModernSelector');
|
|
33
|
-
const RelayFeatureFlags = require('../util/RelayFeatureFlags');
|
|
34
33
|
const warning = require('warning');
|
|
35
34
|
|
|
36
35
|
export type SubscriptionParameters = {|
|
|
37
36
|
+response: {...},
|
|
38
|
-
+variables:
|
|
37
|
+
+variables: {...},
|
|
39
38
|
+rawResponse?: {...},
|
|
40
39
|
|};
|
|
41
40
|
|
|
@@ -50,18 +49,13 @@ export type GraphQLSubscriptionConfig<T: SubscriptionParameters> = {|
|
|
|
50
49
|
updater?: ?SelectorStoreUpdater<T['response']>,
|
|
51
50
|
|};
|
|
52
51
|
|
|
53
|
-
export type DEPRECATED_GraphQLSubscriptionConfig<TSubscriptionPayload> =
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
onCompleted?: ?() => void,
|
|
59
|
-
onError?: ?(error: Error) => void,
|
|
60
|
-
onNext?: ?(response: ?TSubscriptionPayload) => void,
|
|
61
|
-
updater?: ?SelectorStoreUpdater<TSubscriptionPayload>,
|
|
62
|
-
|};
|
|
52
|
+
export type DEPRECATED_GraphQLSubscriptionConfig<TSubscriptionPayload: {...}> =
|
|
53
|
+
GraphQLSubscriptionConfig<{|
|
|
54
|
+
response: TSubscriptionPayload,
|
|
55
|
+
variables: Variables,
|
|
56
|
+
|}>;
|
|
63
57
|
|
|
64
|
-
function requestSubscription<TSubscriptionPayload>(
|
|
58
|
+
function requestSubscription<TSubscriptionPayload: {...}>(
|
|
65
59
|
environment: IEnvironment,
|
|
66
60
|
config: DEPRECATED_GraphQLSubscriptionConfig<TSubscriptionPayload>,
|
|
67
61
|
): Disposable {
|
|
@@ -31,27 +31,27 @@ export type NormalizationHandle =
|
|
|
31
31
|
|
|
32
32
|
export type NormalizationLinkedHandle = {|
|
|
33
33
|
+kind: 'LinkedHandle',
|
|
34
|
-
+alias
|
|
34
|
+
+alias?: ?string,
|
|
35
35
|
+name: string,
|
|
36
|
-
+args
|
|
36
|
+
+args?: ?$ReadOnlyArray<NormalizationArgument>,
|
|
37
37
|
+handle: string,
|
|
38
38
|
+key: string,
|
|
39
39
|
// NOTE: this property is optional because it's expected to be rarely used
|
|
40
40
|
+dynamicKey?: ?NormalizationArgument,
|
|
41
|
-
+filters
|
|
41
|
+
+filters?: ?$ReadOnlyArray<string>,
|
|
42
42
|
+handleArgs?: $ReadOnlyArray<NormalizationArgument>,
|
|
43
43
|
|};
|
|
44
44
|
|
|
45
45
|
export type NormalizationScalarHandle = {|
|
|
46
46
|
+kind: 'ScalarHandle',
|
|
47
|
-
+alias
|
|
47
|
+
+alias?: ?string,
|
|
48
48
|
+name: string,
|
|
49
|
-
+args
|
|
49
|
+
+args?: ?$ReadOnlyArray<NormalizationArgument>,
|
|
50
50
|
+handle: string,
|
|
51
51
|
+key: string,
|
|
52
52
|
// NOTE: this property is optional because it's expected to be rarely used
|
|
53
53
|
+dynamicKey?: ?NormalizationArgument,
|
|
54
|
-
+filters
|
|
54
|
+
+filters?: ?$ReadOnlyArray<string>,
|
|
55
55
|
+handleArgs?: $ReadOnlyArray<NormalizationArgument>,
|
|
56
56
|
|};
|
|
57
57
|
|
|
@@ -82,22 +82,22 @@ export type NormalizationInlineFragment = {|
|
|
|
82
82
|
+kind: 'InlineFragment',
|
|
83
83
|
+selections: $ReadOnlyArray<NormalizationSelection>,
|
|
84
84
|
+type: string,
|
|
85
|
-
+abstractKey
|
|
85
|
+
+abstractKey?: ?string,
|
|
86
86
|
|};
|
|
87
87
|
|
|
88
88
|
export type NormalizationFragmentSpread = {|
|
|
89
89
|
+kind: 'FragmentSpread',
|
|
90
90
|
+fragment: NormalizationSplitOperation,
|
|
91
|
-
+args
|
|
91
|
+
+args?: ?$ReadOnlyArray<NormalizationArgument>,
|
|
92
92
|
|};
|
|
93
93
|
|
|
94
94
|
export type NormalizationLinkedField = {|
|
|
95
95
|
+kind: 'LinkedField',
|
|
96
|
-
+alias
|
|
96
|
+
+alias?: ?string,
|
|
97
97
|
+name: string,
|
|
98
|
-
+storageKey
|
|
99
|
-
+args
|
|
100
|
-
+concreteType
|
|
98
|
+
+storageKey?: ?string,
|
|
99
|
+
+args?: ?$ReadOnlyArray<NormalizationArgument>,
|
|
100
|
+
+concreteType?: ?string,
|
|
101
101
|
+plural: boolean,
|
|
102
102
|
+selections: $ReadOnlyArray<NormalizationSelection>,
|
|
103
103
|
|};
|
|
@@ -108,7 +108,7 @@ export type NormalizationActorChange = {|
|
|
|
108
108
|
|};
|
|
109
109
|
|
|
110
110
|
export type NormalizationModuleImport = {|
|
|
111
|
-
+args
|
|
111
|
+
+args?: ?$ReadOnlyArray<NormalizationArgument>,
|
|
112
112
|
+kind: 'ModuleImport',
|
|
113
113
|
+documentName: string,
|
|
114
114
|
+fragmentPropName: string,
|
|
@@ -146,10 +146,10 @@ export type NormalizationNode =
|
|
|
146
146
|
|
|
147
147
|
export type NormalizationScalarField = {|
|
|
148
148
|
+kind: 'ScalarField',
|
|
149
|
-
+alias
|
|
149
|
+
+alias?: ?string,
|
|
150
150
|
+name: string,
|
|
151
|
-
+args
|
|
152
|
-
+storageKey
|
|
151
|
+
+args?: ?$ReadOnlyArray<NormalizationArgument>,
|
|
152
|
+
+storageKey?: ?string,
|
|
153
153
|
|};
|
|
154
154
|
|
|
155
155
|
export type NormalizationFlightField = {|
|