Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-empty-string-params.md
Original file line number Diff line number Diff line change
@@ -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.
6 changes: 3 additions & 3 deletions packages/electric-db-collection/src/sql-compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ export function compileSQL<T>(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 !== ``) {
// Empty strings are valid query values (e.g., WHERE column = '')
// Only omit null/undefined values from params
if (param != null) {
acc[`${index + 1}`] = serialized
}
return acc
Expand Down
48 changes: 48 additions & 0 deletions packages/electric-db-collection/tests/sql-compiler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,54 @@ describe(`sql-compiler`, () => {
expect(result.where).toBe(`"rating" <= $1`)
expect(result.params).toEqual({ '1': `5` })
})

// Regression test for https://github.com/TanStack/db/issues/1147
it(`should compile eq with empty string value`, () => {
const result = compileSQL({
where: func(`eq`, [ref(`status`), val(``)]),
})
expect(result.where).toBe(`"status" = $1`)
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`)
expect(result.params).toEqual({ '1': `uuid-123`, '2': `` })
})

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': `` })
})

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`, () => {
Expand Down
4 changes: 3 additions & 1 deletion packages/vue-db/tests/useLiveQuery.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ describe(`useLiveQuery type assertions`, () => {
)

// Regular queries should return an array
expectTypeOf(data.value).toEqualTypeOf<Array<{ id: string; name: string }>>()
expectTypeOf(data.value).toEqualTypeOf<
Array<{ id: string; name: string }>
>()
})
})
Loading