@apollo/client
Version:
A fully-featured caching GraphQL client.
503 lines • 21.7 kB
JavaScript
import { __assign, __extends } from "tslib";
import { invariant } from "../utilities/globals/index.js";
import { equal } from '@wry/equality';
import { NetworkStatus, isNetworkRequestInFlight } from "./networkStatus.js";
import { cloneDeep, compact, getOperationDefinition, Observable, iterateObserversSafely, isNonEmptyArray, fixObservableSubclass, getQueryDefinition, } from "../utilities/index.js";
var assign = Object.assign, hasOwnProperty = Object.hasOwnProperty;
var ObservableQuery = (function (_super) {
__extends(ObservableQuery, _super);
function ObservableQuery(_a) {
var queryManager = _a.queryManager, queryInfo = _a.queryInfo, options = _a.options;
var _this = _super.call(this, function (observer) {
try {
var subObserver = observer._subscription._observer;
if (subObserver && !subObserver.error) {
subObserver.error = defaultSubscriptionObserverErrorCallback;
}
}
catch (_a) { }
var first = !_this.observers.size;
_this.observers.add(observer);
var last = _this.last;
if (last && last.error) {
observer.error && observer.error(last.error);
}
else if (last && last.result) {
observer.next && observer.next(last.result);
}
if (first) {
_this.reobserve().catch(function () { });
}
return function () {
if (_this.observers.delete(observer) && !_this.observers.size) {
_this.tearDownQuery();
}
};
}) || this;
_this.observers = new Set();
_this.subscriptions = new Set();
_this.queryInfo = queryInfo;
_this.queryManager = queryManager;
_this.isTornDown = false;
var _b = queryManager.defaultOptions.watchQuery, _c = _b === void 0 ? {} : _b, _d = _c.fetchPolicy, defaultFetchPolicy = _d === void 0 ? "cache-first" : _d;
var _e = options.fetchPolicy, fetchPolicy = _e === void 0 ? defaultFetchPolicy : _e, _f = options.initialFetchPolicy, initialFetchPolicy = _f === void 0 ? (fetchPolicy === "standby" ? defaultFetchPolicy : fetchPolicy) : _f;
_this.options = __assign(__assign({}, options), { initialFetchPolicy: initialFetchPolicy, fetchPolicy: fetchPolicy });
_this.queryId = queryInfo.queryId || queryManager.generateQueryId();
var opDef = getOperationDefinition(_this.query);
_this.queryName = opDef && opDef.name && opDef.name.value;
return _this;
}
Object.defineProperty(ObservableQuery.prototype, "query", {
get: function () {
return this.queryManager.transform(this.options.query).document;
},
enumerable: false,
configurable: true
});
Object.defineProperty(ObservableQuery.prototype, "variables", {
get: function () {
return this.options.variables;
},
enumerable: false,
configurable: true
});
ObservableQuery.prototype.result = function () {
var _this = this;
return new Promise(function (resolve, reject) {
var observer = {
next: function (result) {
resolve(result);
_this.observers.delete(observer);
if (!_this.observers.size) {
_this.queryManager.removeQuery(_this.queryId);
}
setTimeout(function () {
subscription.unsubscribe();
}, 0);
},
error: reject,
};
var subscription = _this.subscribe(observer);
});
};
ObservableQuery.prototype.getCurrentResult = function (saveAsLastResult) {
if (saveAsLastResult === void 0) { saveAsLastResult = true; }
var lastResult = this.getLastResult(true);
var networkStatus = this.queryInfo.networkStatus ||
(lastResult && lastResult.networkStatus) ||
NetworkStatus.ready;
var result = __assign(__assign({}, lastResult), { loading: isNetworkRequestInFlight(networkStatus), networkStatus: networkStatus });
var _a = this.options.fetchPolicy, fetchPolicy = _a === void 0 ? "cache-first" : _a;
if (fetchPolicy === 'network-only' ||
fetchPolicy === 'no-cache' ||
fetchPolicy === 'standby' ||
this.queryManager.transform(this.options.query).hasForcedResolvers) {
}
else {
var diff = this.queryInfo.getDiff();
if (diff.complete || this.options.returnPartialData) {
result.data = diff.result;
}
if (equal(result.data, {})) {
result.data = void 0;
}
if (diff.complete) {
delete result.partial;
if (diff.complete &&
result.networkStatus === NetworkStatus.loading &&
(fetchPolicy === 'cache-first' ||
fetchPolicy === 'cache-only')) {
result.networkStatus = NetworkStatus.ready;
result.loading = false;
}
}
else {
result.partial = true;
}
if (__DEV__ &&
!diff.complete &&
!this.options.partialRefetch &&
!result.loading &&
!result.data &&
!result.error) {
logMissingFieldErrors(diff.missing);
}
}
if (saveAsLastResult) {
this.updateLastResult(result);
}
return result;
};
ObservableQuery.prototype.isDifferentFromLastResult = function (newResult, variables) {
return (!this.last ||
!equal(this.last.result, newResult) ||
(variables && !equal(this.last.variables, variables)));
};
ObservableQuery.prototype.getLast = function (key, variablesMustMatch) {
var last = this.last;
if (last &&
last[key] &&
(!variablesMustMatch || equal(last.variables, this.variables))) {
return last[key];
}
};
ObservableQuery.prototype.getLastResult = function (variablesMustMatch) {
return this.getLast("result", variablesMustMatch);
};
ObservableQuery.prototype.getLastError = function (variablesMustMatch) {
return this.getLast("error", variablesMustMatch);
};
ObservableQuery.prototype.resetLastResults = function () {
delete this.last;
this.isTornDown = false;
};
ObservableQuery.prototype.resetQueryStoreErrors = function () {
this.queryManager.resetErrors(this.queryId);
};
ObservableQuery.prototype.refetch = function (variables) {
var _a;
var reobserveOptions = {
pollInterval: 0,
};
var fetchPolicy = this.options.fetchPolicy;
if (fetchPolicy === 'cache-and-network') {
reobserveOptions.fetchPolicy = fetchPolicy;
}
else if (fetchPolicy === 'no-cache') {
reobserveOptions.fetchPolicy = 'no-cache';
}
else {
reobserveOptions.fetchPolicy = 'network-only';
}
if (__DEV__ && variables && hasOwnProperty.call(variables, "variables")) {
var queryDef = getQueryDefinition(this.query);
var vars = queryDef.variableDefinitions;
if (!vars || !vars.some(function (v) { return v.variable.name.value === "variables"; })) {
__DEV__ && invariant.warn("Called refetch(".concat(JSON.stringify(variables), ") for query ").concat(((_a = queryDef.name) === null || _a === void 0 ? void 0 : _a.value) || JSON.stringify(queryDef), ", which does not declare a $variables variable.\nDid you mean to call refetch(variables) instead of refetch({ variables })?"));
}
}
if (variables && !equal(this.options.variables, variables)) {
reobserveOptions.variables = this.options.variables = __assign(__assign({}, this.options.variables), variables);
}
this.queryInfo.resetLastWrite();
return this.reobserve(reobserveOptions, NetworkStatus.refetch);
};
ObservableQuery.prototype.fetchMore = function (fetchMoreOptions) {
var _this = this;
var combinedOptions = __assign(__assign({}, (fetchMoreOptions.query ? fetchMoreOptions : __assign(__assign(__assign(__assign({}, this.options), { query: this.query }), fetchMoreOptions), { variables: __assign(__assign({}, this.options.variables), fetchMoreOptions.variables) }))), { fetchPolicy: "no-cache" });
var qid = this.queryManager.generateQueryId();
var queryInfo = this.queryInfo;
var originalNetworkStatus = queryInfo.networkStatus;
queryInfo.networkStatus = NetworkStatus.fetchMore;
if (combinedOptions.notifyOnNetworkStatusChange) {
this.observe();
}
var updatedQuerySet = new Set();
return this.queryManager.fetchQuery(qid, combinedOptions, NetworkStatus.fetchMore).then(function (fetchMoreResult) {
_this.queryManager.removeQuery(qid);
if (queryInfo.networkStatus === NetworkStatus.fetchMore) {
queryInfo.networkStatus = originalNetworkStatus;
}
_this.queryManager.cache.batch({
update: function (cache) {
var updateQuery = fetchMoreOptions.updateQuery;
if (updateQuery) {
cache.updateQuery({
query: _this.query,
variables: _this.variables,
returnPartialData: true,
optimistic: false,
}, function (previous) { return updateQuery(previous, {
fetchMoreResult: fetchMoreResult.data,
variables: combinedOptions.variables,
}); });
}
else {
cache.writeQuery({
query: combinedOptions.query,
variables: combinedOptions.variables,
data: fetchMoreResult.data,
});
}
},
onWatchUpdated: function (watch) {
updatedQuerySet.add(watch.query);
},
});
return fetchMoreResult;
}).finally(function () {
if (!updatedQuerySet.has(_this.query)) {
reobserveCacheFirst(_this);
}
});
};
ObservableQuery.prototype.subscribeToMore = function (options) {
var _this = this;
var subscription = this.queryManager
.startGraphQLSubscription({
query: options.document,
variables: options.variables,
context: options.context,
})
.subscribe({
next: function (subscriptionData) {
var updateQuery = options.updateQuery;
if (updateQuery) {
_this.updateQuery(function (previous, _a) {
var variables = _a.variables;
return updateQuery(previous, {
subscriptionData: subscriptionData,
variables: variables,
});
});
}
},
error: function (err) {
if (options.onError) {
options.onError(err);
return;
}
__DEV__ && invariant.error('Unhandled GraphQL subscription error', err);
},
});
this.subscriptions.add(subscription);
return function () {
if (_this.subscriptions.delete(subscription)) {
subscription.unsubscribe();
}
};
};
ObservableQuery.prototype.setOptions = function (newOptions) {
return this.reobserve(newOptions);
};
ObservableQuery.prototype.setVariables = function (variables) {
if (equal(this.variables, variables)) {
return this.observers.size
? this.result()
: Promise.resolve();
}
this.options.variables = variables;
if (!this.observers.size) {
return Promise.resolve();
}
return this.reobserve({
fetchPolicy: this.options.initialFetchPolicy,
variables: variables,
}, NetworkStatus.setVariables);
};
ObservableQuery.prototype.updateQuery = function (mapFn) {
var queryManager = this.queryManager;
var result = queryManager.cache.diff({
query: this.options.query,
variables: this.variables,
returnPartialData: true,
optimistic: false,
}).result;
var newResult = mapFn(result, {
variables: this.variables,
});
if (newResult) {
queryManager.cache.writeQuery({
query: this.options.query,
data: newResult,
variables: this.variables,
});
queryManager.broadcastQueries();
}
};
ObservableQuery.prototype.startPolling = function (pollInterval) {
this.options.pollInterval = pollInterval;
this.updatePolling();
};
ObservableQuery.prototype.stopPolling = function () {
this.options.pollInterval = 0;
this.updatePolling();
};
ObservableQuery.prototype.applyNextFetchPolicy = function (reason, options) {
if (options.nextFetchPolicy) {
var _a = options.fetchPolicy, fetchPolicy = _a === void 0 ? "cache-first" : _a, _b = options.initialFetchPolicy, initialFetchPolicy = _b === void 0 ? fetchPolicy : _b;
if (fetchPolicy === "standby") {
}
else if (typeof options.nextFetchPolicy === "function") {
options.fetchPolicy = options.nextFetchPolicy(fetchPolicy, {
reason: reason,
options: options,
observable: this,
initialFetchPolicy: initialFetchPolicy,
});
}
else if (reason === "variables-changed") {
options.fetchPolicy = initialFetchPolicy;
}
else {
options.fetchPolicy = options.nextFetchPolicy;
}
}
return options.fetchPolicy;
};
ObservableQuery.prototype.fetch = function (options, newNetworkStatus) {
this.queryManager.setObservableQuery(this);
return this.queryManager.fetchQueryObservable(this.queryId, options, newNetworkStatus);
};
ObservableQuery.prototype.updatePolling = function () {
var _this = this;
if (this.queryManager.ssrMode) {
return;
}
var _a = this, pollingInfo = _a.pollingInfo, pollInterval = _a.options.pollInterval;
if (!pollInterval) {
if (pollingInfo) {
clearTimeout(pollingInfo.timeout);
delete this.pollingInfo;
}
return;
}
if (pollingInfo &&
pollingInfo.interval === pollInterval) {
return;
}
__DEV__ ? invariant(pollInterval, 'Attempted to start a polling query without a polling interval.') : invariant(pollInterval, 13);
var info = pollingInfo || (this.pollingInfo = {});
info.interval = pollInterval;
var maybeFetch = function () {
if (_this.pollingInfo) {
if (!isNetworkRequestInFlight(_this.queryInfo.networkStatus)) {
_this.reobserve({
fetchPolicy: _this.options.initialFetchPolicy === 'no-cache' ? 'no-cache' : 'network-only',
}, NetworkStatus.poll).then(poll, poll);
}
else {
poll();
}
}
;
};
var poll = function () {
var info = _this.pollingInfo;
if (info) {
clearTimeout(info.timeout);
info.timeout = setTimeout(maybeFetch, info.interval);
}
};
poll();
};
ObservableQuery.prototype.updateLastResult = function (newResult, variables) {
if (variables === void 0) { variables = this.variables; }
this.last = __assign(__assign({}, this.last), { result: this.queryManager.assumeImmutableResults
? newResult
: cloneDeep(newResult), variables: variables });
if (!isNonEmptyArray(newResult.errors)) {
delete this.last.error;
}
return this.last;
};
ObservableQuery.prototype.reobserve = function (newOptions, newNetworkStatus) {
var _this = this;
this.isTornDown = false;
var useDisposableConcast = newNetworkStatus === NetworkStatus.refetch ||
newNetworkStatus === NetworkStatus.fetchMore ||
newNetworkStatus === NetworkStatus.poll;
var oldVariables = this.options.variables;
var oldFetchPolicy = this.options.fetchPolicy;
var mergedOptions = compact(this.options, newOptions || {});
var options = useDisposableConcast
? mergedOptions
: assign(this.options, mergedOptions);
if (!useDisposableConcast) {
this.updatePolling();
if (newOptions &&
newOptions.variables &&
!equal(newOptions.variables, oldVariables) &&
options.fetchPolicy !== "standby" &&
options.fetchPolicy === oldFetchPolicy) {
this.applyNextFetchPolicy("variables-changed", options);
if (newNetworkStatus === void 0) {
newNetworkStatus = NetworkStatus.setVariables;
}
}
}
var variables = options.variables && __assign({}, options.variables);
var concast = this.fetch(options, newNetworkStatus);
var observer = {
next: function (result) {
_this.reportResult(result, variables);
},
error: function (error) {
_this.reportError(error, variables);
},
};
if (!useDisposableConcast) {
if (this.concast && this.observer) {
this.concast.removeObserver(this.observer);
}
this.concast = concast;
this.observer = observer;
}
concast.addObserver(observer);
return concast.promise;
};
ObservableQuery.prototype.observe = function () {
this.reportResult(this.getCurrentResult(false), this.variables);
};
ObservableQuery.prototype.reportResult = function (result, variables) {
var lastError = this.getLastError();
if (lastError || this.isDifferentFromLastResult(result, variables)) {
if (lastError || !result.partial || this.options.returnPartialData) {
this.updateLastResult(result, variables);
}
iterateObserversSafely(this.observers, 'next', result);
}
};
ObservableQuery.prototype.reportError = function (error, variables) {
var errorResult = __assign(__assign({}, this.getLastResult()), { error: error, errors: error.graphQLErrors, networkStatus: NetworkStatus.error, loading: false });
this.updateLastResult(errorResult, variables);
iterateObserversSafely(this.observers, 'error', this.last.error = error);
};
ObservableQuery.prototype.hasObservers = function () {
return this.observers.size > 0;
};
ObservableQuery.prototype.tearDownQuery = function () {
if (this.isTornDown)
return;
if (this.concast && this.observer) {
this.concast.removeObserver(this.observer);
delete this.concast;
delete this.observer;
}
this.stopPolling();
this.subscriptions.forEach(function (sub) { return sub.unsubscribe(); });
this.subscriptions.clear();
this.queryManager.stopQuery(this.queryId);
this.observers.clear();
this.isTornDown = true;
};
return ObservableQuery;
}(Observable));
export { ObservableQuery };
fixObservableSubclass(ObservableQuery);
export function reobserveCacheFirst(obsQuery) {
var _a = obsQuery.options, fetchPolicy = _a.fetchPolicy, nextFetchPolicy = _a.nextFetchPolicy;
if (fetchPolicy === "cache-and-network" ||
fetchPolicy === "network-only") {
return obsQuery.reobserve({
fetchPolicy: "cache-first",
nextFetchPolicy: function () {
this.nextFetchPolicy = nextFetchPolicy;
if (typeof nextFetchPolicy === "function") {
return nextFetchPolicy.apply(this, arguments);
}
return fetchPolicy;
},
});
}
return obsQuery.reobserve();
}
function defaultSubscriptionObserverErrorCallback(error) {
__DEV__ && invariant.error('Unhandled error', error.message, error.stack);
}
export function logMissingFieldErrors(missing) {
if (__DEV__ && missing) {
__DEV__ && invariant.debug("Missing cache result fields: ".concat(JSON.stringify(missing)), missing);
}
}
//# sourceMappingURL=ObservableQuery.js.map