UNPKG

@apollo/client

Version:

A fully-featured caching GraphQL client.

563 lines 24 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, fixObservableSubclass, getQueryDefinition, } from "../utilities/index.js"; import { equalByQuery } from "./equalByQuery.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.waitForOwnResult = skipCacheDataFor(options.fetchPolicy); _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.lastQuery || this.options.query; }, 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 (skipCacheDataFor(fetchPolicy) || this.queryManager.getDocumentInfo(this.query).hasForcedResolvers) { } else if (this.waitForOwnResult) { this.queryInfo["updateWatch"](); } 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 (globalThis.__DEV__ !== false && !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) { if (!this.last) { return true; } var resultIsDifferent = this.queryManager.getDocumentInfo(this.query) .hasNonreactiveDirective ? !equalByQuery(this.query, this.last.result, newResult, this.variables) : !equal(this.last.result, newResult); return (resultIsDifferent || (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 (globalThis.__DEV__ !== false && 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"; })) { globalThis.__DEV__ !== false && invariant.warn( 18, variables, ((_a = queryDef.name) === null || _a === void 0 ? void 0 : _a.value) || queryDef ); } } 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.options.query }), fetchMoreOptions), { variables: __assign(__assign({}, this.options.variables), fetchMoreOptions.variables) }))), { fetchPolicy: "no-cache" }); combinedOptions.query = this.transformDocument(combinedOptions.query); var qid = this.queryManager.generateQueryId(); this.lastQuery = fetchMoreOptions.query ? this.transformDocument(this.options.query) : combinedOptions.query; 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; } globalThis.__DEV__ !== false && invariant.error(19, 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.silentSetOptions = function (newOptions) { var mergedOptions = compact(this.options, newOptions || {}); assign(this.options, mergedOptions); }; 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["fetchConcastWithInfo"](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; } invariant(pollInterval, 20); 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; } var error = this.getLastError(); if (error && this.last && !equal(variables, this.last.variables)) { error = void 0; } return (this.last = __assign({ result: this.queryManager.assumeImmutableResults ? newResult : cloneDeep(newResult), variables: variables }, (error ? { error: error } : null))); }; ObservableQuery.prototype.reobserveAsConcast = 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); var query = this.transformDocument(options.query); this.lastQuery = query; 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 fetchOptions = query === options.query ? options : __assign(__assign({}, options), { query: query }); this.waitForOwnResult && (this.waitForOwnResult = skipCacheDataFor(fetchOptions.fetchPolicy)); var finishWaitingForOwnResult = function () { if (_this.concast === concast) { _this.waitForOwnResult = false; } }; var variables = fetchOptions.variables && __assign({}, fetchOptions.variables); var _a = this.fetch(fetchOptions, newNetworkStatus), concast = _a.concast, fromLink = _a.fromLink; var observer = { next: function (result) { finishWaitingForOwnResult(); _this.reportResult(result, variables); }, error: function (error) { finishWaitingForOwnResult(); _this.reportError(error, variables); }, }; if (!useDisposableConcast && (fromLink || !this.concast)) { if (this.concast && this.observer) { this.concast.removeObserver(this.observer); } this.concast = concast; this.observer = observer; } concast.addObserver(observer); return concast; }; ObservableQuery.prototype.reobserve = function (newOptions, newNetworkStatus) { return this.reobserveAsConcast(newOptions, newNetworkStatus).promise; }; ObservableQuery.prototype.resubscribeAfterError = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var last = this.last; this.resetLastResults(); var subscription = this.subscribe.apply(this, args); this.last = last; return subscription; }; ObservableQuery.prototype.observe = function () { this.reportResult(this.getCurrentResult(false), this.variables); }; ObservableQuery.prototype.reportResult = function (result, variables) { var lastError = this.getLastError(); var isDifferent = this.isDifferentFromLastResult(result, variables); if (lastError || !result.partial || this.options.returnPartialData) { this.updateLastResult(result, variables); } if (lastError || isDifferent) { 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; }; ObservableQuery.prototype.transformDocument = function (document) { return this.queryManager.transform(document); }; 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) { globalThis.__DEV__ !== false && invariant.error(21, error.message, error.stack); } export function logMissingFieldErrors(missing) { if (globalThis.__DEV__ !== false && missing) { globalThis.__DEV__ !== false && invariant.debug(22, missing); } } function skipCacheDataFor(fetchPolicy) { return (fetchPolicy === "network-only" || fetchPolicy === "no-cache" || fetchPolicy === "standby"); } //# sourceMappingURL=ObservableQuery.js.map