Skip to content

Commit 5bd4525

Browse files
committed
feat: implement exact targeting for refetching queries to prevent unintended cascading effects
1 parent 05776f5 commit 5bd4525

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

packages/query-db-collection/src/query.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,7 @@ export function queryCollectionOptions(
601601
return queryClient.refetchQueries(
602602
{
603603
queryKey: queryKey,
604+
exact: true,
604605
},
605606
{
606607
throwOnError: opts?.throwOnError,

packages/query-db-collection/tests/query.test.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1958,6 +1958,81 @@ describe(`QueryCollection`, () => {
19581958
})
19591959
})
19601960

1961+
it(`should use exact targeting when refetching to avoid unintended cascading of related queries`, async () => {
1962+
// Create multiple collections with related but distinct query keys
1963+
const queryKey = [`todos`]
1964+
const queryKey1 = [`todos`, `project-1`]
1965+
const queryKey2 = [`todos`, `project-2`]
1966+
1967+
const mockItems = [{ id: `1`, name: `Item 1` }]
1968+
const queryFn = vi.fn().mockResolvedValue(mockItems)
1969+
const queryFn1 = vi.fn().mockResolvedValue(mockItems)
1970+
const queryFn2 = vi.fn().mockResolvedValue(mockItems)
1971+
1972+
const config: QueryCollectionConfig<TestItem> = {
1973+
id: `all-todos`,
1974+
queryClient,
1975+
queryKey: queryKey,
1976+
queryFn: queryFn,
1977+
getKey,
1978+
startSync: true,
1979+
}
1980+
const config1: QueryCollectionConfig<TestItem> = {
1981+
id: `project-1-todos`,
1982+
queryClient,
1983+
queryKey: queryKey1,
1984+
queryFn: queryFn1,
1985+
getKey,
1986+
startSync: true,
1987+
}
1988+
const config2: QueryCollectionConfig<TestItem> = {
1989+
id: `project-2-todos`,
1990+
queryClient,
1991+
queryKey: queryKey2,
1992+
queryFn: queryFn2,
1993+
getKey,
1994+
startSync: true,
1995+
}
1996+
1997+
const options = queryCollectionOptions(config)
1998+
const options1 = queryCollectionOptions(config1)
1999+
const options2 = queryCollectionOptions(config2)
2000+
2001+
const collection = createCollection(options)
2002+
const collection1 = createCollection(options1)
2003+
const collection2 = createCollection(options2)
2004+
2005+
// Wait for initial queries to complete
2006+
await vi.waitFor(() => {
2007+
expect(queryFn).toHaveBeenCalledTimes(1)
2008+
expect(queryFn1).toHaveBeenCalledTimes(1)
2009+
expect(queryFn2).toHaveBeenCalledTimes(1)
2010+
expect(collection.status).toBe(`ready`)
2011+
})
2012+
2013+
// Reset call counts to test refetch behavior
2014+
queryFn.mockClear()
2015+
queryFn1.mockClear()
2016+
queryFn2.mockClear()
2017+
2018+
// Refetch the target collection with key ['todos', 'project-1']
2019+
await collection1.utils.refetch()
2020+
2021+
// Verify that only the target query was refetched
2022+
await vi.waitFor(() => {
2023+
expect(queryFn1).toHaveBeenCalledTimes(1)
2024+
expect(queryFn).not.toHaveBeenCalled()
2025+
expect(queryFn2).not.toHaveBeenCalled()
2026+
})
2027+
2028+
// Cleanup
2029+
await Promise.all([
2030+
collection.cleanup(),
2031+
collection1.cleanup(),
2032+
collection2.cleanup(),
2033+
])
2034+
})
2035+
19612036
describe(`Error Handling`, () => {
19622037
// Helper to create test collection with common configuration
19632038
const createErrorHandlingTestCollection = (

0 commit comments

Comments
 (0)