UNPKG

@tanstack/query-core

Version:

The framework agnostic core that powers TanStack Query

506 lines (505 loc) 22.4 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __typeError = (msg) => { throw TypeError(msg); }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg); var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)); var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value); var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value); var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method); // src/queryObserver.ts var queryObserver_exports = {}; __export(queryObserver_exports, { QueryObserver: () => QueryObserver }); module.exports = __toCommonJS(queryObserver_exports); var import_focusManager = require("./focusManager.cjs"); var import_notifyManager = require("./notifyManager.cjs"); var import_query = require("./query.cjs"); var import_subscribable = require("./subscribable.cjs"); var import_thenable = require("./thenable.cjs"); var import_utils = require("./utils.cjs"); var _client, _currentQuery, _currentQueryInitialState, _currentResult, _currentResultState, _currentResultOptions, _currentThenable, _selectError, _selectFn, _selectResult, _lastQueryWithDefinedData, _staleTimeoutId, _refetchIntervalId, _currentRefetchInterval, _trackedProps, _QueryObserver_instances, executeFetch_fn, updateStaleTimeout_fn, computeRefetchInterval_fn, updateRefetchInterval_fn, updateTimers_fn, clearStaleTimeout_fn, clearRefetchInterval_fn, updateQuery_fn, notify_fn; var QueryObserver = class extends import_subscribable.Subscribable { constructor(client, options) { super(); this.options = options; __privateAdd(this, _QueryObserver_instances); __privateAdd(this, _client); __privateAdd(this, _currentQuery); __privateAdd(this, _currentQueryInitialState); __privateAdd(this, _currentResult); __privateAdd(this, _currentResultState); __privateAdd(this, _currentResultOptions); __privateAdd(this, _currentThenable); __privateAdd(this, _selectError); __privateAdd(this, _selectFn); __privateAdd(this, _selectResult); // This property keeps track of the last query with defined data. // It will be used to pass the previous data and query to the placeholder function between renders. __privateAdd(this, _lastQueryWithDefinedData); __privateAdd(this, _staleTimeoutId); __privateAdd(this, _refetchIntervalId); __privateAdd(this, _currentRefetchInterval); __privateAdd(this, _trackedProps, /* @__PURE__ */ new Set()); __privateSet(this, _client, client); __privateSet(this, _selectError, null); __privateSet(this, _currentThenable, (0, import_thenable.pendingThenable)()); if (!this.options.experimental_prefetchInRender) { __privateGet(this, _currentThenable).reject( new Error("experimental_prefetchInRender feature flag is not enabled") ); } this.bindMethods(); this.setOptions(options); } bindMethods() { this.refetch = this.refetch.bind(this); } onSubscribe() { if (this.listeners.size === 1) { __privateGet(this, _currentQuery).addObserver(this); if (shouldFetchOnMount(__privateGet(this, _currentQuery), this.options)) { __privateMethod(this, _QueryObserver_instances, executeFetch_fn).call(this); } else { this.updateResult(); } __privateMethod(this, _QueryObserver_instances, updateTimers_fn).call(this); } } onUnsubscribe() { if (!this.hasListeners()) { this.destroy(); } } shouldFetchOnReconnect() { return shouldFetchOn( __privateGet(this, _currentQuery), this.options, this.options.refetchOnReconnect ); } shouldFetchOnWindowFocus() { return shouldFetchOn( __privateGet(this, _currentQuery), this.options, this.options.refetchOnWindowFocus ); } destroy() { this.listeners = /* @__PURE__ */ new Set(); __privateMethod(this, _QueryObserver_instances, clearStaleTimeout_fn).call(this); __privateMethod(this, _QueryObserver_instances, clearRefetchInterval_fn).call(this); __privateGet(this, _currentQuery).removeObserver(this); } setOptions(options) { const prevOptions = this.options; const prevQuery = __privateGet(this, _currentQuery); this.options = __privateGet(this, _client).defaultQueryOptions(options); if (this.options.enabled !== void 0 && typeof this.options.enabled !== "boolean" && typeof this.options.enabled !== "function" && typeof (0, import_utils.resolveEnabled)(this.options.enabled, __privateGet(this, _currentQuery)) !== "boolean") { throw new Error( "Expected enabled to be a boolean or a callback that returns a boolean" ); } __privateMethod(this, _QueryObserver_instances, updateQuery_fn).call(this); __privateGet(this, _currentQuery).setOptions(this.options); if (prevOptions._defaulted && !(0, import_utils.shallowEqualObjects)(this.options, prevOptions)) { __privateGet(this, _client).getQueryCache().notify({ type: "observerOptionsUpdated", query: __privateGet(this, _currentQuery), observer: this }); } const mounted = this.hasListeners(); if (mounted && shouldFetchOptionally( __privateGet(this, _currentQuery), prevQuery, this.options, prevOptions )) { __privateMethod(this, _QueryObserver_instances, executeFetch_fn).call(this); } this.updateResult(); if (mounted && (__privateGet(this, _currentQuery) !== prevQuery || (0, import_utils.resolveEnabled)(this.options.enabled, __privateGet(this, _currentQuery)) !== (0, import_utils.resolveEnabled)(prevOptions.enabled, __privateGet(this, _currentQuery)) || (0, import_utils.resolveStaleTime)(this.options.staleTime, __privateGet(this, _currentQuery)) !== (0, import_utils.resolveStaleTime)(prevOptions.staleTime, __privateGet(this, _currentQuery)))) { __privateMethod(this, _QueryObserver_instances, updateStaleTimeout_fn).call(this); } const nextRefetchInterval = __privateMethod(this, _QueryObserver_instances, computeRefetchInterval_fn).call(this); if (mounted && (__privateGet(this, _currentQuery) !== prevQuery || (0, import_utils.resolveEnabled)(this.options.enabled, __privateGet(this, _currentQuery)) !== (0, import_utils.resolveEnabled)(prevOptions.enabled, __privateGet(this, _currentQuery)) || nextRefetchInterval !== __privateGet(this, _currentRefetchInterval))) { __privateMethod(this, _QueryObserver_instances, updateRefetchInterval_fn).call(this, nextRefetchInterval); } } getOptimisticResult(options) { const query = __privateGet(this, _client).getQueryCache().build(__privateGet(this, _client), options); const result = this.createResult(query, options); if (shouldAssignObserverCurrentProperties(this, result)) { __privateSet(this, _currentResult, result); __privateSet(this, _currentResultOptions, this.options); __privateSet(this, _currentResultState, __privateGet(this, _currentQuery).state); } return result; } getCurrentResult() { return __privateGet(this, _currentResult); } trackResult(result, onPropTracked) { return new Proxy(result, { get: (target, key) => { this.trackProp(key); onPropTracked == null ? void 0 : onPropTracked(key); return Reflect.get(target, key); } }); } trackProp(key) { __privateGet(this, _trackedProps).add(key); } getCurrentQuery() { return __privateGet(this, _currentQuery); } refetch({ ...options } = {}) { return this.fetch({ ...options }); } fetchOptimistic(options) { const defaultedOptions = __privateGet(this, _client).defaultQueryOptions(options); const query = __privateGet(this, _client).getQueryCache().build(__privateGet(this, _client), defaultedOptions); return query.fetch().then(() => this.createResult(query, defaultedOptions)); } fetch(fetchOptions) { return __privateMethod(this, _QueryObserver_instances, executeFetch_fn).call(this, { ...fetchOptions, cancelRefetch: fetchOptions.cancelRefetch ?? true }).then(() => { this.updateResult(); return __privateGet(this, _currentResult); }); } createResult(query, options) { var _a; const prevQuery = __privateGet(this, _currentQuery); const prevOptions = this.options; const prevResult = __privateGet(this, _currentResult); const prevResultState = __privateGet(this, _currentResultState); const prevResultOptions = __privateGet(this, _currentResultOptions); const queryChange = query !== prevQuery; const queryInitialState = queryChange ? query.state : __privateGet(this, _currentQueryInitialState); const { state } = query; let newState = { ...state }; let isPlaceholderData = false; let data; if (options._optimisticResults) { const mounted = this.hasListeners(); const fetchOnMount = !mounted && shouldFetchOnMount(query, options); const fetchOptionally = mounted && shouldFetchOptionally(query, prevQuery, options, prevOptions); if (fetchOnMount || fetchOptionally) { newState = { ...newState, ...(0, import_query.fetchState)(state.data, query.options) }; } if (options._optimisticResults === "isRestoring") { newState.fetchStatus = "idle"; } } let { error, errorUpdatedAt, status } = newState; data = newState.data; let skipSelect = false; if (options.placeholderData !== void 0 && data === void 0 && status === "pending") { let placeholderData; if ((prevResult == null ? void 0 : prevResult.isPlaceholderData) && options.placeholderData === (prevResultOptions == null ? void 0 : prevResultOptions.placeholderData)) { placeholderData = prevResult.data; skipSelect = true; } else { placeholderData = typeof options.placeholderData === "function" ? options.placeholderData( (_a = __privateGet(this, _lastQueryWithDefinedData)) == null ? void 0 : _a.state.data, __privateGet(this, _lastQueryWithDefinedData) ) : options.placeholderData; } if (placeholderData !== void 0) { status = "success"; data = (0, import_utils.replaceData)( prevResult == null ? void 0 : prevResult.data, placeholderData, options ); isPlaceholderData = true; } } if (options.select && data !== void 0 && !skipSelect) { if (prevResult && data === (prevResultState == null ? void 0 : prevResultState.data) && options.select === __privateGet(this, _selectFn)) { data = __privateGet(this, _selectResult); } else { try { __privateSet(this, _selectFn, options.select); data = options.select(data); data = (0, import_utils.replaceData)(prevResult == null ? void 0 : prevResult.data, data, options); __privateSet(this, _selectResult, data); __privateSet(this, _selectError, null); } catch (selectError) { __privateSet(this, _selectError, selectError); } } } if (__privateGet(this, _selectError)) { error = __privateGet(this, _selectError); data = __privateGet(this, _selectResult); errorUpdatedAt = Date.now(); status = "error"; } const isFetching = newState.fetchStatus === "fetching"; const isPending = status === "pending"; const isError = status === "error"; const isLoading = isPending && isFetching; const hasData = data !== void 0; const result = { status, fetchStatus: newState.fetchStatus, isPending, isSuccess: status === "success", isError, isInitialLoading: isLoading, isLoading, data, dataUpdatedAt: newState.dataUpdatedAt, error, errorUpdatedAt, failureCount: newState.fetchFailureCount, failureReason: newState.fetchFailureReason, errorUpdateCount: newState.errorUpdateCount, isFetched: newState.dataUpdateCount > 0 || newState.errorUpdateCount > 0, isFetchedAfterMount: newState.dataUpdateCount > queryInitialState.dataUpdateCount || newState.errorUpdateCount > queryInitialState.errorUpdateCount, isFetching, isRefetching: isFetching && !isPending, isLoadingError: isError && !hasData, isPaused: newState.fetchStatus === "paused", isPlaceholderData, isRefetchError: isError && hasData, isStale: isStale(query, options), refetch: this.refetch, promise: __privateGet(this, _currentThenable) }; const nextResult = result; if (this.options.experimental_prefetchInRender) { const finalizeThenableIfPossible = (thenable) => { if (nextResult.status === "error") { thenable.reject(nextResult.error); } else if (nextResult.data !== void 0) { thenable.resolve(nextResult.data); } }; const recreateThenable = () => { const pending = __privateSet(this, _currentThenable, nextResult.promise = (0, import_thenable.pendingThenable)()); finalizeThenableIfPossible(pending); }; const prevThenable = __privateGet(this, _currentThenable); switch (prevThenable.status) { case "pending": if (query.queryHash === prevQuery.queryHash) { finalizeThenableIfPossible(prevThenable); } break; case "fulfilled": if (nextResult.status === "error" || nextResult.data !== prevThenable.value) { recreateThenable(); } break; case "rejected": if (nextResult.status !== "error" || nextResult.error !== prevThenable.reason) { recreateThenable(); } break; } } return nextResult; } updateResult() { const prevResult = __privateGet(this, _currentResult); const nextResult = this.createResult(__privateGet(this, _currentQuery), this.options); __privateSet(this, _currentResultState, __privateGet(this, _currentQuery).state); __privateSet(this, _currentResultOptions, this.options); if (__privateGet(this, _currentResultState).data !== void 0) { __privateSet(this, _lastQueryWithDefinedData, __privateGet(this, _currentQuery)); } if ((0, import_utils.shallowEqualObjects)(nextResult, prevResult)) { return; } __privateSet(this, _currentResult, nextResult); const shouldNotifyListeners = () => { if (!prevResult) { return true; } const { notifyOnChangeProps } = this.options; const notifyOnChangePropsValue = typeof notifyOnChangeProps === "function" ? notifyOnChangeProps() : notifyOnChangeProps; if (notifyOnChangePropsValue === "all" || !notifyOnChangePropsValue && !__privateGet(this, _trackedProps).size) { return true; } const includedProps = new Set( notifyOnChangePropsValue ?? __privateGet(this, _trackedProps) ); if (this.options.throwOnError) { includedProps.add("error"); } return Object.keys(__privateGet(this, _currentResult)).some((key) => { const typedKey = key; const changed = __privateGet(this, _currentResult)[typedKey] !== prevResult[typedKey]; return changed && includedProps.has(typedKey); }); }; __privateMethod(this, _QueryObserver_instances, notify_fn).call(this, { listeners: shouldNotifyListeners() }); } onQueryUpdate() { this.updateResult(); if (this.hasListeners()) { __privateMethod(this, _QueryObserver_instances, updateTimers_fn).call(this); } } }; _client = new WeakMap(); _currentQuery = new WeakMap(); _currentQueryInitialState = new WeakMap(); _currentResult = new WeakMap(); _currentResultState = new WeakMap(); _currentResultOptions = new WeakMap(); _currentThenable = new WeakMap(); _selectError = new WeakMap(); _selectFn = new WeakMap(); _selectResult = new WeakMap(); _lastQueryWithDefinedData = new WeakMap(); _staleTimeoutId = new WeakMap(); _refetchIntervalId = new WeakMap(); _currentRefetchInterval = new WeakMap(); _trackedProps = new WeakMap(); _QueryObserver_instances = new WeakSet(); executeFetch_fn = function(fetchOptions) { __privateMethod(this, _QueryObserver_instances, updateQuery_fn).call(this); let promise = __privateGet(this, _currentQuery).fetch( this.options, fetchOptions ); if (!(fetchOptions == null ? void 0 : fetchOptions.throwOnError)) { promise = promise.catch(import_utils.noop); } return promise; }; updateStaleTimeout_fn = function() { __privateMethod(this, _QueryObserver_instances, clearStaleTimeout_fn).call(this); const staleTime = (0, import_utils.resolveStaleTime)( this.options.staleTime, __privateGet(this, _currentQuery) ); if (import_utils.isServer || __privateGet(this, _currentResult).isStale || !(0, import_utils.isValidTimeout)(staleTime)) { return; } const time = (0, import_utils.timeUntilStale)(__privateGet(this, _currentResult).dataUpdatedAt, staleTime); const timeout = time + 1; __privateSet(this, _staleTimeoutId, setTimeout(() => { if (!__privateGet(this, _currentResult).isStale) { this.updateResult(); } }, timeout)); }; computeRefetchInterval_fn = function() { return (typeof this.options.refetchInterval === "function" ? this.options.refetchInterval(__privateGet(this, _currentQuery)) : this.options.refetchInterval) ?? false; }; updateRefetchInterval_fn = function(nextInterval) { __privateMethod(this, _QueryObserver_instances, clearRefetchInterval_fn).call(this); __privateSet(this, _currentRefetchInterval, nextInterval); if (import_utils.isServer || (0, import_utils.resolveEnabled)(this.options.enabled, __privateGet(this, _currentQuery)) === false || !(0, import_utils.isValidTimeout)(__privateGet(this, _currentRefetchInterval)) || __privateGet(this, _currentRefetchInterval) === 0) { return; } __privateSet(this, _refetchIntervalId, setInterval(() => { if (this.options.refetchIntervalInBackground || import_focusManager.focusManager.isFocused()) { __privateMethod(this, _QueryObserver_instances, executeFetch_fn).call(this); } }, __privateGet(this, _currentRefetchInterval))); }; updateTimers_fn = function() { __privateMethod(this, _QueryObserver_instances, updateStaleTimeout_fn).call(this); __privateMethod(this, _QueryObserver_instances, updateRefetchInterval_fn).call(this, __privateMethod(this, _QueryObserver_instances, computeRefetchInterval_fn).call(this)); }; clearStaleTimeout_fn = function() { if (__privateGet(this, _staleTimeoutId)) { clearTimeout(__privateGet(this, _staleTimeoutId)); __privateSet(this, _staleTimeoutId, void 0); } }; clearRefetchInterval_fn = function() { if (__privateGet(this, _refetchIntervalId)) { clearInterval(__privateGet(this, _refetchIntervalId)); __privateSet(this, _refetchIntervalId, void 0); } }; updateQuery_fn = function() { const query = __privateGet(this, _client).getQueryCache().build(__privateGet(this, _client), this.options); if (query === __privateGet(this, _currentQuery)) { return; } const prevQuery = __privateGet(this, _currentQuery); __privateSet(this, _currentQuery, query); __privateSet(this, _currentQueryInitialState, query.state); if (this.hasListeners()) { prevQuery == null ? void 0 : prevQuery.removeObserver(this); query.addObserver(this); } }; notify_fn = function(notifyOptions) { import_notifyManager.notifyManager.batch(() => { if (notifyOptions.listeners) { this.listeners.forEach((listener) => { listener(__privateGet(this, _currentResult)); }); } __privateGet(this, _client).getQueryCache().notify({ query: __privateGet(this, _currentQuery), type: "observerResultsUpdated" }); }); }; function shouldLoadOnMount(query, options) { return (0, import_utils.resolveEnabled)(options.enabled, query) !== false && query.state.data === void 0 && !(query.state.status === "error" && options.retryOnMount === false); } function shouldFetchOnMount(query, options) { return shouldLoadOnMount(query, options) || query.state.data !== void 0 && shouldFetchOn(query, options, options.refetchOnMount); } function shouldFetchOn(query, options, field) { if ((0, import_utils.resolveEnabled)(options.enabled, query) !== false) { const value = typeof field === "function" ? field(query) : field; return value === "always" || value !== false && isStale(query, options); } return false; } function shouldFetchOptionally(query, prevQuery, options, prevOptions) { return (query !== prevQuery || (0, import_utils.resolveEnabled)(prevOptions.enabled, query) === false) && (!options.suspense || query.state.status !== "error") && isStale(query, options); } function isStale(query, options) { return (0, import_utils.resolveEnabled)(options.enabled, query) !== false && query.isStaleByTime((0, import_utils.resolveStaleTime)(options.staleTime, query)); } function shouldAssignObserverCurrentProperties(observer, optimisticResult) { if (!(0, import_utils.shallowEqualObjects)(observer.getCurrentResult(), optimisticResult)) { return true; } return false; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { QueryObserver }); //# sourceMappingURL=queryObserver.cjs.map