relay-runtime 7.0.0 → 9.1.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.
Files changed (157) hide show
  1. package/handlers/RelayDefaultHandlerProvider.js.flow +34 -0
  2. package/handlers/connection/ConnectionHandler.js.flow +549 -0
  3. package/handlers/connection/ConnectionInterface.js.flow +92 -0
  4. package/index.js +1 -1
  5. package/index.js.flow +314 -0
  6. package/lib/handlers/RelayDefaultHandlerProvider.js +3 -2
  7. package/lib/handlers/connection/{RelayConnectionHandler.js → ConnectionHandler.js} +34 -35
  8. package/lib/handlers/connection/{RelayConnectionInterface.js → ConnectionInterface.js} +3 -30
  9. package/lib/index.js +29 -27
  10. package/lib/mutations/RelayDeclarativeMutationConfig.js +30 -52
  11. package/lib/mutations/RelayRecordProxy.js +6 -3
  12. package/lib/mutations/RelayRecordSourceMutator.js +3 -9
  13. package/lib/mutations/RelayRecordSourceProxy.js +21 -24
  14. package/lib/mutations/RelayRecordSourceSelectorProxy.js +18 -14
  15. package/lib/mutations/applyOptimisticMutation.js +2 -1
  16. package/lib/mutations/commitLocalUpdate.js +1 -0
  17. package/lib/mutations/commitMutation.js +26 -8
  18. package/lib/mutations/validateMutation.js +21 -11
  19. package/lib/network/ConvertToExecuteFunction.js +1 -0
  20. package/lib/network/RelayNetwork.js +1 -0
  21. package/lib/network/RelayNetworkTypes.js +1 -0
  22. package/lib/network/RelayObservable.js +10 -9
  23. package/lib/network/RelayQueryResponseCache.js +9 -7
  24. package/lib/query/{RelayModernGraphQLTag.js → GraphQLTag.js} +15 -8
  25. package/lib/query/fetchQuery.js +2 -1
  26. package/lib/query/fetchQueryInternal.js +30 -20
  27. package/lib/store/ClientID.js +1 -0
  28. package/lib/store/DataChecker.js +47 -97
  29. package/lib/store/RelayConcreteVariables.js +7 -2
  30. package/lib/store/RelayModernEnvironment.js +82 -41
  31. package/lib/store/RelayModernFragmentSpecResolver.js +61 -21
  32. package/lib/store/RelayModernOperationDescriptor.js +2 -1
  33. package/lib/store/RelayModernQueryExecutor.js +476 -333
  34. package/lib/store/RelayModernRecord.js +39 -9
  35. package/lib/store/RelayModernSelector.js +2 -1
  36. package/lib/store/RelayModernStore.js +359 -371
  37. package/lib/store/RelayOperationTracker.js +36 -78
  38. package/lib/store/RelayOptimisticRecordSource.js +8 -5
  39. package/lib/store/RelayPublishQueue.js +66 -53
  40. package/lib/store/RelayReader.js +2 -24
  41. package/lib/store/RelayRecordSource.js +3 -9
  42. package/lib/store/RelayRecordSourceMapImpl.js +14 -18
  43. package/lib/store/RelayRecordState.js +1 -0
  44. package/lib/store/RelayReferenceMarker.js +8 -58
  45. package/lib/store/RelayResponseNormalizer.js +15 -144
  46. package/lib/store/RelayStoreTypes.js +1 -0
  47. package/lib/store/RelayStoreUtils.js +34 -10
  48. package/lib/store/StoreInspector.js +11 -5
  49. package/lib/store/ViewerPattern.js +1 -0
  50. package/lib/store/cloneRelayHandleSourceField.js +1 -0
  51. package/lib/store/createFragmentSpecResolver.js +1 -0
  52. package/lib/store/createRelayContext.js +1 -0
  53. package/lib/store/defaultGetDataID.js +1 -0
  54. package/lib/store/hasOverlappingIDs.js +1 -0
  55. package/lib/store/isRelayModernEnvironment.js +1 -0
  56. package/lib/store/normalizeRelayPayload.js +8 -4
  57. package/lib/store/readInlineData.js +2 -1
  58. package/lib/subscription/requestSubscription.js +6 -3
  59. package/lib/util/JSResourceTypes.flow.js +12 -0
  60. package/lib/util/NormalizationNode.js +1 -0
  61. package/lib/util/ReaderNode.js +1 -0
  62. package/lib/util/RelayConcreteNode.js +3 -0
  63. package/lib/util/RelayDefaultHandleKey.js +1 -0
  64. package/lib/util/RelayError.js +2 -1
  65. package/lib/util/RelayFeatureFlags.js +3 -2
  66. package/lib/util/RelayProfiler.js +1 -0
  67. package/lib/util/RelayReplaySubject.js +2 -3
  68. package/lib/util/RelayRuntimeTypes.js +1 -0
  69. package/lib/util/createPayloadFor3DField.js +34 -0
  70. package/lib/util/deepFreeze.js +1 -0
  71. package/lib/util/generateID.js +1 -0
  72. package/lib/util/getFragmentIdentifier.js +1 -0
  73. package/lib/util/getRelayHandleKey.js +1 -0
  74. package/lib/util/getRequestIdentifier.js +1 -0
  75. package/lib/util/isPromise.js +1 -0
  76. package/lib/util/isScalarAndEqual.js +1 -0
  77. package/lib/util/recycleNodesInto.js +1 -0
  78. package/lib/util/resolveImmediate.js +1 -0
  79. package/lib/util/stableCopy.js +1 -0
  80. package/mutations/RelayDeclarativeMutationConfig.js.flow +380 -0
  81. package/mutations/RelayRecordProxy.js.flow +165 -0
  82. package/mutations/RelayRecordSourceMutator.js.flow +238 -0
  83. package/mutations/RelayRecordSourceProxy.js.flow +164 -0
  84. package/mutations/RelayRecordSourceSelectorProxy.js.flow +119 -0
  85. package/mutations/applyOptimisticMutation.js.flow +76 -0
  86. package/mutations/commitLocalUpdate.js.flow +24 -0
  87. package/mutations/commitMutation.js.flow +184 -0
  88. package/mutations/validateMutation.js.flow +211 -0
  89. package/network/ConvertToExecuteFunction.js.flow +49 -0
  90. package/network/RelayNetwork.js.flow +84 -0
  91. package/network/RelayNetworkTypes.js.flow +123 -0
  92. package/network/RelayObservable.js.flow +634 -0
  93. package/network/RelayQueryResponseCache.js.flow +111 -0
  94. package/package.json +1 -1
  95. package/query/GraphQLTag.js.flow +166 -0
  96. package/query/fetchQuery.js.flow +47 -0
  97. package/query/fetchQueryInternal.js.flow +349 -0
  98. package/relay-runtime.js +2 -2
  99. package/relay-runtime.min.js +2 -2
  100. package/store/ClientID.js.flow +43 -0
  101. package/store/DataChecker.js.flow +426 -0
  102. package/store/RelayConcreteVariables.js.flow +96 -0
  103. package/store/RelayModernEnvironment.js.flow +526 -0
  104. package/store/RelayModernFragmentSpecResolver.js.flow +426 -0
  105. package/store/RelayModernOperationDescriptor.js.flow +88 -0
  106. package/store/RelayModernQueryExecutor.js.flow +1327 -0
  107. package/store/RelayModernRecord.js.flow +403 -0
  108. package/store/RelayModernSelector.js.flow +444 -0
  109. package/store/RelayModernStore.js.flow +757 -0
  110. package/store/RelayOperationTracker.js.flow +164 -0
  111. package/store/RelayOptimisticRecordSource.js.flow +119 -0
  112. package/store/RelayPublishQueue.js.flow +401 -0
  113. package/store/RelayReader.js.flow +376 -0
  114. package/store/RelayRecordSource.js.flow +29 -0
  115. package/store/RelayRecordSourceMapImpl.js.flow +87 -0
  116. package/store/RelayRecordState.js.flow +37 -0
  117. package/store/RelayReferenceMarker.js.flow +236 -0
  118. package/store/RelayResponseNormalizer.js.flow +556 -0
  119. package/store/RelayStoreTypes.js.flow +873 -0
  120. package/store/RelayStoreUtils.js.flow +218 -0
  121. package/store/StoreInspector.js.flow +173 -0
  122. package/store/ViewerPattern.js.flow +26 -0
  123. package/store/cloneRelayHandleSourceField.js.flow +66 -0
  124. package/store/createFragmentSpecResolver.js.flow +55 -0
  125. package/store/createRelayContext.js.flow +44 -0
  126. package/store/defaultGetDataID.js.flow +27 -0
  127. package/store/hasOverlappingIDs.js.flow +34 -0
  128. package/store/isRelayModernEnvironment.js.flow +27 -0
  129. package/store/normalizeRelayPayload.js.flow +51 -0
  130. package/store/readInlineData.js.flow +75 -0
  131. package/subscription/requestSubscription.js.flow +100 -0
  132. package/util/JSResourceTypes.flow.js.flow +20 -0
  133. package/util/NormalizationNode.js.flow +191 -0
  134. package/util/ReaderNode.js.flow +208 -0
  135. package/util/RelayConcreteNode.js.flow +80 -0
  136. package/util/RelayDefaultHandleKey.js.flow +17 -0
  137. package/util/RelayError.js.flow +33 -0
  138. package/util/RelayFeatureFlags.js.flow +30 -0
  139. package/util/RelayProfiler.js.flow +284 -0
  140. package/util/RelayReplaySubject.js.flow +134 -0
  141. package/util/RelayRuntimeTypes.js.flow +70 -0
  142. package/util/createPayloadFor3DField.js.flow +43 -0
  143. package/util/deepFreeze.js.flow +36 -0
  144. package/util/generateID.js.flow +21 -0
  145. package/util/getFragmentIdentifier.js.flow +52 -0
  146. package/util/getRelayHandleKey.js.flow +41 -0
  147. package/util/getRequestIdentifier.js.flow +41 -0
  148. package/util/isPromise.js.flow +21 -0
  149. package/util/isScalarAndEqual.js.flow +26 -0
  150. package/util/recycleNodesInto.js.flow +80 -0
  151. package/util/resolveImmediate.js.flow +30 -0
  152. package/util/stableCopy.js.flow +35 -0
  153. package/lib/handlers/RelayDefaultMissingFieldHandlers.js +0 -26
  154. package/lib/store/RelayConnection.js +0 -36
  155. package/lib/store/RelayConnectionResolver.js +0 -177
  156. package/lib/store/RelayRecordSourceObjectImpl.js +0 -78
  157. package/lib/util/getFragmentSpecIdentifier.js +0 -26
@@ -0,0 +1,76 @@
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
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+
13
+ 'use strict';
14
+
15
+ const RelayDeclarativeMutationConfig = require('./RelayDeclarativeMutationConfig');
16
+
17
+ const invariant = require('invariant');
18
+ const isRelayModernEnvironment = require('../store/isRelayModernEnvironment');
19
+
20
+ const {getRequest} = require('../query/GraphQLTag');
21
+ const {
22
+ createOperationDescriptor,
23
+ } = require('../store/RelayModernOperationDescriptor');
24
+
25
+ import type {GraphQLTaggedNode} from '../query/GraphQLTag';
26
+ import type {
27
+ IEnvironment,
28
+ SelectorStoreUpdater,
29
+ } from '../store/RelayStoreTypes';
30
+ import type {Disposable, Variables} from '../util/RelayRuntimeTypes';
31
+ import type {DeclarativeMutationConfig} from './RelayDeclarativeMutationConfig';
32
+
33
+ export type OptimisticMutationConfig = {|
34
+ configs?: ?Array<DeclarativeMutationConfig>,
35
+ mutation: GraphQLTaggedNode,
36
+ variables: Variables,
37
+ optimisticUpdater?: ?SelectorStoreUpdater,
38
+ optimisticResponse?: Object,
39
+ |};
40
+
41
+ /**
42
+ * Higher-level helper function to execute a mutation against a specific
43
+ * environment.
44
+ */
45
+ function applyOptimisticMutation(
46
+ environment: IEnvironment,
47
+ config: OptimisticMutationConfig,
48
+ ): Disposable {
49
+ invariant(
50
+ isRelayModernEnvironment(environment),
51
+ 'commitMutation: expected `environment` to be an instance of ' +
52
+ '`RelayModernEnvironment`.',
53
+ );
54
+ const mutation = getRequest(config.mutation);
55
+ if (mutation.params.operationKind !== 'mutation') {
56
+ throw new Error('commitMutation: Expected mutation operation');
57
+ }
58
+ let {optimisticUpdater} = config;
59
+ const {configs, optimisticResponse, variables} = config;
60
+ const operation = createOperationDescriptor(mutation, variables);
61
+ if (configs) {
62
+ ({optimisticUpdater} = RelayDeclarativeMutationConfig.convert(
63
+ configs,
64
+ mutation,
65
+ optimisticUpdater,
66
+ ));
67
+ }
68
+
69
+ return environment.applyMutation({
70
+ operation,
71
+ response: optimisticResponse,
72
+ updater: optimisticUpdater,
73
+ });
74
+ }
75
+
76
+ module.exports = applyOptimisticMutation;
@@ -0,0 +1,24 @@
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
+ import type {StoreUpdater, IEnvironment} from '../store/RelayStoreTypes';
16
+
17
+ function commitLocalUpdate(
18
+ environment: IEnvironment,
19
+ updater: StoreUpdater,
20
+ ): void {
21
+ environment.commitUpdate(updater);
22
+ }
23
+
24
+ module.exports = commitLocalUpdate;
@@ -0,0 +1,184 @@
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
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+
13
+ 'use strict';
14
+
15
+ const RelayDeclarativeMutationConfig = require('./RelayDeclarativeMutationConfig');
16
+ const RelayFeatureFlags = require('../util/RelayFeatureFlags');
17
+
18
+ const invariant = require('invariant');
19
+ const isRelayModernEnvironment = require('../store/isRelayModernEnvironment');
20
+ const validateMutation = require('./validateMutation');
21
+ const warning = require('warning');
22
+
23
+ const {getRequest} = require('../query/GraphQLTag');
24
+ const {generateUniqueClientID} = require('../store/ClientID');
25
+ const {
26
+ createOperationDescriptor,
27
+ } = require('../store/RelayModernOperationDescriptor');
28
+
29
+ import type {PayloadError, UploadableMap} from '../network/RelayNetworkTypes';
30
+ import type {GraphQLTaggedNode} from '../query/GraphQLTag';
31
+ import type {
32
+ IEnvironment,
33
+ SelectorStoreUpdater,
34
+ } from '../store/RelayStoreTypes';
35
+ import type {
36
+ CacheConfig,
37
+ Disposable,
38
+ Variables,
39
+ } from '../util/RelayRuntimeTypes';
40
+ import type {DeclarativeMutationConfig} from './RelayDeclarativeMutationConfig';
41
+
42
+ export type DEPRECATED_MutationConfig<T> = {|
43
+ configs?: Array<DeclarativeMutationConfig>,
44
+ cacheConfig?: CacheConfig,
45
+ mutation: GraphQLTaggedNode,
46
+ variables: Variables,
47
+ uploadables?: UploadableMap,
48
+ onCompleted?: ?(response: T, errors: ?Array<PayloadError>) => void,
49
+ onError?: ?(error: Error) => void,
50
+ onUnsubscribe?: ?() => void,
51
+ optimisticUpdater?: ?SelectorStoreUpdater,
52
+ optimisticResponse?: Object,
53
+ updater?: ?SelectorStoreUpdater,
54
+ |};
55
+
56
+ export type MutationParameters = {|
57
+ +response: {...},
58
+ +variables: {...},
59
+ +rawResponse?: {...},
60
+ |};
61
+
62
+ export type MutationConfig<T: MutationParameters> = {|
63
+ configs?: Array<DeclarativeMutationConfig>,
64
+ cacheConfig?: CacheConfig,
65
+ mutation: GraphQLTaggedNode,
66
+ onError?: ?(error: Error) => void,
67
+ onCompleted?: ?(
68
+ response: $ElementType<T, 'response'>,
69
+ errors: ?Array<PayloadError>,
70
+ ) => void,
71
+ onUnsubscribe?: ?() => void,
72
+ optimisticResponse?: $ElementType<
73
+ {
74
+ +rawResponse?: {...},
75
+ ...T,
76
+ ...
77
+ },
78
+ 'rawResponse',
79
+ >,
80
+ optimisticUpdater?: ?SelectorStoreUpdater,
81
+ updater?: ?SelectorStoreUpdater,
82
+ uploadables?: UploadableMap,
83
+ variables: $ElementType<T, 'variables'>,
84
+ |};
85
+
86
+ /**
87
+ * Higher-level helper function to execute a mutation against a specific
88
+ * environment.
89
+ */
90
+ function commitMutation<T: MutationParameters>(
91
+ environment: IEnvironment,
92
+ config: MutationConfig<T>,
93
+ ): Disposable {
94
+ invariant(
95
+ isRelayModernEnvironment(environment),
96
+ 'commitMutation: expected `environment` to be an instance of ' +
97
+ '`RelayModernEnvironment`.',
98
+ );
99
+ const mutation = getRequest(config.mutation);
100
+ if (mutation.params.operationKind !== 'mutation') {
101
+ throw new Error('commitMutation: Expected mutation operation');
102
+ }
103
+ if (mutation.kind !== 'Request') {
104
+ throw new Error('commitMutation: Expected mutation to be of type request');
105
+ }
106
+ let {optimisticResponse, optimisticUpdater, updater} = config;
107
+ const {
108
+ configs,
109
+ cacheConfig,
110
+ onError,
111
+ onUnsubscribe,
112
+ variables,
113
+ uploadables,
114
+ } = config;
115
+ const operation = createOperationDescriptor(
116
+ mutation,
117
+ variables,
118
+ RelayFeatureFlags.ENABLE_UNIQUE_MUTATION_ROOT
119
+ ? generateUniqueClientID()
120
+ : undefined,
121
+ );
122
+ // TODO: remove this check after we fix flow.
123
+ if (typeof optimisticResponse === 'function') {
124
+ optimisticResponse = optimisticResponse();
125
+ warning(
126
+ false,
127
+ 'commitMutation: Expected `optimisticResponse` to be an object, ' +
128
+ 'received a function.',
129
+ );
130
+ }
131
+ if (__DEV__) {
132
+ if (optimisticResponse instanceof Object) {
133
+ validateMutation(optimisticResponse, mutation, variables);
134
+ }
135
+ }
136
+ if (configs) {
137
+ ({optimisticUpdater, updater} = RelayDeclarativeMutationConfig.convert(
138
+ configs,
139
+ mutation,
140
+ optimisticUpdater,
141
+ updater,
142
+ ));
143
+ }
144
+ const errors = [];
145
+ const subscription = environment
146
+ .executeMutation({
147
+ cacheConfig,
148
+ operation,
149
+ optimisticResponse,
150
+ optimisticUpdater,
151
+ updater,
152
+ uploadables,
153
+ })
154
+ .subscribe({
155
+ next: payload => {
156
+ if (Array.isArray(payload)) {
157
+ payload.forEach(item => {
158
+ if (item.errors) {
159
+ errors.push(...item.errors);
160
+ }
161
+ });
162
+ } else {
163
+ if (payload.errors) {
164
+ errors.push(...payload.errors);
165
+ }
166
+ }
167
+ },
168
+ complete: () => {
169
+ const {onCompleted} = config;
170
+ if (onCompleted) {
171
+ const snapshot = environment.lookup(operation.fragment);
172
+ onCompleted(
173
+ (snapshot.data: $FlowFixMe),
174
+ errors.length !== 0 ? errors : null,
175
+ );
176
+ }
177
+ },
178
+ error: onError,
179
+ unsubscribe: onUnsubscribe,
180
+ });
181
+ return {dispose: subscription.unsubscribe};
182
+ }
183
+
184
+ module.exports = commitMutation;
@@ -0,0 +1,211 @@
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
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+
13
+ 'use strict';
14
+
15
+ import type {
16
+ NormalizationSelection,
17
+ NormalizationField,
18
+ } from '../util/NormalizationNode';
19
+ import type {ConcreteRequest} from '../util/RelayConcreteNode';
20
+ import type {Variables} from '../util/RelayRuntimeTypes';
21
+
22
+ type ValidationContext = {
23
+ visitedPaths: Set<string>,
24
+ path: string,
25
+ variables: Variables,
26
+ missingDiff: Object,
27
+ extraDiff: Object,
28
+ ...
29
+ };
30
+ const warning = require('warning');
31
+
32
+ let validateMutation = () => {};
33
+ if (__DEV__) {
34
+ const addFieldToDiff = (path: string, diff: Object, isScalar) => {
35
+ let deepLoc = diff;
36
+ path.split('.').forEach((key, index, arr) => {
37
+ if (deepLoc[key] == null) {
38
+ deepLoc[key] = {};
39
+ }
40
+ if (isScalar && index === arr.length - 1) {
41
+ deepLoc[key] = '<scalar>';
42
+ }
43
+ deepLoc = deepLoc[key];
44
+ });
45
+ };
46
+ validateMutation = (
47
+ optimisticResponse: Object,
48
+ mutation: ConcreteRequest,
49
+ variables: ?Object,
50
+ ) => {
51
+ const operationName = mutation.operation.name;
52
+ const context: ValidationContext = {
53
+ path: 'ROOT',
54
+ visitedPaths: new Set(),
55
+ variables: variables || {},
56
+ missingDiff: {},
57
+ extraDiff: {},
58
+ };
59
+ validateSelections(
60
+ optimisticResponse,
61
+ mutation.operation.selections,
62
+ context,
63
+ );
64
+ validateOptimisticResponse(optimisticResponse, context);
65
+ warning(
66
+ context.missingDiff.ROOT == null,
67
+ 'Expected `optimisticResponse` to match structure of server response for mutation `%s`, please define fields for all of\n%s',
68
+ operationName,
69
+ JSON.stringify(context.missingDiff.ROOT, null, 2),
70
+ );
71
+ warning(
72
+ context.extraDiff.ROOT == null,
73
+ 'Expected `optimisticResponse` to match structure of server response for mutation `%s`, please remove all fields of\n%s',
74
+ operationName,
75
+ JSON.stringify(context.extraDiff.ROOT, null, 2),
76
+ );
77
+ };
78
+
79
+ const validateSelections = (
80
+ optimisticResponse: Object,
81
+ selections: $ReadOnlyArray<NormalizationSelection>,
82
+ context: ValidationContext,
83
+ ) => {
84
+ selections.forEach(selection =>
85
+ validateSelection(optimisticResponse, selection, context),
86
+ );
87
+ };
88
+
89
+ const validateSelection = (
90
+ optimisticResponse: Object,
91
+ selection: NormalizationSelection,
92
+ context: ValidationContext,
93
+ ) => {
94
+ switch (selection.kind) {
95
+ case 'Condition':
96
+ validateSelections(optimisticResponse, selection.selections, context);
97
+ return;
98
+ case 'ScalarField':
99
+ case 'LinkedField':
100
+ return validateField(optimisticResponse, selection, context);
101
+ case 'InlineFragment':
102
+ const type = selection.type;
103
+ selection.selections.forEach(subselection => {
104
+ if (optimisticResponse.__typename !== type) {
105
+ return;
106
+ }
107
+ validateSelection(optimisticResponse, subselection, context);
108
+ });
109
+ return;
110
+ case 'ClientExtension':
111
+ selection.selections.forEach(subselection => {
112
+ validateSelection(optimisticResponse, subselection, context);
113
+ });
114
+ return;
115
+ case 'ModuleImport':
116
+ case 'LinkedHandle':
117
+ case 'ScalarHandle':
118
+ case 'Defer':
119
+ case 'Stream': {
120
+ // TODO(T35864292) - Add missing validations for these types
121
+ return;
122
+ }
123
+ default:
124
+ (selection: empty);
125
+ return;
126
+ }
127
+ };
128
+
129
+ const validateField = (
130
+ optimisticResponse: Object,
131
+ field: NormalizationField,
132
+ context: ValidationContext,
133
+ ) => {
134
+ const fieldName = field.alias || field.name;
135
+ const path = `${context.path}.${fieldName}`;
136
+ context.visitedPaths.add(path);
137
+ switch (field.kind) {
138
+ case 'ScalarField':
139
+ if (optimisticResponse.hasOwnProperty(fieldName) === false) {
140
+ addFieldToDiff(path, context.missingDiff, true);
141
+ }
142
+ return;
143
+ case 'LinkedField':
144
+ const selections = field.selections;
145
+ if (
146
+ optimisticResponse[fieldName] === null ||
147
+ (Object.hasOwnProperty(fieldName) &&
148
+ optimisticResponse[fieldName] === undefined)
149
+ ) {
150
+ return;
151
+ }
152
+ if (field.plural) {
153
+ if (Array.isArray(optimisticResponse[fieldName])) {
154
+ optimisticResponse[fieldName].forEach(r => {
155
+ if (r !== null) {
156
+ validateSelections(r, selections, {
157
+ ...context,
158
+ path,
159
+ });
160
+ }
161
+ });
162
+ return;
163
+ } else {
164
+ addFieldToDiff(path, context.missingDiff);
165
+ return;
166
+ }
167
+ } else {
168
+ if (optimisticResponse[fieldName] instanceof Object) {
169
+ validateSelections(optimisticResponse[fieldName], selections, {
170
+ ...context,
171
+ path,
172
+ });
173
+ return;
174
+ } else {
175
+ addFieldToDiff(path, context.missingDiff);
176
+ return;
177
+ }
178
+ }
179
+ }
180
+ };
181
+
182
+ const validateOptimisticResponse = (
183
+ optimisticResponse: Object,
184
+ context: ValidationContext,
185
+ ) => {
186
+ if (Array.isArray(optimisticResponse)) {
187
+ optimisticResponse.forEach(r => {
188
+ if (r instanceof Object) {
189
+ validateOptimisticResponse(r, context);
190
+ }
191
+ });
192
+ return;
193
+ }
194
+ Object.keys(optimisticResponse).forEach((key: string) => {
195
+ const value = optimisticResponse[key];
196
+ const path = `${context.path}.${key}`;
197
+ if (!context.visitedPaths.has(path)) {
198
+ addFieldToDiff(path, context.extraDiff);
199
+ return;
200
+ }
201
+ if (value instanceof Object) {
202
+ validateOptimisticResponse(value, {
203
+ ...context,
204
+ path,
205
+ });
206
+ }
207
+ });
208
+ };
209
+ }
210
+
211
+ module.exports = (validateMutation: (Object, ConcreteRequest, ?Object) => void);
@@ -0,0 +1,49 @@
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 RelayObservable = require('./RelayObservable');
16
+
17
+ import type {ExecuteFunction, FetchFunction} from './RelayNetworkTypes';
18
+
19
+ /**
20
+ * Converts a FetchFunction into an ExecuteFunction for use by RelayNetwork.
21
+ */
22
+ function convertFetch(fn: FetchFunction): ExecuteFunction {
23
+ return function fetch(
24
+ request,
25
+ variables,
26
+ cacheConfig,
27
+ uploadables,
28
+ logRequestInfo,
29
+ ) {
30
+ const result = fn(
31
+ request,
32
+ variables,
33
+ cacheConfig,
34
+ uploadables,
35
+ logRequestInfo,
36
+ );
37
+ // Note: We allow FetchFunction to directly return Error to indicate
38
+ // a failure to fetch. To avoid handling this special case throughout the
39
+ // Relay codebase, it is explicitly handled here.
40
+ if (result instanceof Error) {
41
+ return RelayObservable.create(sink => sink.error(result));
42
+ }
43
+ return RelayObservable.from(result);
44
+ };
45
+ }
46
+
47
+ module.exports = {
48
+ convertFetch,
49
+ };
@@ -0,0 +1,84 @@
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 {convertFetch} = require('./ConvertToExecuteFunction');
18
+
19
+ import type {RequestParameters} from '../util/RelayConcreteNode';
20
+ import type {CacheConfig, Variables} from '../util/RelayRuntimeTypes';
21
+ import type {
22
+ FetchFunction,
23
+ GraphQLResponse,
24
+ LogRequestInfoFunction,
25
+ INetwork,
26
+ SubscribeFunction,
27
+ UploadableMap,
28
+ } from './RelayNetworkTypes';
29
+ import type RelayObservable from './RelayObservable';
30
+
31
+ /**
32
+ * Creates an implementation of the `Network` interface defined in
33
+ * `RelayNetworkTypes` given `fetch` and `subscribe` functions.
34
+ */
35
+ function create(
36
+ fetchFn: FetchFunction,
37
+ subscribe?: SubscribeFunction,
38
+ ): INetwork {
39
+ // Convert to functions that returns RelayObservable.
40
+ const observeFetch = convertFetch(fetchFn);
41
+
42
+ function execute(
43
+ request: RequestParameters,
44
+ variables: Variables,
45
+ cacheConfig: CacheConfig,
46
+ uploadables?: ?UploadableMap,
47
+ logRequestInfo: ?LogRequestInfoFunction,
48
+ ): RelayObservable<GraphQLResponse> {
49
+ if (request.operationKind === 'subscription') {
50
+ invariant(
51
+ subscribe,
52
+ 'RelayNetwork: This network layer does not support Subscriptions. ' +
53
+ 'To use Subscriptions, provide a custom network layer.',
54
+ );
55
+
56
+ invariant(
57
+ !uploadables,
58
+ 'RelayNetwork: Cannot provide uploadables while subscribing.',
59
+ );
60
+ return subscribe(request, variables, cacheConfig);
61
+ }
62
+
63
+ const pollInterval = cacheConfig.poll;
64
+ if (pollInterval != null) {
65
+ invariant(
66
+ !uploadables,
67
+ 'RelayNetwork: Cannot provide uploadables while polling.',
68
+ );
69
+ return observeFetch(request, variables, {force: true}).poll(pollInterval);
70
+ }
71
+
72
+ return observeFetch(
73
+ request,
74
+ variables,
75
+ cacheConfig,
76
+ uploadables,
77
+ logRequestInfo,
78
+ );
79
+ }
80
+
81
+ return {execute};
82
+ }
83
+
84
+ module.exports = {create};