Compare commits

...

5 Commits

Author SHA1 Message Date
Jarred Sumner
b8a029f473 Merge branch 'main' into claude/fix-sqlite-prepare-single-binding 2025-12-16 19:53:46 -08:00
Claude Bot
4ca1dc537e refactor: use test.each for single binding test cases
Consolidated the repetitive single-binding tests (string, number, bigint, null)
into a parameterized test using test.each to reduce code duplication.
Kept Uint8Array, array binding, and object binding tests separate as they
have slightly different assertion logic.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 22:41:08 +00:00
Claude Bot
79bf4f280a fix: use safe integer value in bigint binding test
Changed the bigint test to use `9007199254740991n` (MAX_SAFE_INTEGER) instead
of `9007199254740993n` to avoid precision loss in the expected value assertion.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 22:31:40 +00:00
Alistair Smith
f73a2b422b Merge branch 'main' into claude/fix-sqlite-prepare-single-binding 2025-12-11 14:23:59 -08:00
Claude Bot
4cb5813799 fix(sqlite): handle single binding value in Database.prepare()
Database.prepare() was ignoring single primitive binding values (string,
number, bigint, null, Uint8Array) because it passed them directly to the
C++ layer which expects an array or object. The run() method already
handled this correctly by wrapping single values in an array.

This fix normalizes single primitive values to arrays before passing to
the native layer, matching the behavior documented in the TypeScript
types.

Fixes #25472

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 17:36:56 +00:00
2 changed files with 70 additions and 1 deletions

View File

@@ -527,7 +527,11 @@ class Database implements SqliteTypes.Database {
return createChangesObject();
}
prepare(query: string, params: any[] | undefined, flags: number = 0) {
prepare(query: string, params: any, flags: number = 0) {
// Normalize single primitive values to arrays, similar to run()
if (params !== undefined && !isArray(params) && (!params || typeof params !== "object" || isTypedArray(params))) {
params = [params];
}
return new Statement(SQL.prepare(this.#handle, query, params, flags || 0, this.#internalFlags));
}

View File

@@ -0,0 +1,65 @@
import { Database } from "bun:sqlite";
import { expect, test } from "bun:test";
// https://github.com/oven-sh/bun/issues/25472
// Database.prepare ignores single binding argument, only array bindings work
const singleBindingCases: [string, string, string, unknown, unknown][] = [
["string", "name TEXT", "name", "test1", { name: "test1" }],
["number", "value INTEGER", "value", 42, { value: 42 }],
["bigint", "value INTEGER", "value", 9007199254740991n, { value: 9007199254740991 }],
["null", "name TEXT", "name", null, { name: null }],
];
test.each(singleBindingCases)("prepare() with single %s binding", (_, columnDef, columnName, bindValue, expected) => {
const db = new Database(":memory:");
db.run(`CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, ${columnDef})`);
const stmt = db.prepare(`INSERT INTO test (${columnName}) VALUES (?)`, bindValue);
stmt.run();
const result = db.query("SELECT * FROM test WHERE id = 1").get();
expect(result).toMatchObject(expected as object);
});
test("prepare() with single Uint8Array binding", () => {
const db = new Database(":memory:");
db.run("CREATE TABLE test (id INTEGER PRIMARY KEY, data BLOB)");
const data = new Uint8Array([1, 2, 3, 4]);
const stmt = db.prepare("INSERT INTO test (id, data) VALUES (1, ?)", data);
stmt.run();
const result = db.query("SELECT data FROM test WHERE id = 1").get() as { data: Uint8Array };
expect(result.data).toEqual(data);
});
test("prepare() with array binding still works", () => {
const db = new Database(":memory:");
db.run("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)");
const stmt = db.prepare("INSERT INTO test (name) VALUES (?)", ["test2"]);
stmt.run();
const result = db.query("SELECT name FROM test WHERE id = 1").get();
expect(result).toEqual({ name: "test2" });
});
test("prepare() with object binding still works", () => {
const db = new Database(":memory:");
db.run("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)");
const stmt = db.prepare("INSERT INTO test (name) VALUES ($name)", { $name: "test3" });
stmt.run();
const result = db.query("SELECT name FROM test WHERE id = 1").get();
expect(result).toEqual({ name: "test3" });
});
test("prepare() toString() shows bound value for single binding", () => {
const db = new Database(":memory:");
db.run("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)");
const stmt = db.prepare("INSERT INTO test (name) VALUES (?)", "test1");
expect(stmt.toString()).toContain("'test1'");
});