Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
487 changes: 487 additions & 0 deletions ANALYSIS_REPORT.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/query-broadcast-client-experimental/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export function broadcastQueryClient({
})
}

if (queryEvent.type === 'removed' && observers.length > 0) {
if (queryEvent.type === 'removed' && observers.size > 0) {
channel.postMessage({
type: 'removed',
queryHash,
Expand Down
75 changes: 44 additions & 31 deletions packages/query-core/src/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ export class Query<
#cache: QueryCache
#client: QueryClient
#retryer?: Retryer<TData>
observers: Array<QueryObserver<any, any, any, any, any>>
observers: Set<QueryObserver<any, any, any, any, any>>
#defaultOptions?: QueryOptions<TQueryFnData, TError, TData, TQueryKey>
#abortSignalConsumed: boolean

Expand All @@ -182,7 +182,7 @@ export class Query<
this.#abortSignalConsumed = false
this.#defaultOptions = config.defaultOptions
this.setOptions(config.options)
this.observers = []
this.observers = new Set()
this.#client = config.client
this.#cache = this.#client.getQueryCache()
this.queryKey = config.queryKey
Expand Down Expand Up @@ -219,7 +219,7 @@ export class Query<
}

protected optionalRemove() {
if (!this.observers.length && this.state.fetchStatus === 'idle') {
if (this.observers.size === 0 && this.state.fetchStatus === 'idle') {
this.#cache.remove(this)
}
}
Expand Down Expand Up @@ -266,9 +266,12 @@ export class Query<
}

isActive(): boolean {
return this.observers.some(
(observer) => resolveEnabled(observer.options.enabled, this) !== false,
)
for (const observer of this.observers) {
if (resolveEnabled(observer.options.enabled, this) !== false) {
return true
}
}
return false
}

isDisabled(): boolean {
Expand All @@ -283,23 +286,25 @@ export class Query<
}

isStatic(): boolean {
if (this.getObserversCount() > 0) {
return this.observers.some(
(observer) =>
resolveStaleTime(observer.options.staleTime, this) === 'static',
)
for (const observer of this.observers) {
if (resolveStaleTime(observer.options.staleTime, this) === 'static') {
return true
}
}

return false
}

isStale(): boolean {
// check observers first, their `isStale` has the source of truth
// calculated with `isStaleByTime` and it takes `enabled` into account
if (this.getObserversCount() > 0) {
return this.observers.some(
(observer) => observer.getCurrentResult().isStale,
)
for (const observer of this.observers) {
if (observer.getCurrentResult().isStale) {
return true
}
}

if (this.observers.size > 0) {
return false
}

return this.state.data === undefined || this.state.isInvalidated
Expand All @@ -323,26 +328,32 @@ export class Query<
}

onFocus(): void {
const observer = this.observers.find((x) => x.shouldFetchOnWindowFocus())

observer?.refetch({ cancelRefetch: false })
for (const observer of this.observers) {
if (observer.shouldFetchOnWindowFocus()) {
observer.refetch({ cancelRefetch: false })
break
}
}

// Continue fetch if currently paused
this.#retryer?.continue()
}

onOnline(): void {
const observer = this.observers.find((x) => x.shouldFetchOnReconnect())

observer?.refetch({ cancelRefetch: false })
for (const observer of this.observers) {
if (observer.shouldFetchOnReconnect()) {
observer.refetch({ cancelRefetch: false })
break
}
}

// Continue fetch if currently paused
this.#retryer?.continue()
}

addObserver(observer: QueryObserver<any, any, any, any, any>): void {
if (!this.observers.includes(observer)) {
this.observers.push(observer)
if (!this.observers.has(observer)) {
this.observers.add(observer)

// Stop the query from being garbage collected
this.clearGcTimeout()
Expand All @@ -352,10 +363,10 @@ export class Query<
}

removeObserver(observer: QueryObserver<any, any, any, any, any>): void {
if (this.observers.includes(observer)) {
this.observers = this.observers.filter((x) => x !== observer)
if (this.observers.has(observer)) {
this.observers.delete(observer)

if (!this.observers.length) {
if (this.observers.size === 0) {
// If the transport layer does not support cancellation
// we'll let the query continue so the result can be cached
if (this.#retryer) {
Expand All @@ -374,7 +385,7 @@ export class Query<
}

getObserversCount(): number {
return this.observers.length
return this.observers.size
}

invalidate(): void {
Expand Down Expand Up @@ -413,9 +424,11 @@ export class Query<
// Use the options from the first observer with a query function if no function is found.
// This can happen when the query is hydrated or created with setQueryData.
if (!this.options.queryFn) {
const observer = this.observers.find((x) => x.options.queryFn)
if (observer) {
this.setOptions(observer.options)
for (const observer of this.observers) {
if (observer.options.queryFn) {
this.setOptions(observer.options)
break
}
}
}

Expand Down
14 changes: 14 additions & 0 deletions packages/query-core/src/queryCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,20 @@ export class QueryCache extends Subscribable<QueryCacheListener> {
: queries
}

countMatching(filters: QueryFilters<any> = {}): number {
const hasFilters = Object.keys(filters).length > 0
if (!hasFilters) {
return this.getAll().length
}
let count = 0
for (const query of this.#queries.values()) {
if (matchQuery(filters, query)) {
count++
}
}
return count
}

notify(event: QueryCacheNotifyEvent): void {
notifyManager.batch(() => {
this.listeners.forEach((listener) => {
Expand Down
Loading