From de09b0d7e04e770db67044d625dd159c1b6b4c1d Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Jan 2026 23:47:22 +0000 Subject: [PATCH 1/7] Fix empty string being incorrectly treated as NULL in queries The sql-compiler was filtering out empty strings from query params, treating them the same as null/undefined values. This caused queries like `eq(column, '')` to incorrectly generate `WHERE column = NULL` instead of `WHERE column = ''`. The fix changes the filter condition to check the original value for null/undefined instead of checking if the serialized value is an empty string. This allows legitimate empty string queries to work correctly while still properly omitting null/undefined params. --- .../src/sql-compiler.ts | 7 +++--- .../tests/sql-compiler.test.ts | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/packages/electric-db-collection/src/sql-compiler.ts b/packages/electric-db-collection/src/sql-compiler.ts index d7d021c89..aca0da747 100644 --- a/packages/electric-db-collection/src/sql-compiler.ts +++ b/packages/electric-db-collection/src/sql-compiler.ts @@ -38,9 +38,10 @@ export function compileSQL(options: LoadSubsetOptions): SubsetParams { const paramsRecord = params.reduce( (acc, param, index) => { const serialized = serialize(param) - // Only include non-empty values in params - // Empty strings from null/undefined should be omitted - if (serialized !== ``) { + // Only omit null/undefined values from params + // Note: Actual empty strings should be included - they serialize to '' + // and are valid query values (e.g., WHERE column = '') + if (param !== null && param !== undefined) { acc[`${index + 1}`] = serialized } return acc diff --git a/packages/electric-db-collection/tests/sql-compiler.test.ts b/packages/electric-db-collection/tests/sql-compiler.test.ts index 9989d47f9..7a9ec56ae 100644 --- a/packages/electric-db-collection/tests/sql-compiler.test.ts +++ b/packages/electric-db-collection/tests/sql-compiler.test.ts @@ -68,6 +68,28 @@ describe(`sql-compiler`, () => { expect(result.where).toBe(`"rating" <= $1`) expect(result.params).toEqual({ '1': `5` }) }) + + it(`should compile eq with empty string value`, () => { + // Empty strings are valid query values and should NOT be treated as null + const result = compileSQL({ + where: func(`eq`, [ref(`status`), val(``)]), + }) + expect(result.where).toBe(`"status" = $1`) + // Empty string should be included in params, not filtered out + expect(result.params).toEqual({ '1': `` }) + }) + + it(`should compile eq with empty string in AND clause`, () => { + const result = compileSQL({ + where: func(`and`, [ + func(`eq`, [ref(`projectId`), val(`uuid-123`)]), + func(`eq`, [ref(`status`), val(``)]), + ]), + }) + expect(result.where).toBe(`"projectId" = $1 AND "status" = $2`) + // Both params should be present, including the empty string + expect(result.params).toEqual({ '1': `uuid-123`, '2': `` }) + }) }) describe(`compound where clauses`, () => { From 742d1801ebffaf33129977a91634d2c944d33089 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 00:05:31 +0000 Subject: [PATCH 2/7] ci: apply automated fixes --- packages/vue-db/tests/useLiveQuery.test-d.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/vue-db/tests/useLiveQuery.test-d.ts b/packages/vue-db/tests/useLiveQuery.test-d.ts index 514a2b913..df54ec2be 100644 --- a/packages/vue-db/tests/useLiveQuery.test-d.ts +++ b/packages/vue-db/tests/useLiveQuery.test-d.ts @@ -132,6 +132,8 @@ describe(`useLiveQuery type assertions`, () => { ) // Regular queries should return an array - expectTypeOf(data.value).toEqualTypeOf>() + expectTypeOf(data.value).toEqualTypeOf< + Array<{ id: string; name: string }> + >() }) }) From dbacd535f2d7c66fa306b3f3394cfb22c5ecc266 Mon Sep 17 00:00:00 2001 From: Kyle Mathews Date: Fri, 16 Jan 2026 17:11:46 -0700 Subject: [PATCH 3/7] Simplify null/undefined check to idiomatic pattern Co-Authored-By: Claude Opus 4.5 --- packages/electric-db-collection/src/sql-compiler.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/electric-db-collection/src/sql-compiler.ts b/packages/electric-db-collection/src/sql-compiler.ts index aca0da747..2593d0697 100644 --- a/packages/electric-db-collection/src/sql-compiler.ts +++ b/packages/electric-db-collection/src/sql-compiler.ts @@ -38,10 +38,9 @@ export function compileSQL(options: LoadSubsetOptions): SubsetParams { const paramsRecord = params.reduce( (acc, param, index) => { const serialized = serialize(param) + // Empty strings are valid query values (e.g., WHERE column = '') // Only omit null/undefined values from params - // Note: Actual empty strings should be included - they serialize to '' - // and are valid query values (e.g., WHERE column = '') - if (param !== null && param !== undefined) { + if (param != null) { acc[`${index + 1}`] = serialized } return acc From 9be1b42b64d4eb42f79a683ea21a0489860a199c Mon Sep 17 00:00:00 2001 From: Kyle Mathews Date: Fri, 16 Jan 2026 17:17:05 -0700 Subject: [PATCH 4/7] Add regression tests for issue #1147 Co-Authored-By: Claude Opus 4.5 --- .../tests/sql-compiler.test.ts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/electric-db-collection/tests/sql-compiler.test.ts b/packages/electric-db-collection/tests/sql-compiler.test.ts index 7a9ec56ae..ee6b61f6c 100644 --- a/packages/electric-db-collection/tests/sql-compiler.test.ts +++ b/packages/electric-db-collection/tests/sql-compiler.test.ts @@ -90,6 +90,31 @@ describe(`sql-compiler`, () => { // Both params should be present, including the empty string expect(result.params).toEqual({ '1': `uuid-123`, '2': `` }) }) + + // Regression test for https://github.com/TanStack/db/issues/1147 + it(`should include empty string param for host_id query (issue #1147)`, () => { + // This was the exact reproduction case from the bug report: + // useLiveQuery((q) => q.from({ sessions }).where(({ sessions }) => eq(sessions.host_id, ''))) + const result = compileSQL({ + where: func(`eq`, [ref(`host_id`), val(``)]), + }) + // Before fix: params was {} with $1 placeholder - broken query + // After fix: params correctly includes the empty string + expect(result.where).toBe(`"host_id" = $1`) + expect(result.params).toEqual({ '1': `` }) + }) + + it(`should handle multiple empty strings with correct param indices`, () => { + const result = compileSQL({ + where: func(`and`, [ + func(`eq`, [ref(`field1`), val(``)]), + func(`eq`, [ref(`field2`), val(``)]), + ]), + }) + expect(result.where).toBe(`"field1" = $1 AND "field2" = $2`) + // Both empty strings should be present with correct indices + expect(result.params).toEqual({ '1': ``, '2': `` }) + }) }) describe(`compound where clauses`, () => { From a425e527c7466111e12aa62ba10203df9b43d7bf Mon Sep 17 00:00:00 2001 From: Kyle Mathews Date: Fri, 16 Jan 2026 17:18:26 -0700 Subject: [PATCH 5/7] Add like/ilike empty string tests for defense-in-depth Co-Authored-By: Claude Opus 4.5 --- .../tests/sql-compiler.test.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/electric-db-collection/tests/sql-compiler.test.ts b/packages/electric-db-collection/tests/sql-compiler.test.ts index ee6b61f6c..c23cadddf 100644 --- a/packages/electric-db-collection/tests/sql-compiler.test.ts +++ b/packages/electric-db-collection/tests/sql-compiler.test.ts @@ -115,6 +115,22 @@ describe(`sql-compiler`, () => { // Both empty strings should be present with correct indices expect(result.params).toEqual({ '1': ``, '2': `` }) }) + + it(`should compile like with empty string pattern`, () => { + const result = compileSQL({ + where: func(`like`, [ref(`description`), val(``)]), + }) + expect(result.where).toBe(`"description" LIKE $1`) + expect(result.params).toEqual({ '1': `` }) + }) + + it(`should compile ilike with empty string pattern`, () => { + const result = compileSQL({ + where: func(`ilike`, [ref(`title`), val(``)]), + }) + expect(result.where).toBe(`"title" ILIKE $1`) + expect(result.params).toEqual({ '1': `` }) + }) }) describe(`compound where clauses`, () => { From f51987cc9433f3ca9640238c67bf501c89f64e05 Mon Sep 17 00:00:00 2001 From: Kyle Mathews Date: Fri, 16 Jan 2026 17:19:30 -0700 Subject: [PATCH 6/7] Remove duplicate empty string test Co-Authored-By: Claude Opus 4.5 --- .../tests/sql-compiler.test.ts | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/packages/electric-db-collection/tests/sql-compiler.test.ts b/packages/electric-db-collection/tests/sql-compiler.test.ts index c23cadddf..5dc1cac59 100644 --- a/packages/electric-db-collection/tests/sql-compiler.test.ts +++ b/packages/electric-db-collection/tests/sql-compiler.test.ts @@ -69,13 +69,12 @@ describe(`sql-compiler`, () => { expect(result.params).toEqual({ '1': `5` }) }) + // Regression test for https://github.com/TanStack/db/issues/1147 it(`should compile eq with empty string value`, () => { - // Empty strings are valid query values and should NOT be treated as null const result = compileSQL({ where: func(`eq`, [ref(`status`), val(``)]), }) expect(result.where).toBe(`"status" = $1`) - // Empty string should be included in params, not filtered out expect(result.params).toEqual({ '1': `` }) }) @@ -87,23 +86,9 @@ describe(`sql-compiler`, () => { ]), }) expect(result.where).toBe(`"projectId" = $1 AND "status" = $2`) - // Both params should be present, including the empty string expect(result.params).toEqual({ '1': `uuid-123`, '2': `` }) }) - // Regression test for https://github.com/TanStack/db/issues/1147 - it(`should include empty string param for host_id query (issue #1147)`, () => { - // This was the exact reproduction case from the bug report: - // useLiveQuery((q) => q.from({ sessions }).where(({ sessions }) => eq(sessions.host_id, ''))) - const result = compileSQL({ - where: func(`eq`, [ref(`host_id`), val(``)]), - }) - // Before fix: params was {} with $1 placeholder - broken query - // After fix: params correctly includes the empty string - expect(result.where).toBe(`"host_id" = $1`) - expect(result.params).toEqual({ '1': `` }) - }) - it(`should handle multiple empty strings with correct param indices`, () => { const result = compileSQL({ where: func(`and`, [ From 12fb1522d2e1e7acc05dd56a9d1907d0ed3f98d4 Mon Sep 17 00:00:00 2001 From: Kyle Mathews Date: Fri, 16 Jan 2026 17:20:18 -0700 Subject: [PATCH 7/7] Add changeset for empty string fix Co-Authored-By: Claude Opus 4.5 --- .changeset/fix-empty-string-params.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fix-empty-string-params.md diff --git a/.changeset/fix-empty-string-params.md b/.changeset/fix-empty-string-params.md new file mode 100644 index 000000000..b2a8e65ee --- /dev/null +++ b/.changeset/fix-empty-string-params.md @@ -0,0 +1,5 @@ +--- +'@tanstack/electric-db-collection': patch +--- + +Fix empty string values being incorrectly omitted from SQL query params. Queries like `eq(column, '')` now correctly include the empty string parameter instead of producing a malformed query with a missing `$1` value.