Skip to content

Commit 8d6442e

Browse files
KyleAMathewsclaudeautofix-ci[bot]
authored
Fix sql-compiler to handle empty strings like eq(column, '') (#1146)
* 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. * ci: apply automated fixes * Simplify null/undefined check to idiomatic pattern Co-Authored-By: Claude Opus 4.5 <[email protected]> * Add regression tests for issue #1147 Co-Authored-By: Claude Opus 4.5 <[email protected]> * Add like/ilike empty string tests for defense-in-depth Co-Authored-By: Claude Opus 4.5 <[email protected]> * Remove duplicate empty string test Co-Authored-By: Claude Opus 4.5 <[email protected]> * Add changeset for empty string fix Co-Authored-By: Claude Opus 4.5 <[email protected]> --------- Co-authored-by: Claude <[email protected]> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent f32246a commit 8d6442e

File tree

4 files changed

+59
-4
lines changed

4 files changed

+59
-4
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/electric-db-collection': patch
3+
---
4+
5+
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.

packages/electric-db-collection/src/sql-compiler.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ export function compileSQL<T>(options: LoadSubsetOptions): SubsetParams {
3838
const paramsRecord = params.reduce(
3939
(acc, param, index) => {
4040
const serialized = serialize(param)
41-
// Only include non-empty values in params
42-
// Empty strings from null/undefined should be omitted
43-
if (serialized !== ``) {
41+
// Empty strings are valid query values (e.g., WHERE column = '')
42+
// Only omit null/undefined values from params
43+
if (param != null) {
4444
acc[`${index + 1}`] = serialized
4545
}
4646
return acc

packages/electric-db-collection/tests/sql-compiler.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,54 @@ describe(`sql-compiler`, () => {
6868
expect(result.where).toBe(`"rating" <= $1`)
6969
expect(result.params).toEqual({ '1': `5` })
7070
})
71+
72+
// Regression test for https://github.com/TanStack/db/issues/1147
73+
it(`should compile eq with empty string value`, () => {
74+
const result = compileSQL({
75+
where: func(`eq`, [ref(`status`), val(``)]),
76+
})
77+
expect(result.where).toBe(`"status" = $1`)
78+
expect(result.params).toEqual({ '1': `` })
79+
})
80+
81+
it(`should compile eq with empty string in AND clause`, () => {
82+
const result = compileSQL({
83+
where: func(`and`, [
84+
func(`eq`, [ref(`projectId`), val(`uuid-123`)]),
85+
func(`eq`, [ref(`status`), val(``)]),
86+
]),
87+
})
88+
expect(result.where).toBe(`"projectId" = $1 AND "status" = $2`)
89+
expect(result.params).toEqual({ '1': `uuid-123`, '2': `` })
90+
})
91+
92+
it(`should handle multiple empty strings with correct param indices`, () => {
93+
const result = compileSQL({
94+
where: func(`and`, [
95+
func(`eq`, [ref(`field1`), val(``)]),
96+
func(`eq`, [ref(`field2`), val(``)]),
97+
]),
98+
})
99+
expect(result.where).toBe(`"field1" = $1 AND "field2" = $2`)
100+
// Both empty strings should be present with correct indices
101+
expect(result.params).toEqual({ '1': ``, '2': `` })
102+
})
103+
104+
it(`should compile like with empty string pattern`, () => {
105+
const result = compileSQL({
106+
where: func(`like`, [ref(`description`), val(``)]),
107+
})
108+
expect(result.where).toBe(`"description" LIKE $1`)
109+
expect(result.params).toEqual({ '1': `` })
110+
})
111+
112+
it(`should compile ilike with empty string pattern`, () => {
113+
const result = compileSQL({
114+
where: func(`ilike`, [ref(`title`), val(``)]),
115+
})
116+
expect(result.where).toBe(`"title" ILIKE $1`)
117+
expect(result.params).toEqual({ '1': `` })
118+
})
71119
})
72120

73121
describe(`compound where clauses`, () => {

packages/vue-db/tests/useLiveQuery.test-d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ describe(`useLiveQuery type assertions`, () => {
132132
)
133133

134134
// Regular queries should return an array
135-
expectTypeOf(data.value).toEqualTypeOf<Array<{ id: string; name: string }>>()
135+
expectTypeOf(data.value).toEqualTypeOf<
136+
Array<{ id: string; name: string }>
137+
>()
136138
})
137139
})

0 commit comments

Comments
 (0)