Skip to content
Merged
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
25 changes: 2 additions & 23 deletions packages/query-db-collection/src/query.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { QueryObserver, hashKey } from "@tanstack/query-core"
import { DeduplicatedLoadSubset } from "@tanstack/db"
import {
GetKeyRequiredError,
QueryClientRequiredError,
Expand Down Expand Up @@ -824,21 +823,6 @@ export function queryCollectionOptions(
return handleQueryResult
}

// This function is called when a loadSubset call is deduplicated
// meaning that we have all the data locally available to answer the query
// so we execute the query locally
const createLocalQuery = (opts: LoadSubsetOptions) => {
const queryFn = ({ meta }: QueryFunctionContext<any>) => {
const inserts = collection.currentStateAsChanges(
meta!.loadSubsetOptions as LoadSubsetOptions
)!
const data = inserts.map(({ value }) => value)
return Promise.resolve(data)
}

createQueryFromOpts(opts, queryFn)
}

const isSubscribed = (hashedQueryKey: string) => {
return unsubscribes.has(hashedQueryKey)
}
Expand Down Expand Up @@ -972,15 +956,10 @@ export function queryCollectionOptions(
// This prevents redundant snapshot requests when multiple concurrent
// live queries request overlapping or subset predicates
const loadSubsetDedupe =
syncMode === `eager`
? undefined
: new DeduplicatedLoadSubset({
loadSubset: createQueryFromOpts,
onDeduplicate: createLocalQuery,
})
syncMode === `eager` ? undefined : createQueryFromOpts

return {
loadSubset: loadSubsetDedupe?.loadSubset,
loadSubset: loadSubsetDedupe,
cleanup,
}
}
Expand Down
17 changes: 9 additions & 8 deletions packages/query-db-collection/tests/query.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3424,7 +3424,7 @@ describe(`QueryCollection`, () => {
expect(collection.has(`4`)).toBe(false)
})

it(`should deduplicate queries and handle GC correctly when queries are ordered and have a LIMIT`, async () => {
it(`should handle GC correctly when queries are ordered and have a LIMIT`, async () => {
const baseQueryKey = [`deduplication-gc-test`]

// Mock queryFn to return different data based on predicates
Expand All @@ -3434,12 +3434,14 @@ describe(`QueryCollection`, () => {
const { where, limit } = loadSubsetOptions

// Query 1: all items with category A (no limit)
if (isCategory(`A`, where) && !limit) {
return Promise.resolve([
if (isCategory(`A`, where)) {
const items = [
{ id: `1`, name: `Item 1`, category: `A` },
{ id: `2`, name: `Item 2`, category: `A` },
{ id: `3`, name: `Item 3`, category: `A` },
])
]
// Slice to limit if provided
return Promise.resolve(limit ? items.slice(0, limit) : items)
}

return Promise.resolve([])
Expand Down Expand Up @@ -3510,10 +3512,9 @@ describe(`QueryCollection`, () => {

await flushPromises()

// Second query should still only have been called once
// since query2 is deduplicated so it is executed against the local collection
// and not via queryFn
expect(queryFn).toHaveBeenCalledTimes(1)
// queryFn should have been called twice
// because we do not dedupe the 2nd query
expect(queryFn).toHaveBeenCalledTimes(2)

// Collection should still have all 3 items (deduplication doesn't remove data)
expect(collection.size).toBe(3)
Expand Down
Loading