@@ -3,6 +3,7 @@ import { createCollection } from "../../src/collection.js"
3
3
import { createLiveQueryCollection , eq } from "../../src/query/index.js"
4
4
import { Query } from "../../src/query/builder/index.js"
5
5
import { mockSyncCollectionOptions } from "../utls.js"
6
+ import type { ChangeMessage } from "../../src/types.js"
6
7
7
8
// Sample user type for tests
8
9
type User = {
@@ -189,4 +190,102 @@ describe(`createLiveQueryCollection`, () => {
189
190
} )
190
191
expect ( liveQuery . isReady ( ) ) . toBe ( false )
191
192
} )
193
+
194
+ it ( `should update after source collection is loaded even when not preloaded before rendering` , async ( ) => {
195
+ // Create a source collection that doesn't start sync immediately
196
+ let beginCallback : ( ( ) => void ) | undefined
197
+ let writeCallback :
198
+ | ( ( message : Omit < ChangeMessage < User , string | number > , `key`> ) => void )
199
+ | undefined
200
+ let markReadyCallback : ( ( ) => void ) | undefined
201
+ let commitCallback : ( ( ) => void ) | undefined
202
+
203
+ const sourceCollection = createCollection < User > ( {
204
+ id : `delayed-source-collection` ,
205
+ getKey : ( user ) => user . id ,
206
+ startSync : false , // Don't start sync immediately
207
+ sync : {
208
+ sync : ( { begin, commit, write, markReady } ) => {
209
+ beginCallback = begin
210
+ commitCallback = commit
211
+ markReadyCallback = markReady
212
+ writeCallback = write
213
+ return ( ) => { } // cleanup function
214
+ } ,
215
+ } ,
216
+ onInsert : ( { transaction } ) => {
217
+ const newItem = transaction . mutations [ 0 ] . modified
218
+ // We need to call begin, write, and commit to properly sync the data
219
+ beginCallback ! ( )
220
+ writeCallback ! ( {
221
+ type : `insert` ,
222
+ value : newItem ,
223
+ } )
224
+ commitCallback ! ( )
225
+ return Promise . resolve ( )
226
+ } ,
227
+ onUpdate : ( ) => Promise . resolve ( ) ,
228
+ onDelete : ( ) => Promise . resolve ( ) ,
229
+ } )
230
+
231
+ // Create a live query collection BEFORE the source collection is preloaded
232
+ // This simulates the scenario where the live query is created during rendering
233
+ // but the source collection hasn't been preloaded yet
234
+ const liveQuery = createLiveQueryCollection ( ( q ) =>
235
+ q
236
+ . from ( { user : sourceCollection } )
237
+ . where ( ( { user } ) => eq ( user . active , true ) )
238
+ )
239
+
240
+ // Initially, the live query should be in idle state (default startSync: false)
241
+ expect ( liveQuery . status ) . toBe ( `idle` )
242
+ expect ( liveQuery . size ) . toBe ( 0 )
243
+
244
+ // Now preload the source collection (simulating what happens after rendering)
245
+ sourceCollection . preload ( )
246
+
247
+ // Store the promise so we can wait for it later
248
+ const preloadPromise = liveQuery . preload ( )
249
+
250
+ // Trigger the initial data load first
251
+ if ( beginCallback && writeCallback && commitCallback && markReadyCallback ) {
252
+ beginCallback ( )
253
+ // Write initial data
254
+ writeCallback ( {
255
+ type : `insert` ,
256
+ value : { id : 1 , name : `Alice` , active : true } ,
257
+ } )
258
+ writeCallback ( {
259
+ type : `insert` ,
260
+ value : { id : 2 , name : `Bob` , active : false } ,
261
+ } )
262
+ writeCallback ( {
263
+ type : `insert` ,
264
+ value : { id : 3 , name : `Charlie` , active : true } ,
265
+ } )
266
+ commitCallback ( )
267
+ markReadyCallback ( )
268
+ }
269
+
270
+ // Wait for the preload to complete
271
+ await preloadPromise
272
+
273
+ // The live query should be ready and have the initial data
274
+ expect ( liveQuery . size ) . toBe ( 2 ) // Alice and Charlie are active
275
+ expect ( liveQuery . get ( 1 ) ) . toEqual ( { id : 1 , name : `Alice` , active : true } )
276
+ expect ( liveQuery . get ( 3 ) ) . toEqual ( { id : 3 , name : `Charlie` , active : true } )
277
+ expect ( liveQuery . get ( 2 ) ) . toBeUndefined ( ) // Bob is not active
278
+ // This test should fail because the live query is stuck in 'initialCommit' status
279
+ expect ( liveQuery . status ) . toBe ( `ready` ) // This should be 'ready' but is currently 'initialCommit'
280
+
281
+ // Now add some new data to the source collection (this should work as per the original report)
282
+ sourceCollection . insert ( { id : 4 , name : `David` , active : true } )
283
+
284
+ // Wait for the mutation to propagate
285
+ await new Promise ( ( resolve ) => setTimeout ( resolve , 10 ) )
286
+
287
+ // The live query should update to include the new data
288
+ expect ( liveQuery . size ) . toBe ( 3 ) // Alice, Charlie, and David are active
289
+ expect ( liveQuery . get ( 4 ) ) . toEqual ( { id : 4 , name : `David` , active : true } )
290
+ } )
192
291
} )
0 commit comments