UNPKG

8.03 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 * @emails oncall+relay
8 *
9 * @format
10 */
11// flowlint ambiguous-object-type:error
12'use strict';
13
14var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
15
16var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
17
18function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
19
20function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
21
22var invariant = require("fbjs/lib/invariant");
23
24var _require = require('relay-runtime'),
25 createOperationDescriptor = _require.createOperationDescriptor,
26 Environment = _require.Environment,
27 getRequest = _require.getRequest,
28 getRequestIdentifier = _require.getRequestIdentifier,
29 Observable = _require.Observable,
30 PreloadableQueryRegistry = _require.PreloadableQueryRegistry,
31 ReplaySubject = _require.ReplaySubject;
32
33// Expire results by this delay after they resolve.
34var DEFAULT_PREFETCH_TIMEOUT = 30 * 1000; // 30 seconds
35
36var WEAKMAP_SUPPORTED = typeof WeakMap === 'function';
37var STORE_OR_NETWORK_DEFAULT = 'store-or-network';
38var pendingQueriesByEnvironment = WEAKMAP_SUPPORTED ? new WeakMap() : new Map();
39
40function preloadQuery(environment, preloadableRequest, variables, options, environmentProviderOptions) {
41 !(environment instanceof Environment) ? process.env.NODE_ENV !== "production" ? invariant(false, 'preloadQuery(): Expected a RelayModernEnvironment') : invariant(false) : void 0;
42
43 var _pendingQueries = pendingQueriesByEnvironment.get(environment);
44
45 if (_pendingQueries == null) {
46 _pendingQueries = new Map();
47 pendingQueriesByEnvironment.set(environment, _pendingQueries);
48 }
49
50 var pendingQueries = _pendingQueries; // store in a const for flow
51
52 var queryEntry = preloadQueryDeduped(environment, pendingQueries, preloadableRequest, variables, options);
53 var source = queryEntry.kind === 'network' ? Observable.create(function (sink) {
54 var subscription = queryEntry.subject.subscribe(sink);
55 return function () {
56 subscription.unsubscribe();
57 cleanup(pendingQueries, queryEntry);
58 };
59 }) : null;
60 return {
61 kind: 'PreloadedQuery_DEPRECATED',
62 environment: environment,
63 environmentProviderOptions: environmentProviderOptions,
64 fetchKey: queryEntry.fetchKey,
65 fetchPolicy: queryEntry.fetchPolicy,
66 networkCacheConfig: options === null || options === void 0 ? void 0 : options.networkCacheConfig,
67 id: queryEntry.id,
68 name: queryEntry.name,
69 source: source,
70 variables: variables,
71 status: queryEntry.status
72 };
73}
74
75function preloadQueryDeduped(environment, pendingQueries, preloadableRequest, variables, options) {
76 var _options$fetchPolicy;
77
78 var params;
79 var query;
80
81 if (preloadableRequest.kind === 'PreloadableConcreteRequest') {
82 var preloadableConcreteRequest = preloadableRequest;
83 params = preloadableConcreteRequest.params;
84 query = params.id != null ? PreloadableQueryRegistry.get(params.id) : null;
85 } else {
86 query = getRequest(preloadableRequest);
87 params = query.params;
88 }
89
90 var network = environment.getNetwork();
91 var fetchPolicy = (_options$fetchPolicy = options === null || options === void 0 ? void 0 : options.fetchPolicy) !== null && _options$fetchPolicy !== void 0 ? _options$fetchPolicy : STORE_OR_NETWORK_DEFAULT;
92 var fetchKey = options === null || options === void 0 ? void 0 : options.fetchKey;
93
94 var networkCacheConfig = _objectSpread({
95 force: true
96 }, options === null || options === void 0 ? void 0 : options.networkCacheConfig);
97
98 var cacheKey = "".concat(getRequestIdentifier(params, variables)).concat(fetchKey != null ? "-".concat(fetchKey) : '');
99 var prevQueryEntry = pendingQueries.get(cacheKey);
100 var availability = fetchPolicy === STORE_OR_NETWORK_DEFAULT && query != null && query != null ? environment.check(createOperationDescriptor(query, variables)) : {
101 status: 'missing'
102 };
103 var nextQueryEntry;
104
105 if (availability.status === 'available' && query != null) {
106 var _availability$fetchTi;
107
108 nextQueryEntry = prevQueryEntry && prevQueryEntry.kind === 'cache' ? prevQueryEntry : {
109 cacheKey: cacheKey,
110 fetchKey: fetchKey,
111 fetchPolicy: fetchPolicy,
112 kind: 'cache',
113 id: params.id,
114 name: params.name,
115 status: {
116 cacheConfig: networkCacheConfig,
117 source: 'cache',
118 fetchTime: (_availability$fetchTi = availability === null || availability === void 0 ? void 0 : availability.fetchTime) !== null && _availability$fetchTi !== void 0 ? _availability$fetchTi : null
119 }
120 };
121
122 if (!environment.isServer() && prevQueryEntry == null) {
123 setTimeout(function () {
124 // Clear the cache entry after the default timeout
125 // null-check for Flow
126 if (nextQueryEntry != null) {
127 cleanup(pendingQueries, nextQueryEntry);
128 }
129 }, DEFAULT_PREFETCH_TIMEOUT);
130 }
131 } else if (prevQueryEntry == null || prevQueryEntry.kind !== 'network') {
132 // Should fetch but we're not already fetching: fetch!
133 var _environment$__create = environment.__createLogObserver(params, variables),
134 logObserver = _environment$__create[0],
135 logRequestInfo = _environment$__create[1];
136
137 var source = network.execute(params, variables, networkCacheConfig, null, logRequestInfo);
138 var subject = new ReplaySubject();
139 nextQueryEntry = {
140 cacheKey: cacheKey,
141 fetchKey: fetchKey,
142 fetchPolicy: fetchPolicy,
143 kind: 'network',
144 id: params.id,
145 name: params.name,
146 status: {
147 cacheConfig: networkCacheConfig,
148 source: 'network',
149 fetchTime: null
150 },
151 subject: subject,
152 subscription: source["finally"](function () {
153 if (environment.isServer()) {
154 return;
155 }
156
157 setTimeout(function () {
158 // Clear the cache entry after the default timeout
159 // null-check for Flow
160 if (nextQueryEntry != null) {
161 cleanup(pendingQueries, nextQueryEntry);
162 }
163 }, DEFAULT_PREFETCH_TIMEOUT);
164 })["do"](logObserver).subscribe({
165 complete: function complete() {
166 subject.complete();
167 },
168 error: function error(_error) {
169 subject.error(_error);
170 },
171 next: function next(response) {
172 subject.next(response);
173 }
174 })
175 };
176 } else {
177 nextQueryEntry = prevQueryEntry;
178 }
179
180 pendingQueries.set(cacheKey, nextQueryEntry);
181 return nextQueryEntry;
182}
183
184function cleanup(pendingQueries, entry) {
185 // Reload the entry by its cache key and only invalidate if its the identical
186 // entry instance. This ensures that if the same query/variables are fetched
187 // successively that a timeout/expiration from an earlier fetch doesn't clear
188 // a subsequent fetch.
189 var currentEntry = pendingQueries.get(entry.cacheKey);
190
191 if (currentEntry != null && currentEntry === entry) {
192 if (currentEntry.kind === 'network') {
193 currentEntry.subscription.unsubscribe();
194 }
195
196 pendingQueries["delete"](currentEntry.cacheKey);
197 }
198}
199
200module.exports = preloadQuery;
\No newline at end of file