@tanstack/query-core
Version:
The framework agnostic core that powers TanStack Query
177 lines • 5.6 kB
JavaScript
// src/queriesObserver.ts
import { notifyManager } from "./notifyManager.js";
import { QueryObserver } from "./queryObserver.js";
import { Subscribable } from "./subscribable.js";
import { replaceEqualDeep } from "./utils.js";
function difference(array1, array2) {
return array1.filter((x) => !array2.includes(x));
}
function replaceAt(array, index, value) {
const copy = array.slice(0);
copy[index] = value;
return copy;
}
var QueriesObserver = class extends Subscribable {
#client;
#result;
#queries;
#observers;
#options;
#combinedResult;
constructor(client, queries, options) {
super();
this.#client = client;
this.#queries = [];
this.#observers = [];
this.#setResult([]);
this.setQueries(queries, options);
}
#setResult(value) {
this.#result = value;
this.#combinedResult = this.#combineResult(value);
}
onSubscribe() {
if (this.listeners.size === 1) {
this.#observers.forEach((observer) => {
observer.subscribe((result) => {
this.#onUpdate(observer, result);
});
});
}
}
onUnsubscribe() {
if (!this.listeners.size) {
this.destroy();
}
}
destroy() {
this.listeners = /* @__PURE__ */ new Set();
this.#observers.forEach((observer) => {
observer.destroy();
});
}
setQueries(queries, options, notifyOptions) {
this.#queries = queries;
this.#options = options;
notifyManager.batch(() => {
const prevObservers = this.#observers;
const newObserverMatches = this.#findMatchingObservers(this.#queries);
newObserverMatches.forEach(
(match) => match.observer.setOptions(match.defaultedQueryOptions, notifyOptions)
);
const newObservers = newObserverMatches.map((match) => match.observer);
const newResult = newObservers.map(
(observer) => observer.getCurrentResult()
);
const hasIndexChange = newObservers.some(
(observer, index) => observer !== prevObservers[index]
);
if (prevObservers.length === newObservers.length && !hasIndexChange) {
return;
}
this.#observers = newObservers;
this.#setResult(newResult);
if (!this.hasListeners()) {
return;
}
difference(prevObservers, newObservers).forEach((observer) => {
observer.destroy();
});
difference(newObservers, prevObservers).forEach((observer) => {
observer.subscribe((result) => {
this.#onUpdate(observer, result);
});
});
this.#notify();
});
}
getCurrentResult() {
return this.#combinedResult;
}
getQueries() {
return this.#observers.map((observer) => observer.getCurrentQuery());
}
getObservers() {
return this.#observers;
}
getOptimisticResult(queries) {
const matches = this.#findMatchingObservers(queries);
const result = matches.map(
(match) => match.observer.getOptimisticResult(match.defaultedQueryOptions)
);
return [
result,
(r) => {
return this.#combineResult(r ?? result);
},
() => {
return matches.map((match, index) => {
const observerResult = result[index];
return !match.defaultedQueryOptions.notifyOnChangeProps ? match.observer.trackResult(observerResult) : observerResult;
});
}
];
}
#combineResult(input) {
const combine = this.#options?.combine;
if (combine) {
return replaceEqualDeep(this.#combinedResult, combine(input));
}
return input;
}
#findMatchingObservers(queries) {
const prevObservers = this.#observers;
const prevObserversMap = new Map(
prevObservers.map((observer) => [observer.options.queryHash, observer])
);
const defaultedQueryOptions = queries.map(
(options) => this.#client.defaultQueryOptions(options)
);
const matchingObservers = defaultedQueryOptions.flatMap((defaultedOptions) => {
const match = prevObserversMap.get(defaultedOptions.queryHash);
if (match != null) {
return [{ defaultedQueryOptions: defaultedOptions, observer: match }];
}
return [];
});
const matchedQueryHashes = new Set(
matchingObservers.map((match) => match.defaultedQueryOptions.queryHash)
);
const unmatchedQueries = defaultedQueryOptions.filter(
(defaultedOptions) => !matchedQueryHashes.has(defaultedOptions.queryHash)
);
const getObserver = (options) => {
const defaultedOptions = this.#client.defaultQueryOptions(options);
const currentObserver = this.#observers.find(
(o) => o.options.queryHash === defaultedOptions.queryHash
);
return currentObserver ?? new QueryObserver(this.#client, defaultedOptions);
};
const newOrReusedObservers = unmatchedQueries.map((options) => {
return {
defaultedQueryOptions: options,
observer: getObserver(options)
};
});
const sortMatchesByOrderOfQueries = (a, b) => defaultedQueryOptions.indexOf(a.defaultedQueryOptions) - defaultedQueryOptions.indexOf(b.defaultedQueryOptions);
return matchingObservers.concat(newOrReusedObservers).sort(sortMatchesByOrderOfQueries);
}
#onUpdate(observer, result) {
const index = this.#observers.indexOf(observer);
if (index !== -1) {
this.#setResult(replaceAt(this.#result, index, result));
this.#notify();
}
}
#notify() {
notifyManager.batch(() => {
this.listeners.forEach((listener) => {
listener(this.#result);
});
});
}
};
export {
QueriesObserver
};
//# sourceMappingURL=queriesObserver.js.map