UNPKG

@apollo/client

Version:

A fully-featured caching GraphQL client.

503 lines 21.7 kB
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