@@ -8,11 +8,12 @@ import {
8
8
import {
9
9
CollectionInputNotFoundError ,
10
10
InvalidJoinCondition ,
11
- InvalidJoinConditionLeftTableError ,
12
- InvalidJoinConditionRightTableError ,
13
- InvalidJoinConditionSameTableError ,
14
- InvalidJoinConditionTableMismatchError ,
11
+ InvalidJoinConditionLeftSourceError ,
12
+ InvalidJoinConditionRightSourceError ,
13
+ InvalidJoinConditionSameSourceError ,
14
+ InvalidJoinConditionSourceMismatchError ,
15
15
JoinCollectionNotFoundError ,
16
+ SubscriptionNotFoundError ,
16
17
UnsupportedJoinSourceTypeError ,
17
18
UnsupportedJoinTypeError ,
18
19
} from "../../errors.js"
@@ -179,7 +180,7 @@ function processJoin(
179
180
// Prepare the main pipeline for joining
180
181
let mainPipeline = pipeline . pipe (
181
182
map ( ( [ currentKey , namespacedRow ] ) => {
182
- // Extract the join key from the main table expression
183
+ // Extract the join key from the main source expression
183
184
const mainKey = compiledMainExpr ( namespacedRow )
184
185
185
186
// Return [joinKey, [originalKey, namespacedRow]]
@@ -196,7 +197,7 @@ function processJoin(
196
197
// Wrap the row in a namespaced structure
197
198
const namespacedRow : NamespacedRow = { [ joinedSource ] : row }
198
199
199
- // Extract the join key from the joined table expression
200
+ // Extract the join key from the joined source expression
200
201
const joinedKey = compiledJoinedExpr ( namespacedRow )
201
202
202
203
// Return [joinKey, [originalKey, namespacedRow]]
@@ -269,8 +270,8 @@ function processJoin(
269
270
> = activePipeline . pipe (
270
271
tap ( ( data ) => {
271
272
// For outer joins (LEFT/RIGHT), the driving side determines which alias's
272
- // subscription we consult for lazy loading. The main table drives LEFT joins,
273
- // joined table drives RIGHT joins.
273
+ // subscription we consult for lazy loading. The main source drives LEFT joins,
274
+ // joined source drives RIGHT joins.
274
275
const lazyAliasCandidate =
275
276
activeSource === `main` ? joinedSource : mainSource
276
277
@@ -284,8 +285,11 @@ function processJoin(
284
285
const lazySourceSubscription = subscriptions [ resolvedAlias ]
285
286
286
287
if ( ! lazySourceSubscription ) {
287
- throw new Error (
288
- `Internal error: subscription for alias '${ resolvedAlias } ' (remapped from '${ lazyAliasCandidate } ', collection '${ lazySource . id } ') is missing in join pipeline. Available aliases: ${ Object . keys ( subscriptions ) . join ( `, ` ) } . This indicates a bug in alias tracking.`
288
+ throw new SubscriptionNotFoundError (
289
+ resolvedAlias ,
290
+ lazyAliasCandidate ,
291
+ lazySource . id ,
292
+ Object . keys ( subscriptions )
289
293
)
290
294
}
291
295
@@ -324,90 +328,89 @@ function processJoin(
324
328
}
325
329
326
330
/**
327
- * Analyzes join expressions to determine which refers to which table
328
- * and returns them in the correct order (available table expression first, joined table expression second)
331
+ * Analyzes join expressions to determine which refers to which source
332
+ * and returns them in the correct order (available source expression first, joined source expression second)
329
333
*/
330
334
function analyzeJoinExpressions (
331
335
left : BasicExpression ,
332
336
right : BasicExpression ,
333
- allAvailableTableAliases : Array < string > ,
337
+ allAvailableSourceAliases : Array < string > ,
334
338
joinedSource : string
335
339
) : { mainExpr : BasicExpression ; joinedExpr : BasicExpression } {
336
- // Filter out the joined table alias from the available table aliases
337
- const availableSources = allAvailableTableAliases . filter (
340
+ // Filter out the joined source alias from the available source aliases
341
+ const availableSources = allAvailableSourceAliases . filter (
338
342
( alias ) => alias !== joinedSource
339
343
)
340
344
341
- const leftTableAlias = getTableAliasFromExpression ( left )
342
- const rightTableAlias = getTableAliasFromExpression ( right )
345
+ const leftSourceAlias = getSourceAliasFromExpression ( left )
346
+ const rightSourceAlias = getSourceAliasFromExpression ( right )
343
347
344
- // If left expression refers to an available table and right refers to joined table , keep as is
348
+ // If left expression refers to an available source and right refers to joined source , keep as is
345
349
if (
346
- leftTableAlias &&
347
- availableSources . includes ( leftTableAlias ) &&
348
- rightTableAlias === joinedSource
350
+ leftSourceAlias &&
351
+ availableSources . includes ( leftSourceAlias ) &&
352
+ rightSourceAlias === joinedSource
349
353
) {
350
354
return { mainExpr : left , joinedExpr : right }
351
355
}
352
356
353
- // If left expression refers to joined table and right refers to an available table , swap them
357
+ // If left expression refers to joined source and right refers to an available source , swap them
354
358
if (
355
- leftTableAlias === joinedSource &&
356
- rightTableAlias &&
357
- availableSources . includes ( rightTableAlias )
359
+ leftSourceAlias === joinedSource &&
360
+ rightSourceAlias &&
361
+ availableSources . includes ( rightSourceAlias )
358
362
) {
359
363
return { mainExpr : right , joinedExpr : left }
360
364
}
361
365
362
- // If one expression doesn't refer to any table, this is an invalid join
363
- if ( ! leftTableAlias || ! rightTableAlias ) {
364
- // For backward compatibility, use the first available table alias in error message
365
- throw new InvalidJoinConditionTableMismatchError ( )
366
+ // If one expression doesn't refer to any source, this is an invalid join
367
+ if ( ! leftSourceAlias || ! rightSourceAlias ) {
368
+ throw new InvalidJoinConditionSourceMismatchError ( )
366
369
}
367
370
368
371
// If both expressions refer to the same alias, this is an invalid join
369
- if ( leftTableAlias === rightTableAlias ) {
370
- throw new InvalidJoinConditionSameTableError ( leftTableAlias )
372
+ if ( leftSourceAlias === rightSourceAlias ) {
373
+ throw new InvalidJoinConditionSameSourceError ( leftSourceAlias )
371
374
}
372
375
373
- // Left side must refer to an available table
376
+ // Left side must refer to an available source
374
377
// This cannot happen with the query builder as there is no way to build a ref
375
- // to an unavailable table , but just in case, but could happen with the IR
376
- if ( ! availableSources . includes ( leftTableAlias ) ) {
377
- throw new InvalidJoinConditionLeftTableError ( leftTableAlias )
378
+ // to an unavailable source , but just in case, but could happen with the IR
379
+ if ( ! availableSources . includes ( leftSourceAlias ) ) {
380
+ throw new InvalidJoinConditionLeftSourceError ( leftSourceAlias )
378
381
}
379
382
380
- // Right side must refer to the joined table
381
- if ( rightTableAlias !== joinedSource ) {
382
- throw new InvalidJoinConditionRightTableError ( joinedSource )
383
+ // Right side must refer to the joined source
384
+ if ( rightSourceAlias !== joinedSource ) {
385
+ throw new InvalidJoinConditionRightSourceError ( joinedSource )
383
386
}
384
387
385
388
// This should not be reachable given the logic above, but just in case
386
389
throw new InvalidJoinCondition ( )
387
390
}
388
391
389
392
/**
390
- * Extracts the table alias from a join expression
393
+ * Extracts the source alias from a join expression
391
394
*/
392
- function getTableAliasFromExpression ( expr : BasicExpression ) : string | null {
395
+ function getSourceAliasFromExpression ( expr : BasicExpression ) : string | null {
393
396
switch ( expr . type ) {
394
397
case `ref` :
395
- // PropRef path has the table alias as the first element
398
+ // PropRef path has the source alias as the first element
396
399
return expr . path [ 0 ] || null
397
400
case `func` : {
398
- // For function expressions, we need to check if all arguments refer to the same table
399
- const tableAliases = new Set < string > ( )
401
+ // For function expressions, we need to check if all arguments refer to the same source
402
+ const sourceAliases = new Set < string > ( )
400
403
for ( const arg of expr . args ) {
401
- const alias = getTableAliasFromExpression ( arg )
404
+ const alias = getSourceAliasFromExpression ( arg )
402
405
if ( alias ) {
403
- tableAliases . add ( alias )
406
+ sourceAliases . add ( alias )
404
407
}
405
408
}
406
- // If all arguments refer to the same table , return that table alias
407
- return tableAliases . size === 1 ? Array . from ( tableAliases ) [ 0 ] ! : null
409
+ // If all arguments refer to the same source , return that source alias
410
+ return sourceAliases . size === 1 ? Array . from ( sourceAliases ) [ 0 ] ! : null
408
411
}
409
412
default :
410
- // Values (type='val') don't reference any table
413
+ // Values (type='val') don't reference any source
411
414
return null
412
415
}
413
416
}
@@ -567,7 +570,7 @@ function processJoinResults(joinType: string) {
567
570
/**
568
571
* Returns the active and lazy collections for a join clause.
569
572
* The active collection is the one that we need to fully iterate over
570
- * and it can be the main table (i.e. left collection) or the joined table (i.e. right collection).
573
+ * and it can be the main source (i.e. left collection) or the joined source (i.e. right collection).
571
574
* The lazy collection is the one that we should join-in lazily based on matches in the active collection.
572
575
* @param joinClause - The join clause to analyze
573
576
* @param leftCollection - The left collection
0 commit comments