From 74808f490f7e332db79bc466c3cfc8eb03466f71 Mon Sep 17 00:00:00 2001 From: Kevin De Porre Date: Tue, 3 Mar 2026 10:45:55 +0100 Subject: [PATCH 1/3] fix(db): throw error when fn.select() is used with groupBy() fn.select() with groupBy() silently produced wrong results ({ __key_0: ... }) because the compiler cannot statically analyze an opaque function to discover aggregate expressions needed by groupBy. This adds a clear error message directing users to use the standard .select() API instead. Closes #1189 Co-Authored-By: Claude Opus 4.6 --- packages/db/src/errors.ts | 11 ++++++++++ packages/db/src/query/compiler/index.ts | 5 +++++ packages/db/tests/query/group-by.test.ts | 27 ++++++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/packages/db/src/errors.ts b/packages/db/src/errors.ts index dc1c7b900..f62278c56 100644 --- a/packages/db/src/errors.ts +++ b/packages/db/src/errors.ts @@ -433,6 +433,17 @@ export class DistinctRequiresSelectError extends QueryCompilationError { } } +export class FnSelectWithGroupByError extends QueryCompilationError { + constructor() { + super( + `fn.select() cannot be used with groupBy(). ` + + `groupBy requires the compiler to statically analyze aggregate functions (count, sum, max, etc.) in the SELECT clause, ` + + `which is not possible with fn.select() since it is an opaque function. ` + + `Use .select() instead of .fn.select() when combining with groupBy().`, + ) + } +} + export class HavingRequiresGroupByError extends QueryCompilationError { constructor() { super(`HAVING clause requires GROUP BY clause`) diff --git a/packages/db/src/query/compiler/index.ts b/packages/db/src/query/compiler/index.ts index d0d7469e2..885a7eaa6 100644 --- a/packages/db/src/query/compiler/index.ts +++ b/packages/db/src/query/compiler/index.ts @@ -4,6 +4,7 @@ import { CollectionInputNotFoundError, DistinctRequiresSelectError, DuplicateAliasInSubqueryError, + FnSelectWithGroupByError, HavingRequiresGroupByError, LimitOffsetRequireOrderByError, UnsupportedFromTypeError, @@ -218,6 +219,10 @@ export function compileQuery( throw new DistinctRequiresSelectError() } + if (query.fnSelect && query.groupBy && query.groupBy.length > 0) { + throw new FnSelectWithGroupByError() + } + // Process the SELECT clause early - always create $selected // This eliminates duplication and allows for DISTINCT implementation if (query.fnSelect) { diff --git a/packages/db/tests/query/group-by.test.ts b/packages/db/tests/query/group-by.test.ts index 0875ec141..f5f6b33eb 100644 --- a/packages/db/tests/query/group-by.test.ts +++ b/packages/db/tests/query/group-by.test.ts @@ -2167,6 +2167,33 @@ function createGroupByTests(autoIndex: `off` | `eager`): void { expect(result?.totalAmount).toBe(700) }) }) + + describe(`fn.select with groupBy throws error`, () => { + let ordersCollection: ReturnType + + beforeEach(() => { + ordersCollection = createOrdersCollection(autoIndex) + }) + + test(`fn.select with groupBy should throw FnSelectWithGroupByError`, () => { + expect(() => + createLiveQueryCollection({ + startSync: true, + query: (q) => + q + .from({ orders: ordersCollection }) + .groupBy(({ orders }) => orders.customer_id) + .fn.select((row) => ({ + customerId: row.orders.customer_id, + totalAmount: sum(row.orders.amount), + orderCount: count(row.orders.id), + })), + }), + ).toThrow( + `fn.select() cannot be used with groupBy()`, + ) + }) + }) }) } From 37f7936bed7c435b633a7b70bcbe3b95855c1259 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2026 09:47:15 +0000 Subject: [PATCH 2/3] ci: apply automated fixes --- packages/db/tests/query/group-by.test.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/db/tests/query/group-by.test.ts b/packages/db/tests/query/group-by.test.ts index f5f6b33eb..3187736a0 100644 --- a/packages/db/tests/query/group-by.test.ts +++ b/packages/db/tests/query/group-by.test.ts @@ -2189,9 +2189,7 @@ function createGroupByTests(autoIndex: `off` | `eager`): void { orderCount: count(row.orders.id), })), }), - ).toThrow( - `fn.select() cannot be used with groupBy()`, - ) + ).toThrow(`fn.select() cannot be used with groupBy()`) }) }) }) From e60aa76beaf43726746eaf35985cbcf622f2a75d Mon Sep 17 00:00:00 2001 From: Kevin De Porre Date: Tue, 3 Mar 2026 10:51:14 +0100 Subject: [PATCH 3/3] chore: add changeset for fn.select + groupBy error Co-Authored-By: Claude Opus 4.6 --- .changeset/fn-select-groupby-error.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fn-select-groupby-error.md diff --git a/.changeset/fn-select-groupby-error.md b/.changeset/fn-select-groupby-error.md new file mode 100644 index 000000000..cfc87883d --- /dev/null +++ b/.changeset/fn-select-groupby-error.md @@ -0,0 +1,5 @@ +--- +'@tanstack/db': patch +--- + +fix(db): throw error when fn.select() is used with groupBy()