@@ -2,7 +2,10 @@ import { beforeEach, describe, expect, it } from "vitest"
22import { createCollection } from "../../src/collection.js"
33import { createLiveQueryCollection , eq } from "../../src/query/index.js"
44import { Query } from "../../src/query/builder/index.js"
5- import { mockSyncCollectionOptions } from "../utls.js"
5+ import {
6+ mockSyncCollectionOptions ,
7+ mockSyncCollectionOptionsNoInitialState ,
8+ } from "../utls.js"
69import type { ChangeMessage } from "../../src/types.js"
710
811// Sample user type for tests
@@ -313,4 +316,92 @@ describe(`createLiveQueryCollection`, () => {
313316 // Resubscribe should not throw (would throw "Graph already finalized" without the fix)
314317 expect ( ( ) => liveQuery . subscribeChanges ( ( ) => { } ) ) . not . toThrow ( )
315318 } )
319+
320+ for ( const autoIndex of [ `eager` , `off` ] as const ) {
321+ it ( `should not send the initial state twice on joins with autoIndex: ${ autoIndex } ` , async ( ) => {
322+ type Player = { id : number ; name : string }
323+ type Challenge = { id : number ; value : number }
324+
325+ const playerCollection = createCollection (
326+ mockSyncCollectionOptionsNoInitialState < Player > ( {
327+ id : `player` ,
328+ getKey : ( post ) => post . id ,
329+ autoIndex,
330+ } )
331+ )
332+
333+ const challenge1Collection = createCollection (
334+ mockSyncCollectionOptionsNoInitialState < Challenge > ( {
335+ id : `challenge1` ,
336+ getKey : ( post ) => post . id ,
337+ autoIndex,
338+ } )
339+ )
340+
341+ const challenge2Collection = createCollection (
342+ mockSyncCollectionOptionsNoInitialState < Challenge > ( {
343+ id : `challenge2` ,
344+ getKey : ( post ) => post . id ,
345+ autoIndex,
346+ } )
347+ )
348+
349+ const liveQuery = createLiveQueryCollection ( ( q ) =>
350+ q
351+ . from ( { player : playerCollection } )
352+ . leftJoin (
353+ { challenge1 : challenge1Collection } ,
354+ ( { player, challenge1 } ) => eq ( player . id , challenge1 . id )
355+ )
356+ . leftJoin (
357+ { challenge2 : challenge2Collection } ,
358+ ( { player, challenge2 } ) => eq ( player . id , challenge2 . id )
359+ )
360+ )
361+
362+ // Start the query, but don't wait it, we are doing to write the data to the
363+ // source collections while the query is loading the initial state
364+ const preloadPromise = liveQuery . preload ( )
365+
366+ // Write player
367+ playerCollection . utils . begin ( )
368+ playerCollection . utils . write ( {
369+ type : `insert` ,
370+ value : { id : 1 , name : `Alice` } ,
371+ } )
372+ playerCollection . utils . commit ( )
373+ playerCollection . utils . markReady ( )
374+
375+ // Write challenge1
376+ challenge1Collection . utils . begin ( )
377+ challenge1Collection . utils . write ( {
378+ type : `insert` ,
379+ value : { id : 1 , value : 100 } ,
380+ } )
381+ challenge1Collection . utils . commit ( )
382+ challenge1Collection . utils . markReady ( )
383+
384+ // Write challenge2
385+ challenge2Collection . utils . begin ( )
386+ challenge2Collection . utils . write ( {
387+ type : `insert` ,
388+ value : { id : 1 , value : 200 } ,
389+ } )
390+ challenge2Collection . utils . commit ( )
391+ challenge2Collection . utils . markReady ( )
392+
393+ await preloadPromise
394+
395+ // With a failed test the results show more than 1 item
396+ // It returns both an unjoined player with no joined challenges, and a joined
397+ // player with the challenges
398+ const results = liveQuery . toArray
399+ expect ( results . length ) . toBe ( 1 )
400+
401+ const result = results [ 0 ] !
402+ expect ( result . player . name ) . toBe ( `Alice` )
403+ expect ( result . challenge1 ?. value ) . toBe ( 100 )
404+ expect ( result . challenge2 ?. value ) . toBe ( 200 )
405+ } )
406+ }
316407} )
0 commit comments