UNPKG

11.1 kBJavaScriptView Raw
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 *
8 * @format
9 */
10// flowlint ambiguous-object-type:error
11'use strict';
12
13var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
14
15var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
16
17var invariant = require("fbjs/lib/invariant");
18
19var _require = require('relay-runtime'),
20 isRelayModernEnvironment = _require.isRelayModernEnvironment,
21 fetchQuery = _require.__internal.fetchQuery;
22
23var ReactRelayQueryFetcher = /*#__PURE__*/function () {
24 function ReactRelayQueryFetcher(args) {
25 (0, _defineProperty2["default"])(this, "_selectionReferences", []);
26 (0, _defineProperty2["default"])(this, "_callOnDataChangeWhenSet", false);
27
28 if (args != null) {
29 this._cacheSelectionReference = args.cacheSelectionReference;
30 this._selectionReferences = args.selectionReferences;
31 }
32 }
33
34 var _proto = ReactRelayQueryFetcher.prototype;
35
36 _proto.getSelectionReferences = function getSelectionReferences() {
37 return {
38 cacheSelectionReference: this._cacheSelectionReference,
39 selectionReferences: this._selectionReferences
40 };
41 };
42
43 _proto.lookupInStore = function lookupInStore(environment, operation, fetchPolicy) {
44 if (fetchPolicy === 'store-and-network' || fetchPolicy === 'store-or-network') {
45 if (environment.check(operation).status === 'available') {
46 this._retainCachedOperation(environment, operation);
47
48 return environment.lookup(operation.fragment);
49 }
50 }
51
52 return null;
53 };
54
55 _proto.execute = function execute(_ref) {
56 var _this = this;
57
58 var environment = _ref.environment,
59 operation = _ref.operation,
60 cacheConfig = _ref.cacheConfig,
61 _ref$preservePrevious = _ref.preservePreviousReferences,
62 preservePreviousReferences = _ref$preservePrevious === void 0 ? false : _ref$preservePrevious;
63 var reference = environment.retain(operation);
64 var fetchQueryOptions = cacheConfig != null ? {
65 networkCacheConfig: cacheConfig
66 } : {};
67
68 var error = function error() {
69 // We may have partially fulfilled the request, so let the next request
70 // or the unmount dispose of the references.
71 _this._selectionReferences = _this._selectionReferences.concat(reference);
72 };
73
74 var complete = function complete() {
75 if (!preservePreviousReferences) {
76 _this.disposeSelectionReferences();
77 }
78
79 _this._selectionReferences = _this._selectionReferences.concat(reference);
80 };
81
82 var unsubscribe = function unsubscribe() {
83 // Let the next request or the unmount code dispose of the references.
84 // We may have partially fulfilled the request.
85 _this._selectionReferences = _this._selectionReferences.concat(reference);
86 };
87
88 if (!isRelayModernEnvironment(environment)) {
89 return environment.execute({
90 operation: operation,
91 cacheConfig: cacheConfig
92 })["do"]({
93 error: error,
94 complete: complete,
95 unsubscribe: unsubscribe
96 });
97 }
98
99 return fetchQuery(environment, operation, fetchQueryOptions)["do"]({
100 error: error,
101 complete: complete,
102 unsubscribe: unsubscribe
103 });
104 };
105
106 _proto.setOnDataChange = function setOnDataChange(onDataChange) {
107 !this._fetchOptions ? process.env.NODE_ENV !== "production" ? invariant(false, 'ReactRelayQueryFetcher: `setOnDataChange` should have been called after having called `fetch`') : invariant(false) : void 0;
108
109 if (typeof onDataChange === 'function') {
110 // Mutate the most recent fetchOptions in place,
111 // So that in-progress requests can access the updated callback.
112 this._fetchOptions.onDataChangeCallbacks = this._fetchOptions.onDataChangeCallbacks || [];
113
114 this._fetchOptions.onDataChangeCallbacks.push(onDataChange);
115
116 if (this._callOnDataChangeWhenSet) {
117 // We don't reset '_callOnDataChangeWhenSet' because another callback may be set
118 if (this._error != null) {
119 onDataChange({
120 error: this._error
121 });
122 } else if (this._snapshot != null) {
123 onDataChange({
124 snapshot: this._snapshot
125 });
126 }
127 }
128 }
129 }
130 /**
131 * `fetch` fetches the data for the given operation.
132 * If a result is immediately available synchronously, it will be synchronously
133 * returned by this function.
134 *
135 * Otherwise, the fetched result will be communicated via the `onDataChange` callback.
136 * `onDataChange` will be called with the first result (**if it wasn't returned synchronously**),
137 * and then subsequently whenever the data changes.
138 */
139 ;
140
141 _proto.fetch = function fetch(fetchOptions, cacheConfigOverride) {
142 var _this2 = this;
143
144 var cacheConfig = fetchOptions.cacheConfig,
145 environment = fetchOptions.environment,
146 operation = fetchOptions.operation,
147 onDataChange = fetchOptions.onDataChange;
148 var fetchHasReturned = false;
149
150 var _error;
151
152 this.disposeRequest();
153 var oldOnDataChangeCallbacks = this._fetchOptions && this._fetchOptions.onDataChangeCallbacks;
154 this._fetchOptions = {
155 cacheConfig: cacheConfig,
156 environment: environment,
157 onDataChangeCallbacks: oldOnDataChangeCallbacks || [],
158 operation: operation
159 };
160
161 if (onDataChange && this._fetchOptions.onDataChangeCallbacks.indexOf(onDataChange) === -1) {
162 this._fetchOptions.onDataChangeCallbacks.push(onDataChange);
163 }
164
165 var request = this.execute({
166 environment: environment,
167 operation: operation,
168 cacheConfig: cacheConfigOverride !== null && cacheConfigOverride !== void 0 ? cacheConfigOverride : cacheConfig
169 })["finally"](function () {
170 _this2._pendingRequest = null;
171 }).subscribe({
172 next: function next() {
173 // If we received a response,
174 // Make a note that to notify the callback when it's later added.
175 _this2._callOnDataChangeWhenSet = true;
176 _this2._error = null; // Only notify of the first result if `next` is being called **asynchronously**
177 // (i.e. after `fetch` has returned).
178
179 _this2._onQueryDataAvailable({
180 notifyFirstResult: fetchHasReturned
181 });
182 },
183 error: function error(err) {
184 // If we received a response when we didn't have a change callback,
185 // Make a note that to notify the callback when it's later added.
186 _this2._callOnDataChangeWhenSet = true;
187 _this2._error = err;
188 _this2._snapshot = null;
189 var onDataChangeCallbacks = _this2._fetchOptions && _this2._fetchOptions.onDataChangeCallbacks; // Only notify of error if `error` is being called **asynchronously**
190 // (i.e. after `fetch` has returned).
191
192 if (fetchHasReturned) {
193 if (onDataChangeCallbacks) {
194 onDataChangeCallbacks.forEach(function (onDataChange) {
195 onDataChange({
196 error: err
197 });
198 });
199 }
200 } else {
201 _error = err;
202 }
203 }
204 });
205 this._pendingRequest = {
206 dispose: function dispose() {
207 request.unsubscribe();
208 }
209 };
210 fetchHasReturned = true;
211
212 if (_error) {
213 throw _error;
214 }
215
216 return this._snapshot;
217 };
218
219 _proto.retry = function retry(cacheConfigOverride) {
220 !this._fetchOptions ? process.env.NODE_ENV !== "production" ? invariant(false, 'ReactRelayQueryFetcher: `retry` should be called after having called `fetch`') : invariant(false) : void 0;
221 return this.fetch({
222 cacheConfig: this._fetchOptions.cacheConfig,
223 environment: this._fetchOptions.environment,
224 operation: this._fetchOptions.operation,
225 onDataChange: null // If there are onDataChangeCallbacks they will be reused
226
227 }, cacheConfigOverride);
228 };
229
230 _proto.dispose = function dispose() {
231 this.disposeRequest();
232 this.disposeSelectionReferences();
233 };
234
235 _proto.disposeRequest = function disposeRequest() {
236 this._error = null;
237 this._snapshot = null; // order is important, dispose of pendingFetch before selectionReferences
238
239 if (this._pendingRequest) {
240 this._pendingRequest.dispose();
241 }
242
243 if (this._rootSubscription) {
244 this._rootSubscription.dispose();
245
246 this._rootSubscription = null;
247 }
248 };
249
250 _proto._retainCachedOperation = function _retainCachedOperation(environment, operation) {
251 this._disposeCacheSelectionReference();
252
253 this._cacheSelectionReference = environment.retain(operation);
254 };
255
256 _proto._disposeCacheSelectionReference = function _disposeCacheSelectionReference() {
257 this._cacheSelectionReference && this._cacheSelectionReference.dispose();
258 this._cacheSelectionReference = null;
259 };
260
261 _proto.disposeSelectionReferences = function disposeSelectionReferences() {
262 this._disposeCacheSelectionReference();
263
264 this._selectionReferences.forEach(function (r) {
265 return r.dispose();
266 });
267
268 this._selectionReferences = [];
269 };
270
271 _proto._onQueryDataAvailable = function _onQueryDataAvailable(_ref2) {
272 var _this3 = this;
273
274 var notifyFirstResult = _ref2.notifyFirstResult;
275 !this._fetchOptions ? process.env.NODE_ENV !== "production" ? invariant(false, 'ReactRelayQueryFetcher: `_onQueryDataAvailable` should have been called after having called `fetch`') : invariant(false) : void 0;
276 var _this$_fetchOptions = this._fetchOptions,
277 environment = _this$_fetchOptions.environment,
278 onDataChangeCallbacks = _this$_fetchOptions.onDataChangeCallbacks,
279 operation = _this$_fetchOptions.operation; // `_onQueryDataAvailable` can be called synchronously the first time and can be called
280 // multiple times by network layers that support data subscriptions.
281 // Wait until the first payload to call `onDataChange` and subscribe for data updates.
282
283 if (this._snapshot) {
284 return;
285 }
286
287 this._snapshot = environment.lookup(operation.fragment); // Subscribe to changes in the data of the root fragment
288
289 this._rootSubscription = environment.subscribe(this._snapshot, function (snapshot) {
290 // Read from this._fetchOptions in case onDataChange() was lazily added.
291 if (_this3._fetchOptions != null) {
292 var maybeNewOnDataChangeCallbacks = _this3._fetchOptions.onDataChangeCallbacks;
293
294 if (Array.isArray(maybeNewOnDataChangeCallbacks)) {
295 maybeNewOnDataChangeCallbacks.forEach(function (onDataChange) {
296 return onDataChange({
297 snapshot: snapshot
298 });
299 });
300 }
301 }
302 });
303
304 if (this._snapshot && notifyFirstResult && Array.isArray(onDataChangeCallbacks)) {
305 var snapshot = this._snapshot;
306 onDataChangeCallbacks.forEach(function (onDataChange) {
307 return onDataChange({
308 snapshot: snapshot
309 });
310 });
311 }
312 };
313
314 return ReactRelayQueryFetcher;
315}();
316
317module.exports = ReactRelayQueryFetcher;
\No newline at end of file