@@ -2,6 +2,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
22import { QueryClient } from "@tanstack/query-core"
33import { createCollection } from "@tanstack/db"
44import { queryCollectionOptions } from "../src/query"
5+ import { Func , PropRef , Value } from "../../db/src/query/ir"
56import type { QueryFunctionContext } from "@tanstack/query-core"
67import type {
78 CollectionImpl ,
@@ -18,6 +19,12 @@ interface TestItem {
1819 value ?: number
1920}
2021
22+ interface CategorisedItem {
23+ id : string
24+ name : string
25+ category : string
26+ }
27+
2128const getKey = ( item : TestItem ) => item . id
2229
2330// Helper to advance timers and allow microtasks to flush
@@ -2462,10 +2469,10 @@ describe(`QueryCollection`, () => {
24622469 const queryFn = vi . fn ( ) . mockImplementation ( ( context ) => {
24632470 const { meta } = context
24642471 const loadSubsetOptions = meta ?. loadSubsetOptions ?? { }
2465- const { where, orderBy , limit } = loadSubsetOptions
2472+ const { where } = loadSubsetOptions
24662473
2467- // Query 1: items 1, 2, 3 (no predicates )
2468- if ( ! where && ! orderBy && ! limit ) {
2474+ // Query 1: items 1, 2, 3 (where: { category: 'A' } )
2475+ if ( where ?. category === `A` ) {
24692476 return Promise . resolve ( [
24702477 { id : `1` , name : `Item 1` } ,
24712478 { id : `2` , name : `Item 2` } ,
@@ -2517,7 +2524,7 @@ describe(`QueryCollection`, () => {
25172524 expect ( collection . size ) . toBe ( 0 )
25182525
25192526 // Load query 1 with no predicates (items 1, 2, 3)
2520- await collection . _sync . loadSubset ( { } )
2527+ await collection . _sync . loadSubset ( { where : { category : `A` } } as any )
25212528
25222529 // Wait for query 1 data to load
25232530 await vi . waitFor ( ( ) => {
@@ -2551,7 +2558,10 @@ describe(`QueryCollection`, () => {
25512558
25522559 // GC query 1 (no predicates) - should only remove item 1 (unique to query 1)
25532560 // Items 2 and 3 should remain because they're shared with other queries
2554- queryClient . removeQueries ( { queryKey : queryKey ( { } ) , exact : true } )
2561+ queryClient . removeQueries ( {
2562+ queryKey : queryKey ( { where : { category : `A` } } ) ,
2563+ exact : true ,
2564+ } )
25552565
25562566 await vi . waitFor ( ( ) => {
25572567 expect ( collection . size ) . toBe ( 4 ) // Should have items 2, 3, 4, 5
@@ -2608,13 +2618,13 @@ describe(`QueryCollection`, () => {
26082618 const queryFn = vi . fn ( ) . mockImplementation ( ( ) => {
26092619 // All queries return the same data regardless of predicates
26102620 return Promise . resolve ( [
2611- { id : `1` , name : `Item 1` } ,
2612- { id : `2` , name : `Item 2` } ,
2613- { id : `3` , name : `Item 3` } ,
2621+ { id : `1` , name : `Item 1` , category : `A` } ,
2622+ { id : `2` , name : `Item 2` , category : `A` } ,
2623+ { id : `3` , name : `Item 3` , category : `A` } ,
26142624 ] )
26152625 } )
26162626
2617- const config : QueryCollectionConfig < TestItem > = {
2627+ const config : QueryCollectionConfig < CategorisedItem > = {
26182628 id : `identical-test` ,
26192629 queryClient,
26202630 queryKey : ( ctx ) => {
@@ -2644,15 +2654,29 @@ describe(`QueryCollection`, () => {
26442654 } )
26452655
26462656 // Add query 2 with different predicates (but returns same data)
2647- await collection . _sync . loadSubset ( { where : { category : `A` } } as any )
2657+ const whereClause1 = new Func ( `eq` , [
2658+ new PropRef ( [ `category` ] ) ,
2659+ new Value ( `A` ) ,
2660+ ] )
2661+
2662+ await collection . _sync . loadSubset ( {
2663+ where : whereClause1 ,
2664+ } )
26482665
26492666 // Wait for query 2 data to load
26502667 await vi . waitFor ( ( ) => {
26512668 expect ( collection . size ) . toBe ( 3 ) // Same data, no new items
26522669 } )
26532670
26542671 // Add query 3 with different predicates (but returns same data)
2655- await collection . _sync . loadSubset ( { where : { category : `B` } } as any )
2672+ const whereClause2 = new Func ( `or` , [
2673+ new Func ( `eq` , [ new PropRef ( [ `category` ] ) , new Value ( `A` ) ] ) ,
2674+ new Func ( `eq` , [ new PropRef ( [ `category` ] ) , new Value ( `B` ) ] ) ,
2675+ ] )
2676+
2677+ await collection . _sync . loadSubset ( {
2678+ where : whereClause2 ,
2679+ } )
26562680
26572681 // Wait for query 3 data to load
26582682 await vi . waitFor ( ( ) => {
@@ -2676,7 +2700,7 @@ describe(`QueryCollection`, () => {
26762700
26772701 // GC query 2 - should still not remove any items (all items are shared with query 3)
26782702 queryClient . removeQueries ( {
2679- queryKey : ( config . queryKey as any ) ( { where : { category : `A` } } ) ,
2703+ queryKey : ( config . queryKey as any ) ( { where : whereClause1 } ) ,
26802704 exact : true ,
26812705 } )
26822706
@@ -2691,7 +2715,7 @@ describe(`QueryCollection`, () => {
26912715
26922716 // GC query 3 - should remove all items (no more queries reference them)
26932717 queryClient . removeQueries ( {
2694- queryKey : ( config . queryKey as any ) ( { where : { category : `B` } } ) ,
2718+ queryKey : ( config . queryKey as any ) ( { where : whereClause2 } ) ,
26952719 exact : true ,
26962720 } )
26972721
@@ -2712,18 +2736,13 @@ describe(`QueryCollection`, () => {
27122736 const queryFn = vi . fn ( ) . mockImplementation ( ( context ) => {
27132737 const { meta } = context
27142738 const loadSubsetOptions = meta ?. loadSubsetOptions || { }
2715- const { where, orderBy , limit } = loadSubsetOptions
2739+ const { where } = loadSubsetOptions
27162740
2717- // Query 1: empty array (no predicates)
2718- if ( ! where && ! orderBy && ! limit ) {
2719- return Promise . resolve ( [ ] )
2720- }
2721-
2722- // Query 2: some items (where: { category: 'A' })
2723- if ( where ?. category === `A` ) {
2741+ // Query 2: some items (where: { category: 'B' })
2742+ if ( where ?. name === `eq` && where ?. args [ 1 ] . value === `B` ) {
27242743 return Promise . resolve ( [
2725- { id : `1` , name : `Item 1` } ,
2726- { id : `2` , name : `Item 2` } ,
2744+ { id : `1` , name : `Item 1` , category : `B` } ,
2745+ { id : `2` , name : `Item 2` , category : `B` } ,
27272746 ] )
27282747 }
27292748
@@ -2752,15 +2771,23 @@ describe(`QueryCollection`, () => {
27522771 expect ( collection . size ) . toBe ( 0 )
27532772
27542773 // Load query 1 with no predicates (returns empty array)
2755- await collection . _sync . loadSubset ( { } )
2774+ const whereClause1 = new Func ( `eq` , [
2775+ new PropRef ( [ `category` ] ) ,
2776+ new Value ( `A` ) ,
2777+ ] )
2778+ await collection . _sync . loadSubset ( { where : whereClause1 } )
27562779
27572780 // Wait for query 1 data to load (still empty)
27582781 await vi . waitFor ( ( ) => {
27592782 expect ( collection . size ) . toBe ( 0 ) // Empty query
27602783 } )
27612784
27622785 // Add query 2 with different predicates (items 1, 2)
2763- await collection . _sync . loadSubset ( { where : { category : `A` } } as any )
2786+ const whereClause2 = new Func ( `eq` , [
2787+ new PropRef ( [ `category` ] ) ,
2788+ new Value ( `B` ) ,
2789+ ] )
2790+ await collection . _sync . loadSubset ( { where : whereClause2 } as any )
27642791
27652792 // Wait for query 2 data to load
27662793 await vi . waitFor ( ( ) => {
@@ -2786,7 +2813,7 @@ describe(`QueryCollection`, () => {
27862813
27872814 // GC non-empty query 2 - should remove its items
27882815 queryClient . removeQueries ( {
2789- queryKey : ( config . queryKey as any ) ( { where : { category : `A` } } ) ,
2816+ queryKey : ( config . queryKey as any ) ( { where : whereClause2 } ) ,
27902817 exact : true ,
27912818 } )
27922819
@@ -2805,29 +2832,29 @@ describe(`QueryCollection`, () => {
28052832 const queryFn = vi . fn ( ) . mockImplementation ( ( context ) => {
28062833 const { meta } = context
28072834 const loadSubsetOptions = meta ?. loadSubsetOptions || { }
2808- const { where, orderBy , limit } = loadSubsetOptions
2835+ const { where } = loadSubsetOptions
28092836
28102837 // Query 1: items 1, 2 (no predicates)
2811- if ( ! where && ! orderBy && ! limit ) {
2838+ if ( where ?. name === `eq` && where ?. args [ 1 ] . value === `C` ) {
28122839 return Promise . resolve ( [
2813- { id : `1` , name : `Item 1` } ,
2814- { id : `2` , name : `Item 2` } ,
2840+ { id : `1` , name : `Item 1` , type : `C` } ,
2841+ { id : `2` , name : `Item 2` , type : `C` } ,
28152842 ] )
28162843 }
28172844
28182845 // Query 2: items 2, 3 (where: { type: 'A' })
2819- if ( where ?. type === `A` ) {
2846+ if ( where ?. name === `eq` && where ?. args [ 1 ] . value === `A` ) {
28202847 return Promise . resolve ( [
2821- { id : `2` , name : `Item 2` } ,
2822- { id : `3` , name : `Item 3` } ,
2848+ { id : `2` , name : `Item 2` , type : `A` } ,
2849+ { id : `3` , name : `Item 3` , type : `A` } ,
28232850 ] )
28242851 }
28252852
28262853 // Query 3: items 3, 4 (where: { type: 'B' })
2827- if ( where ?. type === `B` ) {
2854+ if ( where ?. name === `eq` && where ?. args [ 1 ] . value === `B` ) {
28282855 return Promise . resolve ( [
2829- { id : `3` , name : `Item 3` } ,
2830- { id : `4` , name : `Item 4` } ,
2856+ { id : `3` , name : `Item 3` , type : `B` } ,
2857+ { id : `4` , name : `Item 4` , type : `B` } ,
28312858 ] )
28322859 }
28332860
@@ -2856,23 +2883,35 @@ describe(`QueryCollection`, () => {
28562883 expect ( collection . size ) . toBe ( 0 )
28572884
28582885 // Load query 1 with no predicates (items 1, 2)
2859- await collection . _sync . loadSubset ( { } )
2886+ const whereClause1 = new Func ( `eq` , [
2887+ new PropRef ( [ `type` ] ) ,
2888+ new Value ( `C` ) ,
2889+ ] )
2890+ await collection . _sync . loadSubset ( { where : whereClause1 } )
28602891
28612892 // Wait for query 1 data to load
28622893 await vi . waitFor ( ( ) => {
28632894 expect ( collection . size ) . toBe ( 2 )
28642895 } )
28652896
28662897 // Add query 2 with different predicates (items 2, 3)
2867- await collection . _sync . loadSubset ( { where : { type : `A` } } as any )
2898+ const whereClause2 = new Func ( `eq` , [
2899+ new PropRef ( [ `type` ] ) ,
2900+ new Value ( `A` ) ,
2901+ ] )
2902+ await collection . _sync . loadSubset ( { where : whereClause2 } )
28682903
28692904 // Wait for query 2 data to load
28702905 await vi . waitFor ( ( ) => {
28712906 expect ( collection . size ) . toBe ( 3 ) // Should have items 1, 2, 3
28722907 } )
28732908
28742909 // Add query 3 with different predicates
2875- await collection . _sync . loadSubset ( { where : { type : `B` } } as any )
2910+ const whereClause3 = new Func ( `eq` , [
2911+ new PropRef ( [ `type` ] ) ,
2912+ new Value ( `B` ) ,
2913+ ] )
2914+ await collection . _sync . loadSubset ( { where : whereClause3 } as any )
28762915
28772916 // Wait for query 3 data to load
28782917 await vi . waitFor ( ( ) => {
@@ -2881,15 +2920,15 @@ describe(`QueryCollection`, () => {
28812920
28822921 // GC all queries concurrently
28832922 queryClient . removeQueries ( {
2884- queryKey : ( config . queryKey as any ) ( { } ) ,
2923+ queryKey : ( config . queryKey as any ) ( { where : whereClause1 } ) ,
28852924 exact : true ,
28862925 } )
28872926 queryClient . removeQueries ( {
2888- queryKey : ( config . queryKey as any ) ( { where : { type : `A` } } ) ,
2927+ queryKey : ( config . queryKey as any ) ( { where : whereClause2 } ) ,
28892928 exact : true ,
28902929 } )
28912930 queryClient . removeQueries ( {
2892- queryKey : ( config . queryKey as any ) ( { where : { type : `B` } } ) ,
2931+ queryKey : ( config . queryKey as any ) ( { where : whereClause3 } ) ,
28932932 exact : true ,
28942933 } )
28952934
0 commit comments