mirror of
https://github.com/lancedb/lancedb.git
synced 2026-10-12 14:52:26 +00:00
## What's wrong
`toSQL` renders numbers with `toString()`, so `NaN` becomes `NaN` and
`Infinity` becomes `Infinity`. SQL reads those as column names:
```ts
await table.update({ values: { price: NaN }, where: "id = 1" });
// Error: Invalid input, Schema error: No field named "NaN". Valid fields are id, price.
```
`Infinity` and `-Infinity` fail the same way. The only workaround today
is `valuesSql`.
## Fix
Emit `CAST('NaN' AS DOUBLE)`, `CAST('Infinity' AS DOUBLE)` and
`CAST('-Infinity' AS DOUBLE)` for these values. Finite numbers render as
before.
## Tests
- `__test__/util.test.ts` adds `toSQL` cases for `NaN`, `Infinity` and
`-Infinity`.
- `__test__/table.test.ts` adds "should let me update float values to
NaN and Infinity", which updates a float column and reads the values
back.
- On `main`, the new cases fail with `No field named "NaN"`.
- With the fix, all of `util.test.ts` and `table.test.ts` pass (344
tests). These were run against the published
`@lancedb/lancedb@0.40.0-beta.11` native binary.
- `biome check` is clean on the changed files.
The Python SDK has the same issue in `value_to_sql`. That fix is in
#4326.
The fix was found and written by an AI agent (Breken) and checked
against the tests above.
Co-authored-by: breken-ai <312387581+breken-ai@users.noreply.github.com>
35 lines
1.1 KiB
TypeScript
35 lines
1.1 KiB
TypeScript
// SPDX-License-Identifier: Apache-2.0
|
|
// SPDX-FileCopyrightText: Copyright The LanceDB Authors
|
|
|
|
import { IntoSql, toSQL } from "../lancedb/util";
|
|
test.each([
|
|
["string", "'string'"],
|
|
[123, "123"],
|
|
[1.11, "1.11"],
|
|
[true, "TRUE"],
|
|
[false, "FALSE"],
|
|
[null, "NULL"],
|
|
[new Date("2021-01-01T00:00:00.000Z"), "'2021-01-01T00:00:00.000Z'"],
|
|
[[1, 2, 3], "[1, 2, 3]"],
|
|
[new ArrayBuffer(8), "X'0000000000000000'"],
|
|
[Buffer.from("hello"), "X'68656c6c6f'"],
|
|
["Hello 'world'", "'Hello ''world'''"],
|
|
[NaN, "CAST('NaN' AS DOUBLE)"],
|
|
[Infinity, "CAST('Infinity' AS DOUBLE)"],
|
|
[-Infinity, "CAST('-Infinity' AS DOUBLE)"],
|
|
])("toSQL(%p) === %p", (value, expected) => {
|
|
expect(toSQL(value)).toBe(expected);
|
|
});
|
|
|
|
test("toSQL({}) throws on unsupported value type", () => {
|
|
expect(() => toSQL({} as unknown as IntoSql)).toThrow(
|
|
"Unsupported value type: object value: ([object Object])",
|
|
);
|
|
});
|
|
test("toSQL() throws on unsupported value type", () => {
|
|
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
expect(() => (<any>toSQL)()).toThrow(
|
|
"Unsupported value type: undefined value: (undefined)",
|
|
);
|
|
});
|