* Step 2: Analyze which table sources a WHERE clause touches. * * This determines whether a clause can be pushed down to a specific table * or must remain in the main query (for multi-source clauses like join conditions). * * Special handling for namespace-only references in outer joins: * WHE
( clause: BasicExpression<boolean>, )
| 599 | * ``` |
| 600 | */ |
| 601 | function analyzeWhereClause( |
| 602 | clause: BasicExpression<boolean>, |
| 603 | ): AnalyzedWhereClause { |
| 604 | // Track which table aliases this WHERE clause touches |
| 605 | const touchedSources = new Set<string>() |
| 606 | // Track whether this clause contains namespace-only references that prevent pushdown |
| 607 | let hasNamespaceOnlyRef = false |
| 608 | |
| 609 | /** |
| 610 | * Recursively collect all table aliases referenced in an expression |
| 611 | */ |
| 612 | function collectSources(expr: BasicExpression | any): void { |
| 613 | switch (expr.type) { |
| 614 | case `ref`: |
| 615 | // PropRef path has the table alias as the first element |
| 616 | if (expr.path && expr.path.length > 0) { |
| 617 | const firstElement = expr.path[0] |
| 618 | if (firstElement) { |
| 619 | touchedSources.add(firstElement) |
| 620 | |
| 621 | // If the path has only one element (just the namespace), |
| 622 | // this is a namespace-only reference that should not be pushed down |
| 623 | // This applies to ANY function, not just existence-checking functions |
| 624 | if (expr.path.length === 1) { |
| 625 | hasNamespaceOnlyRef = true |
| 626 | } |
| 627 | } |
| 628 | } |
| 629 | break |
| 630 | case `func`: |
| 631 | // Recursively analyze function arguments (e.g., eq, gt, and, or) |
| 632 | if (expr.args) { |
| 633 | expr.args.forEach(collectSources) |
| 634 | } |
| 635 | break |
| 636 | case `val`: |
| 637 | // Values don't reference any sources |
| 638 | break |
| 639 | case `agg`: |
| 640 | // Aggregates can reference sources in their arguments |
| 641 | if (expr.args) { |
| 642 | expr.args.forEach(collectSources) |
| 643 | } |
| 644 | break |
| 645 | } |
| 646 | } |
| 647 | |
| 648 | collectSources(clause) |
| 649 | |
| 650 | return { |
| 651 | expression: clause, |
| 652 | touchedSources, |
| 653 | hasNamespaceOnlyRef, |
| 654 | } |
| 655 | } |
| 656 | |
| 657 | /** |
| 658 | * Step 3: Group WHERE clauses by the sources they touch. |
no test coverage detected