* Recursively collect all table aliases referenced in an expression
(expr: BasicExpression | any)
| 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 |
no test coverage detected