From e006f023aaa628727f4cb7f7ab3d9261ccc92261 Mon Sep 17 00:00:00 2001 From: Liu Husong Date: Tue, 16 Dec 2025 21:52:38 +0800 Subject: [PATCH 1/2] adding a regression test --- dev/test/query.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dev/test/query.ts b/dev/test/query.ts index b3ee1595b..c859e323d 100644 --- a/dev/test/query.ts +++ b/dev/test/query.ts @@ -1915,6 +1915,23 @@ describe('limit() interface', () => { query = query.limit(1).limit(2).limit(3); await query.get(); }); + + // Regression test: This test currently fails because limit(0) is not + // serialized in the query proto (limit(0) is falsy in JavaScript). + // This test is expected to fail until the fix is applied. + it('handles limit(0) correctly', async () => { + const overrides: ApiOverride = { + runQuery: request => { + queryEquals(request, limit(0)); + return emptyQueryStream(); + }, + }; + + firestore = await createInstance(overrides); + let query: Query = firestore.collection('collectionId'); + query = query.limit(0); + await query.get(); + }); }); describe('limitToLast() interface', () => { From be8b9c59127373920af83cb14e7b810f17fdcb65 Mon Sep 17 00:00:00 2001 From: Liu Husong Date: Tue, 16 Dec 2025 21:53:05 +0800 Subject: [PATCH 2/2] fix: ensure limit(0) is properly serialized in query requests Previously, calling `.limit(0)` on a Firestore Query did not correctly serialize the zero value to the underlying wire protocol. This caused queries intended to return zero results to be sent without a limit constraint, potentially returning unintended results. This commit fixes the serialization logic so that `limit(0)` is now explicitly included in the query proto. Also adds/updates related unit tests to validate the correct handling of limit-zero queries. --- dev/src/reference/query-util.ts | 2 +- dev/src/reference/query.ts | 2 +- dev/test/query.ts | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/dev/src/reference/query-util.ts b/dev/src/reference/query-util.ts index c05e84b39..a5aa0c24f 100644 --- a/dev/src/reference/query-util.ts +++ b/dev/src/reference/query-util.ts @@ -344,7 +344,7 @@ export class QueryUtil< // call to `requestStream()` will backoff should the restart // fail before delivering any results. let newQuery: Query; - if (!this._queryOptions.limit) { + if (this._queryOptions.limit === undefined) { newQuery = query; } else { const newLimit = diff --git a/dev/src/reference/query.ts b/dev/src/reference/query.ts index d3c383417..217095ad7 100644 --- a/dev/src/reference/query.ts +++ b/dev/src/reference/query.ts @@ -1439,7 +1439,7 @@ export class Query< structuredQuery.startAt = this.toCursor(this._queryOptions.startAt); structuredQuery.endAt = this.toCursor(this._queryOptions.endAt); - if (this._queryOptions.limit) { + if (this._queryOptions.limit !== undefined) { structuredQuery.limit = {value: this._queryOptions.limit}; } diff --git a/dev/test/query.ts b/dev/test/query.ts index c859e323d..b11913ace 100644 --- a/dev/test/query.ts +++ b/dev/test/query.ts @@ -1916,9 +1916,6 @@ describe('limit() interface', () => { await query.get(); }); - // Regression test: This test currently fails because limit(0) is not - // serialized in the query proto (limit(0) is falsy in JavaScript). - // This test is expected to fail until the fix is applied. it('handles limit(0) correctly', async () => { const overrides: ApiOverride = { runQuery: request => {