Skip to content

Commit 192dd2c

Browse files
committed
fix: auto-start sync for on-demand collections to enable write operations
On-demand collections were throwing SyncNotInitializedError when users tried to call writeUpsert or other write operations. This happened because the sync function was only invoked when startSync: true was explicitly set, but write operations require the sync infrastructure to be initialized. For on-demand collections, starting sync is cheap (no data is fetched until loadSubset is called), so we now automatically start sync when syncMode is 'on-demand'. This ensures write operations work immediately while maintaining the on-demand loading behavior. Fixes the issue where users with on-demand collections could not manually insert related records using writeUpsert.
1 parent 4eb7671 commit 192dd2c

File tree

2 files changed

+69
-2
lines changed

2 files changed

+69
-2
lines changed

packages/db/src/collection/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,11 @@ export class CollectionImpl<
310310
events: this._events,
311311
})
312312

313-
// Only start sync immediately if explicitly enabled
314-
if (config.startSync === true) {
313+
// Start sync immediately if:
314+
// 1. Explicitly enabled via startSync: true
315+
// 2. Collection uses on-demand sync mode - sync must be started for write
316+
// operations to work, but no data will be fetched until loadSubset is called
317+
if (config.startSync === true || config.syncMode === `on-demand`) {
315318
this._sync.startSync()
316319
}
317320
}

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

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1622,6 +1622,70 @@ describe(`QueryCollection`, () => {
16221622
expect(collection.has(`1`)).toBe(false)
16231623
})
16241624

1625+
it(`should allow write operations on on-demand collections without startSync`, async () => {
1626+
// This test verifies that on-demand collections can perform write operations
1627+
// even when startSync is not explicitly set to true.
1628+
// See: https://github.com/TanStack/db/issues/xyz - SyncNotInitializedError
1629+
// was thrown when trying to writeUpsert on on-demand collections
1630+
1631+
const queryKey = [`on-demand-write-test`]
1632+
const queryFn = vi.fn().mockResolvedValue([])
1633+
1634+
const config: QueryCollectionConfig<TestItem> = {
1635+
id: `on-demand-write-collection`,
1636+
queryClient,
1637+
queryKey,
1638+
queryFn,
1639+
getKey,
1640+
syncMode: `on-demand`,
1641+
// Note: startSync is NOT set to true - this was the bug scenario
1642+
}
1643+
1644+
const options = queryCollectionOptions(config)
1645+
const collection = createCollection(options)
1646+
1647+
// On-demand collections should be ready immediately
1648+
await vi.waitFor(() => {
1649+
expect(collection.status).toBe(`ready`)
1650+
})
1651+
1652+
// Write operations should work without throwing SyncNotInitializedError
1653+
const newItem: TestItem = { id: `1`, name: `Item 1`, value: 10 }
1654+
collection.utils.writeInsert(newItem)
1655+
1656+
expect(collection.size).toBe(1)
1657+
expect(collection.get(`1`)).toEqual(newItem)
1658+
1659+
// Test writeUpsert (the specific operation from the bug report)
1660+
collection.utils.writeUpsert({ id: `2`, name: `Item 2`, value: 20 })
1661+
1662+
expect(collection.size).toBe(2)
1663+
expect(collection.get(`2`)).toEqual({
1664+
id: `2`,
1665+
name: `Item 2`,
1666+
value: 20,
1667+
})
1668+
1669+
// Test writeUpdate
1670+
collection.utils.writeUpdate({ id: `1`, name: `Updated Item 1` })
1671+
expect(collection.get(`1`)?.name).toBe(`Updated Item 1`)
1672+
1673+
// Test writeDelete
1674+
collection.utils.writeDelete(`1`)
1675+
expect(collection.size).toBe(1)
1676+
expect(collection.has(`1`)).toBe(false)
1677+
1678+
// Test writeBatch
1679+
collection.utils.writeBatch(() => {
1680+
collection.utils.writeInsert({ id: `3`, name: `Item 3`, value: 30 })
1681+
collection.utils.writeUpsert({ id: `4`, name: `Item 4`, value: 40 })
1682+
})
1683+
1684+
expect(collection.size).toBe(3)
1685+
expect(collection.get(`3`)?.name).toBe(`Item 3`)
1686+
expect(collection.get(`4`)?.name).toBe(`Item 4`)
1687+
})
1688+
16251689
it(`should handle sync method errors appropriately`, async () => {
16261690
const queryKey = [`sync-error-test`]
16271691
const initialItems: Array<TestItem> = [{ id: `1`, name: `Item 1` }]

0 commit comments

Comments
 (0)