* Detects whether a WHERE clause references the subquery alias through fields that * are re-exposed under different names (renamed SELECT projections or fnSelect output). * In those cases we keep the clause at the outer level to avoid alias remapping bugs. * TODO: in future we should handle this
( subquery: QueryIR, whereClause: BasicExpression<boolean>, outerAlias: string, )
| 1152 | * internal field references, but it likely needs a wider refactor to do cleanly. |
| 1153 | */ |
| 1154 | function referencesAliasWithRemappedSelect( |
| 1155 | subquery: QueryIR, |
| 1156 | whereClause: BasicExpression<boolean>, |
| 1157 | outerAlias: string, |
| 1158 | ): boolean { |
| 1159 | const refs = collectRefs(whereClause) |
| 1160 | // Only care about clauses that actually reference the outer alias. |
| 1161 | if (refs.every((ref) => ref.path[0] !== outerAlias)) { |
| 1162 | return false |
| 1163 | } |
| 1164 | |
| 1165 | // fnSelect always rewrites the row shape, so alias-safe pushdown is impossible. |
| 1166 | if (subquery.fnSelect) { |
| 1167 | return true |
| 1168 | } |
| 1169 | |
| 1170 | const select = subquery.select |
| 1171 | // Without an explicit SELECT the clause still refers to the original collection. |
| 1172 | if (!select) { |
| 1173 | return false |
| 1174 | } |
| 1175 | |
| 1176 | for (const ref of refs) { |
| 1177 | const path = ref.path |
| 1178 | // Need at least alias + field to matter. |
| 1179 | if (path.length < 2) continue |
| 1180 | if (path[0] !== outerAlias) continue |
| 1181 | |
| 1182 | const projected = select[path[1]!] |
| 1183 | // Unselected fields can't be remapped, so skip - only care about fields in the SELECT. |
| 1184 | if (!projected) continue |
| 1185 | |
| 1186 | // Non-PropRef projections are computed values; cannot push down. |
| 1187 | if (!(projected instanceof PropRef)) { |
| 1188 | return true |
| 1189 | } |
| 1190 | |
| 1191 | // If the projection is just the alias (whole row) without a specific field, |
| 1192 | // we can't verify whether the field we're referencing is being preserved or remapped. |
| 1193 | if (projected.path.length < 2) { |
| 1194 | return true |
| 1195 | } |
| 1196 | |
| 1197 | const [innerAlias, innerField] = projected.path |
| 1198 | |
| 1199 | // Safe only when the projection points straight back to the same alias or the |
| 1200 | // underlying source alias and preserves the field name. |
| 1201 | const firstFromAlias = getFirstFromAlias(subquery) |
| 1202 | if (innerAlias !== outerAlias && innerAlias !== firstFromAlias) { |
| 1203 | return true |
| 1204 | } |
| 1205 | |
| 1206 | if (innerField !== path[1]) { |
| 1207 | return true |
| 1208 | } |
| 1209 | } |
| 1210 | |
| 1211 | return false |
no test coverage detected