1
1
import { MultiSet } from "@tanstack/db-ivm"
2
2
import { convertToBasicExpression } from "../compiler/expressions.js"
3
+ import { Func } from "../ir.js"
3
4
import type { FullSyncState } from "./types.js"
4
5
import type { MultiSetArray , RootStreamBuilder } from "@tanstack/db-ivm"
5
6
import type { Collection } from "../../collection/index.js"
@@ -25,34 +26,14 @@ export class CollectionSubscriber<
25
26
) { }
26
27
27
28
subscribe ( ) : CollectionSubscription {
28
- const collectionAlias = findCollectionAlias (
29
- this . collectionId ,
30
- this . collectionConfigBuilder . query
31
- )
32
- const whereClause = this . getWhereClauseFromAlias ( collectionAlias )
33
-
34
- if ( whereClause ) {
35
- // Convert WHERE clause to BasicExpression format for collection subscription
36
- const whereExpression = convertToBasicExpression (
37
- whereClause ,
38
- collectionAlias !
39
- )
29
+ const whereExpression = this . buildCollectionFilter ( )
40
30
41
- if ( whereExpression ) {
42
- // Use index optimization for this collection
43
- return this . subscribeToChanges ( whereExpression )
44
- } else {
45
- // This should not happen - if we have a whereClause but can't create whereExpression,
46
- // it indicates a bug in our optimization logic
47
- throw new Error (
48
- `Failed to convert WHERE clause to collection filter for collection '${ this . collectionId } '. ` +
49
- `This indicates a bug in the query optimization logic.`
50
- )
51
- }
52
- } else {
53
- // No WHERE clause for this collection, use regular subscription
54
- return this . subscribeToChanges ( )
31
+ if ( whereExpression ) {
32
+ return this . subscribeToChanges ( whereExpression )
55
33
}
34
+
35
+ // No applicable filter for this collection, use regular subscription
36
+ return this . subscribeToChanges ( )
56
37
}
57
38
58
39
private subscribeToChanges ( whereExpression ?: BasicExpression < boolean > ) {
@@ -240,15 +221,38 @@ export class CollectionSubscriber<
240
221
} )
241
222
}
242
223
243
- private getWhereClauseFromAlias (
244
- collectionAlias : string | undefined
245
- ) : BasicExpression < boolean > | undefined {
224
+ private buildCollectionFilter ( ) : BasicExpression < boolean > | undefined {
246
225
const collectionWhereClausesCache =
247
226
this . collectionConfigBuilder . collectionWhereClausesCache
248
- if ( collectionAlias && collectionWhereClausesCache ) {
249
- return collectionWhereClausesCache . get ( collectionAlias )
227
+ if ( ! collectionWhereClausesCache ) {
228
+ return undefined
250
229
}
251
- return undefined
230
+
231
+ const aliases = this . collectionConfigBuilder . getCollectionAliases (
232
+ this . collectionId
233
+ )
234
+ if ( aliases . length === 0 ) {
235
+ return undefined
236
+ }
237
+
238
+ const convertedClauses : Array < BasicExpression < boolean > > = [ ]
239
+ for ( const alias of aliases ) {
240
+ const clause = collectionWhereClausesCache . get ( alias )
241
+ if ( ! clause ) {
242
+ // At least one alias requires the full collection, so we cannot safely filter
243
+ return undefined
244
+ }
245
+
246
+ const converted = convertToBasicExpression ( clause , alias )
247
+ if ( ! converted ) {
248
+ // Conversion failed which means we cannot use this filter at the subscription level
249
+ return undefined
250
+ }
251
+
252
+ convertedClauses . push ( converted )
253
+ }
254
+
255
+ return combineWithOr ( convertedClauses )
252
256
}
253
257
254
258
private * trackSentValues (
@@ -267,36 +271,6 @@ export class CollectionSubscriber<
267
271
}
268
272
}
269
273
270
- /**
271
- * Finds the alias for a collection ID in the query
272
- */
273
- function findCollectionAlias (
274
- collectionId : string ,
275
- query : any
276
- ) : string | undefined {
277
- // Check FROM clause
278
- if (
279
- query . from ?. type === `collectionRef` &&
280
- query . from . collection ?. id === collectionId
281
- ) {
282
- return query . from . alias
283
- }
284
-
285
- // Check JOIN clauses
286
- if ( query . join ) {
287
- for ( const joinClause of query . join ) {
288
- if (
289
- joinClause . from ?. type === `collectionRef` &&
290
- joinClause . from . collection ?. id === collectionId
291
- ) {
292
- return joinClause . from . alias
293
- }
294
- }
295
- }
296
-
297
- return undefined
298
- }
299
-
300
274
/**
301
275
* Helper function to send changes to a D2 input stream
302
276
*/
@@ -326,6 +300,20 @@ function sendChangesToInput(
326
300
return multiSetArray . length
327
301
}
328
302
303
+ function combineWithOr (
304
+ expressions : Array < BasicExpression < boolean > >
305
+ ) : BasicExpression < boolean > | undefined {
306
+ if ( expressions . length === 0 ) {
307
+ return undefined
308
+ }
309
+
310
+ if ( expressions . length === 1 ) {
311
+ return expressions [ 0 ] !
312
+ }
313
+
314
+ return new Func ( `or` , expressions )
315
+ }
316
+
329
317
/** Splits updates into a delete of the old value and an insert of the new value */
330
318
function * splitUpdates <
331
319
T extends object = Record < string , unknown > ,
0 commit comments