@tanstack/query-core
Version:
The framework agnostic core that powers TanStack Query
1 lines • 11.5 kB
Source Map (JSON)
{"version":3,"sources":["../../src/queriesObserver.ts"],"sourcesContent":["import { notifyManager } from './notifyManager'\nimport { QueryObserver } from './queryObserver'\nimport { Subscribable } from './subscribable'\nimport { replaceEqualDeep } from './utils'\nimport type {\n DefaultedQueryObserverOptions,\n QueryObserverOptions,\n QueryObserverResult,\n} from './types'\nimport type { QueryClient } from './queryClient'\nimport type { NotifyOptions } from './queryObserver'\n\nfunction difference<T>(array1: Array<T>, array2: Array<T>): Array<T> {\n return array1.filter((x) => !array2.includes(x))\n}\n\nfunction replaceAt<T>(array: Array<T>, index: number, value: T): Array<T> {\n const copy = array.slice(0)\n copy[index] = value\n return copy\n}\n\ntype QueriesObserverListener = (result: Array<QueryObserverResult>) => void\n\nexport interface QueriesObserverOptions<\n TCombinedResult = Array<QueryObserverResult>,\n> {\n combine?: (result: Array<QueryObserverResult>) => TCombinedResult\n}\n\nexport class QueriesObserver<\n TCombinedResult = Array<QueryObserverResult>,\n> extends Subscribable<QueriesObserverListener> {\n #client: QueryClient\n #result!: Array<QueryObserverResult>\n #queries: Array<QueryObserverOptions>\n #observers: Array<QueryObserver>\n #options?: QueriesObserverOptions<TCombinedResult>\n #combinedResult!: TCombinedResult\n\n constructor(\n client: QueryClient,\n queries: Array<QueryObserverOptions>,\n options?: QueriesObserverOptions<TCombinedResult>,\n ) {\n super()\n\n this.#client = client\n this.#queries = []\n this.#observers = []\n\n this.#setResult([])\n this.setQueries(queries, options)\n }\n\n #setResult(value: Array<QueryObserverResult>) {\n this.#result = value\n this.#combinedResult = this.#combineResult(value)\n }\n\n protected onSubscribe(): void {\n if (this.listeners.size === 1) {\n this.#observers.forEach((observer) => {\n observer.subscribe((result) => {\n this.#onUpdate(observer, result)\n })\n })\n }\n }\n\n protected onUnsubscribe(): void {\n if (!this.listeners.size) {\n this.destroy()\n }\n }\n\n destroy(): void {\n this.listeners = new Set()\n this.#observers.forEach((observer) => {\n observer.destroy()\n })\n }\n\n setQueries(\n queries: Array<QueryObserverOptions>,\n options?: QueriesObserverOptions<TCombinedResult>,\n notifyOptions?: NotifyOptions,\n ): void {\n this.#queries = queries\n this.#options = options\n\n notifyManager.batch(() => {\n const prevObservers = this.#observers\n\n const newObserverMatches = this.#findMatchingObservers(this.#queries)\n\n // set options for the new observers to notify of changes\n newObserverMatches.forEach((match) =>\n match.observer.setOptions(match.defaultedQueryOptions, notifyOptions),\n )\n\n const newObservers = newObserverMatches.map((match) => match.observer)\n const newResult = newObservers.map((observer) =>\n observer.getCurrentResult(),\n )\n\n const hasIndexChange = newObservers.some(\n (observer, index) => observer !== prevObservers[index],\n )\n if (prevObservers.length === newObservers.length && !hasIndexChange) {\n return\n }\n\n this.#observers = newObservers\n this.#setResult(newResult)\n\n if (!this.hasListeners()) {\n return\n }\n\n difference(prevObservers, newObservers).forEach((observer) => {\n observer.destroy()\n })\n\n difference(newObservers, prevObservers).forEach((observer) => {\n observer.subscribe((result) => {\n this.#onUpdate(observer, result)\n })\n })\n\n this.#notify()\n })\n }\n\n getCurrentResult(): TCombinedResult {\n return this.#combinedResult\n }\n\n getQueries() {\n return this.#observers.map((observer) => observer.getCurrentQuery())\n }\n\n getObservers() {\n return this.#observers\n }\n\n getOptimisticResult(\n queries: Array<QueryObserverOptions>,\n ): [\n rawResult: Array<QueryObserverResult>,\n combineResult: (r?: Array<QueryObserverResult>) => TCombinedResult,\n trackResult: () => Array<QueryObserverResult>,\n ] {\n const matches = this.#findMatchingObservers(queries)\n const result = matches.map((match) =>\n match.observer.getOptimisticResult(match.defaultedQueryOptions),\n )\n\n return [\n result,\n (r?: Array<QueryObserverResult>) => {\n return this.#combineResult(r ?? result)\n },\n () => {\n return matches.map((match, index) => {\n const observerResult = result[index]!\n return !match.defaultedQueryOptions.notifyOnChangeProps\n ? match.observer.trackResult(observerResult)\n : observerResult\n })\n },\n ]\n }\n\n #combineResult(input: Array<QueryObserverResult>): TCombinedResult {\n const combine = this.#options?.combine\n if (combine) {\n return replaceEqualDeep(this.#combinedResult, combine(input))\n }\n return input as any\n }\n\n #findMatchingObservers(\n queries: Array<QueryObserverOptions>,\n ): Array<QueryObserverMatch> {\n const prevObservers = this.#observers\n const prevObserversMap = new Map(\n prevObservers.map((observer) => [observer.options.queryHash, observer]),\n )\n\n const defaultedQueryOptions = queries.map((options) =>\n this.#client.defaultQueryOptions(options),\n )\n\n const matchingObservers: Array<QueryObserverMatch> =\n defaultedQueryOptions.flatMap((defaultedOptions) => {\n const match = prevObserversMap.get(defaultedOptions.queryHash)\n if (match != null) {\n return [{ defaultedQueryOptions: defaultedOptions, observer: match }]\n }\n return []\n })\n\n const matchedQueryHashes = new Set(\n matchingObservers.map((match) => match.defaultedQueryOptions.queryHash),\n )\n const unmatchedQueries = defaultedQueryOptions.filter(\n (defaultedOptions) => !matchedQueryHashes.has(defaultedOptions.queryHash),\n )\n\n const getObserver = (options: QueryObserverOptions): QueryObserver => {\n const defaultedOptions = this.#client.defaultQueryOptions(options)\n const currentObserver = this.#observers.find(\n (o) => o.options.queryHash === defaultedOptions.queryHash,\n )\n return (\n currentObserver ?? new QueryObserver(this.#client, defaultedOptions)\n )\n }\n\n const newOrReusedObservers: Array<QueryObserverMatch> =\n unmatchedQueries.map((options) => {\n return {\n defaultedQueryOptions: options,\n observer: getObserver(options),\n }\n })\n\n const sortMatchesByOrderOfQueries = (\n a: QueryObserverMatch,\n b: QueryObserverMatch,\n ): number =>\n defaultedQueryOptions.indexOf(a.defaultedQueryOptions) -\n defaultedQueryOptions.indexOf(b.defaultedQueryOptions)\n\n return matchingObservers\n .concat(newOrReusedObservers)\n .sort(sortMatchesByOrderOfQueries)\n }\n\n #onUpdate(observer: QueryObserver, result: QueryObserverResult): void {\n const index = this.#observers.indexOf(observer)\n if (index !== -1) {\n this.#setResult(replaceAt(this.#result, index, result))\n this.#notify()\n }\n }\n\n #notify(): void {\n notifyManager.batch(() => {\n this.listeners.forEach((listener) => {\n listener(this.#result)\n })\n })\n }\n}\n\ntype QueryObserverMatch = {\n defaultedQueryOptions: DefaultedQueryObserverOptions\n observer: QueryObserver\n}\n"],"mappings":"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","names":[]}