Skip to content

Commit 3b4722c

Browse files
committed
fix(tsql): inject time fallbacks into FROM subqueries
The fallback WHERE injection only targeted the top-level SELECT, so a query shaped as an outer aggregation over a FROM subquery failed to compile: the time column only exists inside the subquery. Descend into the subquery so the fallback lands next to the table reference.
1 parent fbaa4be commit 3b4722c

2 files changed

Lines changed: 38 additions & 0 deletions

File tree

internal-packages/tsql/src/index.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,26 @@ describe("injectFallbackConditions", () => {
231231
expect(modified.where.expression_type).toBe("and");
232232
}
233233
});
234+
235+
it("should inject into a FROM subquery, where the fallback column's table lives", () => {
236+
const ast = parseTSQLSelect(
237+
"SELECT t, sum(total) AS total FROM (SELECT time AS t, status, count(*) AS total FROM task_runs GROUP BY t, status) GROUP BY t"
238+
);
239+
const fallbacks: Record<string, WhereClauseCondition> = {
240+
time: { op: "gte", value: "2024-01-01" },
241+
};
242+
243+
const modified = injectFallbackConditions(ast, fallbacks);
244+
expect(modified.expression_type).toBe("select_query");
245+
if (modified.expression_type === "select_query") {
246+
expect(modified.where).toBeUndefined();
247+
const inner = modified.select_from?.table;
248+
expect(inner?.expression_type).toBe("select_query");
249+
if (inner?.expression_type === "select_query") {
250+
expect(isColumnReferencedInExpression(inner.where, "time")).toBe(true);
251+
}
252+
}
253+
});
234254
});
235255

236256
describe("compileTSQL with whereClauseFallback", () => {

internal-packages/tsql/src/index.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,24 @@ export function injectFallbackConditions(
429429

430430
// Handle SelectQuery
431431
const selectQuery = ast as SelectQuery;
432+
433+
// When the FROM is a subquery, the fallback columns belong to the inner query's
434+
// table, not this level; descend so e.g. a time fallback lands next to the table ref.
435+
const fromTable = selectQuery.select_from?.table;
436+
if (
437+
fromTable &&
438+
(fromTable.expression_type === "select_query" ||
439+
fromTable.expression_type === "select_set_query")
440+
) {
441+
return {
442+
...selectQuery,
443+
select_from: {
444+
...selectQuery.select_from!,
445+
table: injectFallbackConditions(fromTable, fallbacks) as SelectQuery | SelectSetQuery,
446+
},
447+
};
448+
}
449+
432450
const existingWhere = selectQuery.where;
433451

434452
// Collect fallback expressions for columns not already in WHERE

0 commit comments

Comments
 (0)