Skip to content

Commit 3b7556f

Browse files
jmtoungTkDodoautofix-ci[bot]
authored
fix(QueriesObserver): fix improper sorting in QueriesObserver's #find… (#8351)
* fix(QueriesObserver): fix improper sorting in QueriesObserver's #findMatchingObservers method This commit fixes a bug in the QueriesObserver's #findMatchingObservers. The bug is present when there are duplicate unsorted queries, for example, ['A', 'B', 'A']. The bug results in #findMatchingObservers to return the queries in sorted order, or ['A', 'A', 'B'], which results in a mismatch between Array<QueryObserverOptions> and Array<QueryObserverMatch>. This bug was introduced in 5499577 * ci: apply automated fixes --------- Co-authored-by: Dominik Dorfmeister <[email protected]> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent dfe2cd1 commit 3b7556f

File tree

2 files changed

+70
-16
lines changed

2 files changed

+70
-16
lines changed

packages/query-core/src/__tests__/queriesObserver.test.tsx

+68
Original file line numberDiff line numberDiff line change
@@ -264,4 +264,72 @@ describe('queriesObserver', () => {
264264
// Clean-up
265265
unsubscribe2()
266266
})
267+
268+
test('should handle duplicate query keys in different positions', async () => {
269+
const key1 = queryKey()
270+
const key2 = queryKey()
271+
const queryFn1 = vi.fn().mockReturnValue(1)
272+
const queryFn2 = vi.fn().mockReturnValue(2)
273+
274+
const observer = new QueriesObserver(queryClient, [
275+
{ queryKey: key1, queryFn: queryFn1 },
276+
{ queryKey: key2, queryFn: queryFn2 },
277+
{ queryKey: key1, queryFn: queryFn1 },
278+
])
279+
280+
const results: Array<Array<QueryObserverResult>> = []
281+
results.push(
282+
observer.getOptimisticResult(
283+
[
284+
{ queryKey: key1, queryFn: queryFn1 },
285+
{ queryKey: key2, queryFn: queryFn2 },
286+
{ queryKey: key1, queryFn: queryFn1 },
287+
],
288+
undefined,
289+
)[0],
290+
)
291+
292+
const unsubscribe = observer.subscribe((result) => {
293+
results.push(result)
294+
})
295+
296+
await sleep(1)
297+
unsubscribe()
298+
299+
expect(results.length).toBe(6)
300+
expect(results[0]).toMatchObject([
301+
{ status: 'pending', fetchStatus: 'idle', data: undefined },
302+
{ status: 'pending', fetchStatus: 'idle', data: undefined },
303+
{ status: 'pending', fetchStatus: 'idle', data: undefined },
304+
])
305+
expect(results[1]).toMatchObject([
306+
{ status: 'pending', fetchStatus: 'fetching', data: undefined },
307+
{ status: 'pending', fetchStatus: 'idle', data: undefined },
308+
{ status: 'pending', fetchStatus: 'idle', data: undefined },
309+
])
310+
expect(results[2]).toMatchObject([
311+
{ status: 'pending', fetchStatus: 'fetching', data: undefined },
312+
{ status: 'pending', fetchStatus: 'fetching', data: undefined },
313+
{ status: 'pending', fetchStatus: 'idle', data: undefined },
314+
])
315+
expect(results[3]).toMatchObject([
316+
{ status: 'success', fetchStatus: 'idle', data: 1 },
317+
{ status: 'pending', fetchStatus: 'fetching', data: undefined },
318+
{ status: 'pending', fetchStatus: 'idle', data: undefined },
319+
])
320+
expect(results[4]).toMatchObject([
321+
{ status: 'success', fetchStatus: 'idle', data: 1 },
322+
{ status: 'pending', fetchStatus: 'fetching', data: undefined },
323+
{ status: 'success', fetchStatus: 'idle', data: 1 },
324+
])
325+
expect(results[5]).toMatchObject([
326+
{ status: 'success', fetchStatus: 'idle', data: 1 },
327+
{ status: 'success', fetchStatus: 'idle', data: 2 },
328+
{ status: 'success', fetchStatus: 'idle', data: 1 },
329+
])
330+
331+
// Verify that queryFn1 was only called once despite being used twice
332+
expect(queryFn1).toHaveBeenCalledTimes(1)
333+
expect(queryFn2).toHaveBeenCalledTimes(1)
334+
})
267335
})

packages/query-core/src/queriesObserver.ts

+2-16
Original file line numberDiff line numberDiff line change
@@ -240,28 +240,14 @@ export class QueriesObserver<
240240
observer: match,
241241
})
242242
} else {
243-
const existingObserver = this.#observers.find(
244-
(o) => o.options.queryHash === defaultedOptions.queryHash,
245-
)
246243
observers.push({
247244
defaultedQueryOptions: defaultedOptions,
248-
observer:
249-
existingObserver ??
250-
new QueryObserver(this.#client, defaultedOptions),
245+
observer: new QueryObserver(this.#client, defaultedOptions),
251246
})
252247
}
253248
})
254249

255-
return observers.sort((a, b) => {
256-
return (
257-
queries.findIndex(
258-
(q) => q.queryHash === a.defaultedQueryOptions.queryHash,
259-
) -
260-
queries.findIndex(
261-
(q) => q.queryHash === b.defaultedQueryOptions.queryHash,
262-
)
263-
)
264-
})
250+
return observers
265251
}
266252

267253
#onUpdate(observer: QueryObserver, result: QueryObserverResult): void {

0 commit comments

Comments
 (0)