UNPKG

@tanstack/query-core

Version:

The framework agnostic core that powers TanStack Query

452 lines (451 loc) 14.7 kB
import { __privateAdd, __privateGet, __privateMethod, __privateSet } from "./chunk-PXG64RU4.js"; // src/query.ts import { ensureQueryFn, noop, replaceData, resolveEnabled, resolveStaleTime, skipToken, timeUntilStale } from "./utils.js"; import { notifyManager } from "./notifyManager.js"; import { CancelledError, canFetch, createRetryer } from "./retryer.js"; import { Removable } from "./removable.js"; var _initialState, _revertState, _cache, _client, _retryer, _defaultOptions, _abortSignalConsumed, _Query_instances, dispatch_fn; var Query = class extends Removable { constructor(config) { super(); __privateAdd(this, _Query_instances); __privateAdd(this, _initialState); __privateAdd(this, _revertState); __privateAdd(this, _cache); __privateAdd(this, _client); __privateAdd(this, _retryer); __privateAdd(this, _defaultOptions); __privateAdd(this, _abortSignalConsumed); __privateSet(this, _abortSignalConsumed, false); __privateSet(this, _defaultOptions, config.defaultOptions); this.setOptions(config.options); this.observers = []; __privateSet(this, _client, config.client); __privateSet(this, _cache, __privateGet(this, _client).getQueryCache()); this.queryKey = config.queryKey; this.queryHash = config.queryHash; __privateSet(this, _initialState, getDefaultState(this.options)); this.state = config.state ?? __privateGet(this, _initialState); this.scheduleGc(); } get meta() { return this.options.meta; } get promise() { var _a; return (_a = __privateGet(this, _retryer)) == null ? void 0 : _a.promise; } setOptions(options) { this.options = { ...__privateGet(this, _defaultOptions), ...options }; this.updateGcTime(this.options.gcTime); if (this.state && this.state.data === void 0) { const defaultState = getDefaultState(this.options); if (defaultState.data !== void 0) { this.setData(defaultState.data, { updatedAt: defaultState.dataUpdatedAt, manual: true }); __privateSet(this, _initialState, defaultState); } } } optionalRemove() { if (!this.observers.length && this.state.fetchStatus === "idle") { __privateGet(this, _cache).remove(this); } } setData(newData, options) { const data = replaceData(this.state.data, newData, this.options); __privateMethod(this, _Query_instances, dispatch_fn).call(this, { data, type: "success", dataUpdatedAt: options == null ? void 0 : options.updatedAt, manual: options == null ? void 0 : options.manual }); return data; } setState(state, setStateOptions) { __privateMethod(this, _Query_instances, dispatch_fn).call(this, { type: "setState", state, setStateOptions }); } cancel(options) { var _a, _b; const promise = (_a = __privateGet(this, _retryer)) == null ? void 0 : _a.promise; (_b = __privateGet(this, _retryer)) == null ? void 0 : _b.cancel(options); return promise ? promise.then(noop).catch(noop) : Promise.resolve(); } destroy() { super.destroy(); this.cancel({ silent: true }); } reset() { this.destroy(); this.setState(__privateGet(this, _initialState)); } isActive() { return this.observers.some( (observer) => resolveEnabled(observer.options.enabled, this) !== false ); } isDisabled() { if (this.getObserversCount() > 0) { return !this.isActive(); } return this.options.queryFn === skipToken || this.state.dataUpdateCount + this.state.errorUpdateCount === 0; } isStatic() { if (this.getObserversCount() > 0) { return this.observers.some( (observer) => resolveStaleTime(observer.options.staleTime, this) === "static" ); } return false; } isStale() { if (this.getObserversCount() > 0) { return this.observers.some( (observer) => observer.getCurrentResult().isStale ); } return this.state.data === void 0 || this.state.isInvalidated; } isStaleByTime(staleTime = 0) { if (this.state.data === void 0) { return true; } if (staleTime === "static") { return false; } if (this.state.isInvalidated) { return true; } return !timeUntilStale(this.state.dataUpdatedAt, staleTime); } onFocus() { var _a; const observer = this.observers.find((x) => x.shouldFetchOnWindowFocus()); observer == null ? void 0 : observer.refetch({ cancelRefetch: false }); (_a = __privateGet(this, _retryer)) == null ? void 0 : _a.continue(); } onOnline() { var _a; const observer = this.observers.find((x) => x.shouldFetchOnReconnect()); observer == null ? void 0 : observer.refetch({ cancelRefetch: false }); (_a = __privateGet(this, _retryer)) == null ? void 0 : _a.continue(); } addObserver(observer) { if (!this.observers.includes(observer)) { this.observers.push(observer); this.clearGcTimeout(); __privateGet(this, _cache).notify({ type: "observerAdded", query: this, observer }); } } removeObserver(observer) { if (this.observers.includes(observer)) { this.observers = this.observers.filter((x) => x !== observer); if (!this.observers.length) { if (__privateGet(this, _retryer)) { if (__privateGet(this, _abortSignalConsumed)) { __privateGet(this, _retryer).cancel({ revert: true }); } else { __privateGet(this, _retryer).cancelRetry(); } } this.scheduleGc(); } __privateGet(this, _cache).notify({ type: "observerRemoved", query: this, observer }); } } getObserversCount() { return this.observers.length; } invalidate() { if (!this.state.isInvalidated) { __privateMethod(this, _Query_instances, dispatch_fn).call(this, { type: "invalidate" }); } } async fetch(options, fetchOptions) { var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l; if (this.state.fetchStatus !== "idle" && // If the promise in the retyer is already rejected, we have to definitely // re-start the fetch; there is a chance that the query is still in a // pending state when that happens ((_a = __privateGet(this, _retryer)) == null ? void 0 : _a.status()) !== "rejected") { if (this.state.data !== void 0 && (fetchOptions == null ? void 0 : fetchOptions.cancelRefetch)) { this.cancel({ silent: true }); } else if (__privateGet(this, _retryer)) { __privateGet(this, _retryer).continueRetry(); return __privateGet(this, _retryer).promise; } } if (options) { this.setOptions(options); } if (!this.options.queryFn) { const observer = this.observers.find((x) => x.options.queryFn); if (observer) { this.setOptions(observer.options); } } if (process.env.NODE_ENV !== "production") { if (!Array.isArray(this.options.queryKey)) { console.error( `As of v4, queryKey needs to be an Array. If you are using a string like 'repoData', please change it to an Array, e.g. ['repoData']` ); } } const abortController = new AbortController(); const addSignalProperty = (object) => { Object.defineProperty(object, "signal", { enumerable: true, get: () => { __privateSet(this, _abortSignalConsumed, true); return abortController.signal; } }); }; const fetchFn = () => { const queryFn = ensureQueryFn(this.options, fetchOptions); const createQueryFnContext = () => { const queryFnContext2 = { client: __privateGet(this, _client), queryKey: this.queryKey, meta: this.meta }; addSignalProperty(queryFnContext2); return queryFnContext2; }; const queryFnContext = createQueryFnContext(); __privateSet(this, _abortSignalConsumed, false); if (this.options.persister) { return this.options.persister( queryFn, queryFnContext, this ); } return queryFn(queryFnContext); }; const createFetchContext = () => { const context2 = { fetchOptions, options: this.options, queryKey: this.queryKey, client: __privateGet(this, _client), state: this.state, fetchFn }; addSignalProperty(context2); return context2; }; const context = createFetchContext(); (_b = this.options.behavior) == null ? void 0 : _b.onFetch(context, this); __privateSet(this, _revertState, this.state); if (this.state.fetchStatus === "idle" || this.state.fetchMeta !== ((_c = context.fetchOptions) == null ? void 0 : _c.meta)) { __privateMethod(this, _Query_instances, dispatch_fn).call(this, { type: "fetch", meta: (_d = context.fetchOptions) == null ? void 0 : _d.meta }); } __privateSet(this, _retryer, createRetryer({ initialPromise: fetchOptions == null ? void 0 : fetchOptions.initialPromise, fn: context.fetchFn, onCancel: (error) => { if (error instanceof CancelledError && error.revert) { this.setState({ ...__privateGet(this, _revertState), fetchStatus: "idle" }); } abortController.abort(); }, onFail: (failureCount, error) => { __privateMethod(this, _Query_instances, dispatch_fn).call(this, { type: "failed", failureCount, error }); }, onPause: () => { __privateMethod(this, _Query_instances, dispatch_fn).call(this, { type: "pause" }); }, onContinue: () => { __privateMethod(this, _Query_instances, dispatch_fn).call(this, { type: "continue" }); }, retry: context.options.retry, retryDelay: context.options.retryDelay, networkMode: context.options.networkMode, canRun: () => true })); try { const data = await __privateGet(this, _retryer).start(); if (data === void 0) { if (process.env.NODE_ENV !== "production") { console.error( `Query data cannot be undefined. Please make sure to return a value other than undefined from your query function. Affected query key: ${this.queryHash}` ); } throw new Error(`${this.queryHash} data is undefined`); } this.setData(data); (_f = (_e = __privateGet(this, _cache).config).onSuccess) == null ? void 0 : _f.call(_e, data, this); (_h = (_g = __privateGet(this, _cache).config).onSettled) == null ? void 0 : _h.call( _g, data, this.state.error, this ); return data; } catch (error) { if (error instanceof CancelledError) { if (error.silent) { return __privateGet(this, _retryer).promise; } else if (error.revert) { if (this.state.data === void 0) { throw error; } return this.state.data; } } __privateMethod(this, _Query_instances, dispatch_fn).call(this, { type: "error", error }); (_j = (_i = __privateGet(this, _cache).config).onError) == null ? void 0 : _j.call( _i, error, this ); (_l = (_k = __privateGet(this, _cache).config).onSettled) == null ? void 0 : _l.call( _k, this.state.data, error, this ); throw error; } finally { this.scheduleGc(); } } }; _initialState = new WeakMap(); _revertState = new WeakMap(); _cache = new WeakMap(); _client = new WeakMap(); _retryer = new WeakMap(); _defaultOptions = new WeakMap(); _abortSignalConsumed = new WeakMap(); _Query_instances = new WeakSet(); dispatch_fn = function(action) { const reducer = (state) => { switch (action.type) { case "failed": return { ...state, fetchFailureCount: action.failureCount, fetchFailureReason: action.error }; case "pause": return { ...state, fetchStatus: "paused" }; case "continue": return { ...state, fetchStatus: "fetching" }; case "fetch": return { ...state, ...fetchState(state.data, this.options), fetchMeta: action.meta ?? null }; case "success": const newState = { ...state, data: action.data, dataUpdateCount: state.dataUpdateCount + 1, dataUpdatedAt: action.dataUpdatedAt ?? Date.now(), error: null, isInvalidated: false, status: "success", ...!action.manual && { fetchStatus: "idle", fetchFailureCount: 0, fetchFailureReason: null } }; __privateSet(this, _revertState, action.manual ? newState : void 0); return newState; case "error": const error = action.error; return { ...state, error, errorUpdateCount: state.errorUpdateCount + 1, errorUpdatedAt: Date.now(), fetchFailureCount: state.fetchFailureCount + 1, fetchFailureReason: error, fetchStatus: "idle", status: "error" }; case "invalidate": return { ...state, isInvalidated: true }; case "setState": return { ...state, ...action.state }; } }; this.state = reducer(this.state); notifyManager.batch(() => { this.observers.forEach((observer) => { observer.onQueryUpdate(); }); __privateGet(this, _cache).notify({ query: this, type: "updated", action }); }); }; function fetchState(data, options) { return { fetchFailureCount: 0, fetchFailureReason: null, fetchStatus: canFetch(options.networkMode) ? "fetching" : "paused", ...data === void 0 && { error: null, status: "pending" } }; } function getDefaultState(options) { const data = typeof options.initialData === "function" ? options.initialData() : options.initialData; const hasData = data !== void 0; const initialDataUpdatedAt = hasData ? typeof options.initialDataUpdatedAt === "function" ? options.initialDataUpdatedAt() : options.initialDataUpdatedAt : 0; return { data, dataUpdateCount: 0, dataUpdatedAt: hasData ? initialDataUpdatedAt ?? Date.now() : 0, error: null, errorUpdateCount: 0, errorUpdatedAt: 0, fetchFailureCount: 0, fetchFailureReason: null, fetchMeta: null, isInvalidated: false, status: hasData ? "success" : "pending", fetchStatus: "idle" }; } export { Query, fetchState }; //# sourceMappingURL=query.js.map