@@ -32,8 +32,9 @@ export class CollectionConfigBuilder<
32
32
private readonly id : string
33
33
readonly query : QueryIR
34
34
private readonly collections : Record < string , Collection < any , any , any > >
35
- private readonly aliasToCollectionId : Record < string , string >
36
35
private readonly collectionByAlias : Record < string , Collection < any , any , any > >
36
+ // Populated during compilation to include optimizer-generated aliases
37
+ private compiledAliasToCollectionId : Record < string , string > = { }
37
38
38
39
// WeakMap to store the keys of the results
39
40
// so that we can retrieve them in the getKey function
@@ -72,13 +73,11 @@ export class CollectionConfigBuilder<
72
73
this . collections = extractCollectionsFromQuery ( this . query )
73
74
const collectionAliasesById = extractCollectionAliases ( this . query )
74
75
75
- this . aliasToCollectionId = { }
76
76
this . collectionByAlias = { }
77
77
for ( const [ collectionId , aliases ] of collectionAliasesById . entries ( ) ) {
78
78
const collection = this . collections [ collectionId ]
79
79
if ( ! collection ) continue
80
80
for ( const alias of aliases ) {
81
- this . aliasToCollectionId [ alias ] = collectionId
82
81
this . collectionByAlias [ alias ] = collection
83
82
}
84
83
}
@@ -111,11 +110,15 @@ export class CollectionConfigBuilder<
111
110
}
112
111
113
112
getCollectionIdForAlias ( alias : string ) : string {
114
- const collectionId = this . aliasToCollectionId [ alias ]
115
- if ( ! collectionId ) {
116
- throw new Error ( `Unknown collection alias " ${ alias } "` )
113
+ const compiled = this . compiledAliasToCollectionId [ alias ]
114
+ if ( compiled ) {
115
+ return compiled
117
116
}
118
- return collectionId
117
+ const collection = this . collectionByAlias [ alias ]
118
+ if ( collection ) {
119
+ return collection . id
120
+ }
121
+ throw new Error ( `Unknown collection alias "${ alias } "` )
119
122
}
120
123
121
124
// The callback function is called after the graph has run.
@@ -224,11 +227,8 @@ export class CollectionConfigBuilder<
224
227
] )
225
228
)
226
229
227
- // Compile the query and get both pipeline and collection WHERE clauses
228
- const {
229
- pipeline : pipelineCache ,
230
- collectionWhereClauses : collectionWhereClausesCache ,
231
- } = compileQuery (
230
+ // Compile the query and capture alias metadata produced during optimisation
231
+ let compilation = compileQuery (
232
232
this . query ,
233
233
this . inputsCache as Record < string , KeyedStream > ,
234
234
this . collections ,
@@ -238,8 +238,37 @@ export class CollectionConfigBuilder<
238
238
this . optimizableOrderByCollections
239
239
)
240
240
241
- this . pipelineCache = pipelineCache
242
- this . collectionWhereClausesCache = collectionWhereClausesCache
241
+ this . pipelineCache = compilation . pipeline
242
+ this . collectionWhereClausesCache = compilation . collectionWhereClauses
243
+ this . compiledAliasToCollectionId = compilation . aliasToCollectionId
244
+ // Optimized queries can introduce aliases beyond those declared on the
245
+ // builder. If that happens, provision inputs for the missing aliases and
246
+ // recompile so the pipeline is fully wired before execution.
247
+ const missingAliases = Object . keys ( this . compiledAliasToCollectionId ) . filter (
248
+ ( alias ) => ! Object . hasOwn ( this . inputsCache ! , alias )
249
+ )
250
+
251
+ if ( missingAliases . length > 0 ) {
252
+ for ( const alias of missingAliases ) {
253
+ this . inputsCache [ alias ] = this . graphCache . newInput < any > ( )
254
+ }
255
+
256
+ compilation = compileQuery (
257
+ this . query ,
258
+ this . inputsCache as Record < string , KeyedStream > ,
259
+ this . collections ,
260
+ this . subscriptions ,
261
+ this . lazyCollectionsCallbacks ,
262
+ this . lazyCollections ,
263
+ this . optimizableOrderByCollections ,
264
+ new WeakMap ( ) ,
265
+ new WeakMap ( )
266
+ )
267
+
268
+ this . pipelineCache = compilation . pipeline
269
+ this . collectionWhereClausesCache = compilation . collectionWhereClauses
270
+ this . compiledAliasToCollectionId = compilation . aliasToCollectionId
271
+ }
243
272
}
244
273
245
274
private maybeCompileBasePipeline ( ) {
@@ -355,31 +384,41 @@ export class CollectionConfigBuilder<
355
384
config : Parameters < SyncConfig < TResult > [ `sync`] > [ 0 ] ,
356
385
syncState : FullSyncState
357
386
) {
358
- const loaders = Object . entries ( this . collectionByAlias ) . map (
359
- ( [ alias , collection ] ) => {
360
- const collectionId = this . aliasToCollectionId [ alias ] !
361
- const collectionSubscriber = new CollectionSubscriber (
362
- alias ,
363
- collectionId ,
364
- collection ,
365
- config ,
366
- syncState ,
367
- this
368
- )
369
-
370
- const subscription = collectionSubscriber . subscribe ( )
371
- this . subscriptions [ alias ] = subscription
372
- const collectionKey = `__collection:${ collectionId } `
373
- this . subscriptions [ collectionKey ] = subscription
374
-
375
- const loadMore = collectionSubscriber . loadMoreIfNeeded . bind (
376
- collectionSubscriber ,
377
- subscription
378
- )
379
-
380
- return loadMore
381
- }
382
- )
387
+ const compiledAliases = Object . entries ( this . compiledAliasToCollectionId )
388
+ if ( compiledAliases . length === 0 ) {
389
+ throw new Error (
390
+ `Compiler returned no alias metadata for query '${ this . id } '. This should not happen; please report.`
391
+ )
392
+ }
393
+
394
+ // Subscribe to each alias the compiler reported.
395
+ const aliasEntries = compiledAliases
396
+
397
+ const loaders = aliasEntries . map ( ( [ alias , collectionId ] ) => {
398
+ const collection =
399
+ this . collectionByAlias [ alias ] ?? this . collections [ collectionId ] !
400
+
401
+ const collectionSubscriber = new CollectionSubscriber (
402
+ alias ,
403
+ collectionId ,
404
+ collection ,
405
+ config ,
406
+ syncState ,
407
+ this
408
+ )
409
+
410
+ const subscription = collectionSubscriber . subscribe ( )
411
+ this . subscriptions [ alias ] = subscription
412
+ const collectionKey = `__collection:${ collectionId } `
413
+ this . subscriptions [ collectionKey ] = subscription
414
+
415
+ const loadMore = collectionSubscriber . loadMoreIfNeeded . bind (
416
+ collectionSubscriber ,
417
+ subscription
418
+ )
419
+
420
+ return loadMore
421
+ } )
383
422
384
423
const loadMoreDataCallback = ( ) => {
385
424
loaders . map ( ( loader ) => loader ( ) )
0 commit comments