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.
Files changed (46) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +1 -4
  3. package/index.js +2 -2
  4. package/index.js.flow +4 -0
  5. package/lib/index.js +7 -1
  6. package/lib/mutations/readUpdatableQuery_EXPERIMENTAL.js +22 -17
  7. package/lib/mutations/validateMutation.js +11 -1
  8. package/lib/network/RelayNetwork.js +7 -3
  9. package/lib/query/fetchQuery.js +3 -0
  10. package/lib/store/RelayConcreteVariables.js +12 -3
  11. package/lib/store/RelayExperimentalGraphResponseTransform.js +34 -2
  12. package/lib/store/RelayModernOperationDescriptor.js +1 -1
  13. package/lib/store/RelayPublishQueue.js +4 -2
  14. package/lib/store/RelayReader.js +55 -13
  15. package/lib/store/RelayStoreUtils.js +1 -0
  16. package/lib/store/ResolverCache.js +10 -2
  17. package/lib/store/ResolverFragments.js +2 -2
  18. package/lib/subscription/requestSubscription.js +0 -2
  19. package/lib/util/withProvidedVariables.js +49 -0
  20. package/mutations/RelayDeclarativeMutationConfig.js.flow +0 -1
  21. package/mutations/commitMutation.js.flow +8 -19
  22. package/mutations/readUpdatableQuery_EXPERIMENTAL.js.flow +47 -49
  23. package/mutations/validateMutation.js.flow +14 -2
  24. package/network/RelayNetwork.js.flow +10 -3
  25. package/network/RelayNetworkTypes.js.flow +1 -1
  26. package/package.json +6 -2
  27. package/query/fetchQuery.js.flow +9 -7
  28. package/relay-runtime.js +2 -2
  29. package/relay-runtime.min.js +3 -3
  30. package/store/RelayConcreteVariables.js.flow +12 -2
  31. package/store/RelayExperimentalGraphResponseTransform.js.flow +35 -1
  32. package/store/RelayModernOperationDescriptor.js.flow +5 -1
  33. package/store/RelayModernStore.js.flow +0 -1
  34. package/store/RelayPublishQueue.js.flow +8 -1
  35. package/store/RelayReader.js.flow +78 -31
  36. package/store/RelayStoreTypes.js.flow +3 -2
  37. package/store/RelayStoreUtils.js.flow +1 -0
  38. package/store/ResolverCache.js.flow +18 -5
  39. package/store/ResolverFragments.js.flow +2 -2
  40. package/subscription/requestSubscription.js.flow +7 -13
  41. package/util/NormalizationNode.js.flow +16 -16
  42. package/util/ReaderNode.js.flow +15 -15
  43. package/util/RelayConcreteNode.js.flow +4 -2
  44. package/util/withProvidedVariables.js.flow +64 -0
  45. package/lib/util/getAllRootVariables.js +0 -29
  46. package/util/getAllRootVariables.js.flow +0 -36
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and 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
+ *
8
+ * @format
9
+ * @emails oncall+relay
10
+ */
11
+ // flowlint ambiguous-object-type:error
12
+ 'use strict';
13
+
14
+ var areEqual = require("fbjs/lib/areEqual");
15
+
16
+ var warning = require("fbjs/lib/warning");
17
+
18
+ var WEAKMAP_SUPPORTED = typeof WeakMap === 'function';
19
+ var debugCache = WEAKMAP_SUPPORTED ? new WeakMap() : new Map();
20
+
21
+ function withProvidedVariables(userSuppliedVariables, providedVariables) {
22
+ if (providedVariables != null) {
23
+ var operationVariables = {};
24
+ Object.assign(operationVariables, userSuppliedVariables);
25
+ Object.keys(providedVariables).forEach(function (varName) {
26
+ var providerFunction = providedVariables[varName].get;
27
+ var providerResult = providerFunction(); // people like to ignore these warnings, so use the cache to
28
+ // enforce that we only compute the value the first time
29
+
30
+ if (!debugCache.has(providerFunction)) {
31
+ debugCache.set(providerFunction, providerResult);
32
+ operationVariables[varName] = providerResult;
33
+ } else {
34
+ var cachedResult = debugCache.get(providerFunction);
35
+
36
+ if (process.env.NODE_ENV !== "production") {
37
+ process.env.NODE_ENV !== "production" ? warning(areEqual(providerResult, cachedResult), 'Relay: Expected function `%s` for provider `%s` to be a pure function, ' + 'but got conflicting return values `%s` and `%s`', providerFunction.name, varName, providerResult, cachedResult) : void 0;
38
+ }
39
+
40
+ operationVariables[varName] = cachedResult;
41
+ }
42
+ });
43
+ return operationVariables;
44
+ } else {
45
+ return userSuppliedVariables;
46
+ }
47
+ }
48
+
49
+ module.exports = withProvidedVariables;
@@ -15,7 +15,6 @@
15
15
  import type {
16
16
  MutationParameters,
17
17
  RecordSourceSelectorProxy,
18
- SelectorData,
19
18
  SelectorStoreUpdater,
20
19
  } from '../store/RelayStoreTypes';
21
20
  import type {ConcreteRequest} from '../util/RelayConcreteNode';
@@ -37,32 +37,15 @@ const validateMutation = require('./validateMutation');
37
37
  const invariant = require('invariant');
38
38
  const warning = require('warning');
39
39
 
40
- export type DEPRECATED_MutationConfig<TMutationResponse> = {|
41
- configs?: Array<DeclarativeMutationConfig>,
42
- cacheConfig?: CacheConfig,
43
- mutation: GraphQLTaggedNode,
44
- variables: Variables,
45
- uploadables?: UploadableMap,
46
- onCompleted?: ?(
47
- response: TMutationResponse,
48
- errors: ?Array<PayloadError>,
49
- ) => void,
50
- onError?: ?(error: Error) => void,
51
- onUnsubscribe?: ?() => void,
52
- optimisticUpdater?: ?SelectorStoreUpdater<TMutationResponse>,
53
- optimisticResponse?: Object,
54
- updater?: ?SelectorStoreUpdater<TMutationResponse>,
55
- |};
56
-
57
40
  export type MutationConfig<TMutation: MutationParameters> = {|
58
- configs?: Array<DeclarativeMutationConfig>,
59
41
  cacheConfig?: CacheConfig,
42
+ configs?: Array<DeclarativeMutationConfig>,
60
43
  mutation: GraphQLTaggedNode,
61
- onError?: ?(error: Error) => void,
62
44
  onCompleted?: ?(
63
45
  response: TMutation['response'],
64
46
  errors: ?Array<PayloadError>,
65
47
  ) => void,
48
+ onError?: ?(error: Error) => void,
66
49
  onNext?: ?() => void,
67
50
  onUnsubscribe?: ?() => void,
68
51
  optimisticResponse?: {
@@ -76,6 +59,12 @@ export type MutationConfig<TMutation: MutationParameters> = {|
76
59
  variables: TMutation['variables'],
77
60
  |};
78
61
 
62
+ export type DEPRECATED_MutationConfig<TMutationResponse> = MutationConfig<{|
63
+ response: TMutationResponse,
64
+ rawResponse: any,
65
+ variables: Variables,
66
+ |}>;
67
+
79
68
  /**
80
69
  * Higher-level helper function to execute a mutation against a specific
81
70
  * environment.
@@ -21,7 +21,7 @@ import type {OperationType} from '../util/RelayRuntimeTypes';
21
21
  const {getRequest} = require('../query/GraphQLTag');
22
22
  const {getArgumentValues} = require('../store/RelayStoreUtils');
23
23
 
24
- const nonUpdatableKeys = ['id', '__id', '__typename'];
24
+ const nonUpdatableKeys = ['id', '__id', '__typename', 'js'];
25
25
 
26
26
  function readUpdatableQuery_EXPERIMENTAL<TQuery: OperationType>(
27
27
  query: GraphQLTaggedNode,
@@ -55,50 +55,46 @@ function updateProxyFromSelections<TQuery: OperationType>(
55
55
  for (const selection of selections) {
56
56
  switch (selection.kind) {
57
57
  case 'LinkedField':
58
- // Linked fields are assignable if they contain fragment spreads or
59
- // read-only otherwise.
60
- const isAssignable = selection.selections.some(
61
- item => item.kind === 'FragmentSpread',
62
- );
63
-
64
- const set = !isAssignable
65
- ? undefined
66
- : selection.plural
67
- ? createSetterForPluralLinkedField(
68
- selection,
69
- queryVariables,
70
- recordProxy,
71
- root,
72
- )
73
- : createSetterForSingularLinkedField(
74
- selection,
75
- queryVariables,
76
- recordProxy,
77
- root,
78
- );
79
-
80
- const get = selection.plural
81
- ? createGetterForPluralLinkedField(
82
- selection,
83
- queryVariables,
84
- recordProxy,
85
- root,
86
- )
87
- : createGetterForSingularLinkedField(
88
- selection,
89
- queryVariables,
90
- recordProxy,
91
- root,
92
- );
93
-
94
- Object.defineProperty(
95
- mutableUpdatableProxy,
96
- selection.alias ?? selection.name,
97
- {
98
- get,
99
- set,
100
- },
101
- );
58
+ if (selection.plural) {
59
+ Object.defineProperty(
60
+ mutableUpdatableProxy,
61
+ selection.alias ?? selection.name,
62
+ {
63
+ // $FlowFixMe[incompatible-call] these getters and setters have different types on purpose
64
+ get: createGetterForPluralLinkedField(
65
+ selection,
66
+ queryVariables,
67
+ recordProxy,
68
+ root,
69
+ ),
70
+ set: createSetterForPluralLinkedField(
71
+ selection,
72
+ queryVariables,
73
+ recordProxy,
74
+ root,
75
+ ),
76
+ },
77
+ );
78
+ } else {
79
+ Object.defineProperty(
80
+ mutableUpdatableProxy,
81
+ selection.alias ?? selection.name,
82
+ {
83
+ get: createGetterForSingularLinkedField(
84
+ selection,
85
+ queryVariables,
86
+ recordProxy,
87
+ root,
88
+ ),
89
+ set: createSetterForSingularLinkedField(
90
+ selection,
91
+ queryVariables,
92
+ recordProxy,
93
+ root,
94
+ ),
95
+ },
96
+ );
97
+ }
102
98
  break;
103
99
  case 'ScalarField':
104
100
  const scalarFieldName = selection.alias ?? selection.name;
@@ -171,11 +167,12 @@ function createSetterForPluralLinkedField<TQuery: OperationType>(
171
167
  recordProxy: RecordProxy,
172
168
  root: RecordSourceProxy,
173
169
  ) {
174
- return function set(newValue: ?$ReadOnlyArray<{__id: string, ...}>) {
170
+ return function set(newValue: $ReadOnlyArray<{__id: string, ...}>) {
175
171
  const variables = getArgumentValues(selection.args ?? [], queryVariables);
176
172
  if (newValue == null) {
177
- // $FlowFixMe[unclear-type] No good way to type these variables
178
- recordProxy.setValue(null, selection.name, (variables: any));
173
+ throw new Error(
174
+ 'Do not assign null to plural linked fields; assign an empty array instead.',
175
+ );
179
176
  } else {
180
177
  const recordProxies = newValue.map(item => {
181
178
  if (item == null) {
@@ -206,6 +203,7 @@ function createSetterForPluralLinkedField<TQuery: OperationType>(
206
203
  }
207
204
  };
208
205
  }
206
+
209
207
  function createSetterForSingularLinkedField<TQuery: OperationType>(
210
208
  selection: ReaderLinkedField,
211
209
  queryVariables: TQuery['variables'],
@@ -216,7 +214,7 @@ function createSetterForSingularLinkedField<TQuery: OperationType>(
216
214
  const variables = getArgumentValues(selection.args ?? [], queryVariables);
217
215
  if (newValue == null) {
218
216
  // $FlowFixMe[unclear-type] No good way to type these variables
219
- recordProxy.setValue(null, selection.name, (variables: any));
217
+ recordProxy.setValue(newValue, selection.name, (variables: any));
220
218
  } else {
221
219
  const {__id} = newValue;
222
220
  if (__id == null) {
@@ -141,6 +141,7 @@ if (__DEV__) {
141
141
  case INLINE_FRAGMENT:
142
142
  const type = selection.type;
143
143
  const isConcreteType = selection.abstractKey == null;
144
+ validateAbstractKey(context, selection.abstractKey);
144
145
  selection.selections.forEach(subselection => {
145
146
  if (isConcreteType && optimisticResponse.__typename !== type) {
146
147
  return;
@@ -155,11 +156,12 @@ if (__DEV__) {
155
156
  return;
156
157
  case MODULE_IMPORT:
157
158
  return validateModuleImport(context);
159
+ case TYPE_DISCRIMINATOR:
160
+ return validateAbstractKey(context, selection.abstractKey);
158
161
  case LINKED_HANDLE:
159
162
  case SCALAR_HANDLE:
160
163
  case DEFER:
161
- case STREAM:
162
- case TYPE_DISCRIMINATOR: {
164
+ case STREAM: {
163
165
  // TODO(T35864292) - Add missing validations for these types
164
166
  return;
165
167
  }
@@ -173,6 +175,16 @@ if (__DEV__) {
173
175
  context.moduleImportPaths.add(context.path);
174
176
  };
175
177
 
178
+ const validateAbstractKey = (
179
+ context: ValidationContext,
180
+ abstractKey: ?string,
181
+ ) => {
182
+ if (abstractKey != null) {
183
+ const path = `${context.path}.${abstractKey}`;
184
+ context.visitedPaths.add(path);
185
+ }
186
+ };
187
+
176
188
  const validateField = (
177
189
  optimisticResponse: Object,
178
190
  field: NormalizationField,
@@ -24,6 +24,7 @@ import type {
24
24
  } from './RelayNetworkTypes';
25
25
  import type RelayObservable from './RelayObservable';
26
26
 
27
+ const withProvidedVariables = require('../util/withProvidedVariables');
27
28
  const {convertFetch} = require('./ConvertToExecuteFunction');
28
29
  const invariant = require('invariant');
29
30
 
@@ -45,6 +46,10 @@ function create(
45
46
  uploadables?: ?UploadableMap,
46
47
  logRequestInfo: ?LogRequestInfoFunction,
47
48
  ): RelayObservable<GraphQLResponse> {
49
+ const operationVariables = withProvidedVariables(
50
+ variables,
51
+ request.providedVariables,
52
+ );
48
53
  if (request.operationKind === 'subscription') {
49
54
  invariant(
50
55
  subscribe,
@@ -56,7 +61,7 @@ function create(
56
61
  !uploadables,
57
62
  'RelayNetwork: Cannot provide uploadables while subscribing.',
58
63
  );
59
- return subscribe(request, variables, cacheConfig);
64
+ return subscribe(request, operationVariables, cacheConfig);
60
65
  }
61
66
 
62
67
  const pollInterval = cacheConfig.poll;
@@ -65,12 +70,14 @@ function create(
65
70
  !uploadables,
66
71
  'RelayNetwork: Cannot provide uploadables while polling.',
67
72
  );
68
- return observeFetch(request, variables, {force: true}).poll(pollInterval);
73
+ return observeFetch(request, operationVariables, {force: true}).poll(
74
+ pollInterval,
75
+ );
69
76
  }
70
77
 
71
78
  return observeFetch(
72
79
  request,
73
- variables,
80
+ operationVariables,
74
81
  cacheConfig,
75
82
  uploadables,
76
83
  logRequestInfo,
@@ -26,7 +26,7 @@ export interface INetwork {
26
26
 
27
27
  export type LogRequestInfoFunction = mixed => void;
28
28
 
29
- export type PayloadData = interface {[key: string]: mixed};
29
+ export type PayloadData = {[key: string]: mixed};
30
30
 
31
31
  export type PayloadError = interface {
32
32
  message: string,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "relay-runtime",
3
3
  "description": "A core runtime for building GraphQL-driven applications.",
4
- "version": "13.0.0-rc.2",
4
+ "version": "13.0.3",
5
5
  "keywords": [
6
6
  "graphql",
7
7
  "relay"
@@ -9,7 +9,11 @@
9
9
  "license": "MIT",
10
10
  "homepage": "https://relay.dev",
11
11
  "bugs": "https://github.com/facebook/relay/issues",
12
- "repository": "facebook/relay",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/facebook/relay.git",
15
+ "directory": "packages/relay-runtime"
16
+ },
13
17
  "dependencies": {
14
18
  "@babel/runtime": "^7.0.0",
15
19
  "fbjs": "^3.0.2",
@@ -22,9 +22,9 @@ import type {
22
22
  CacheConfig,
23
23
  FetchQueryFetchPolicy,
24
24
  OperationType,
25
- VariablesOf,
25
+ Query,
26
+ Variables,
26
27
  } from '../util/RelayRuntimeTypes';
27
- import type {GraphQLTaggedNode} from './GraphQLTag';
28
28
 
29
29
  const RelayObservable = require('../network/RelayObservable');
30
30
  const {
@@ -112,15 +112,15 @@ const invariant = require('invariant');
112
112
  * ```
113
113
  * NOTE: When using .toPromise(), the request cannot be cancelled.
114
114
  */
115
- function fetchQuery<TQuery: OperationType>(
115
+ function fetchQuery<TVariables: Variables, TData, TRawResponse>(
116
116
  environment: IEnvironment,
117
- query: GraphQLTaggedNode,
118
- variables: VariablesOf<TQuery>,
117
+ query: Query<TVariables, TData, TRawResponse>,
118
+ variables: TVariables,
119
119
  options?: $ReadOnly<{|
120
120
  fetchPolicy?: FetchQueryFetchPolicy,
121
121
  networkCacheConfig?: CacheConfig,
122
122
  |}>,
123
- ): RelayObservable<TQuery['response']> {
123
+ ): RelayObservable<TData> {
124
124
  const queryNode = getRequest(query);
125
125
  invariant(
126
126
  queryNode.params.operationKind === 'query',
@@ -137,10 +137,12 @@ function fetchQuery<TQuery: OperationType>(
137
137
  );
138
138
  const fetchPolicy = options?.fetchPolicy ?? 'network-only';
139
139
 
140
- function readData(snapshot: Snapshot) {
140
+ function readData(snapshot: Snapshot): TData {
141
141
  if (snapshot.missingRequiredFields != null) {
142
142
  reportMissingRequiredFields(environment, snapshot.missingRequiredFields);
143
143
  }
144
+ /* $FlowFixMe[incompatible-return] we assume readData returns the right
145
+ * data just having written it from network or checked availability. */
144
146
  return snapshot.data;
145
147
  }
146
148