From 376adbb10a4c31e9d11c9cfd29401fb57a7de0ed Mon Sep 17 00:00:00 2001 From: Diego Reis Date: Thu, 22 May 2025 15:20:26 -0300 Subject: [PATCH] bind/js: Add support to variadic functions --- bindings/javascript/__test__/limbo.spec.mjs | 20 ++++++--- bindings/javascript/src/lib.rs | 45 ++++++++++++++++----- bindings/javascript/wrapper.js | 26 +++--------- 3 files changed, 55 insertions(+), 36 deletions(-) diff --git a/bindings/javascript/__test__/limbo.spec.mjs b/bindings/javascript/__test__/limbo.spec.mjs index 8657fb8dd..c4c4c6a78 100644 --- a/bindings/javascript/__test__/limbo.spec.mjs +++ b/bindings/javascript/__test__/limbo.spec.mjs @@ -1,6 +1,6 @@ import test from "ava"; -import { Database } from "../index.js"; +import { Database } from "../wrapper.js"; test("Open in-memory database", async (t) => { const [db] = await connect(":memory:"); @@ -28,16 +28,26 @@ test("Statement.get() returns null when no data", async (t) => { test("Statement.run() returns correct result object", async (t) => { const [db] = await connect(":memory:"); db.prepare("CREATE TABLE users (name TEXT, age INTEGER)").run(); - db.prepare("INSERT INTO users (name, age) VALUES (?, ?)").run(["Alice", 42]); + db.prepare("INSERT INTO users (name, age) VALUES (?, ?)").run("Alice", 42); let rows = db.prepare("SELECT * FROM users").all(); t.deepEqual(rows, [{ name: "Alice", age: 42 }]); }); test("Statment.iterate() should correctly return an iterable object", async (t) => { const [db] = await connect(":memory:"); - db.prepare("CREATE TABLE users (name TEXT, age INTEGER)").run(); - db.prepare("INSERT INTO users (name, age) VALUES (?, ?)").run(["Alice", 42]); - db.prepare("INSERT INTO users (name, age) VALUES (?, ?)").run(["Bob", 24]); + db.prepare( + "CREATE TABLE users (name TEXT, age INTEGER, nationality TEXT)", + ).run(); + db.prepare("INSERT INTO users (name, age) VALUES (?, ?)").run( + ["Alice", 42], + "UK", + ); + db.prepare("INSERT INTO users (name, age) VALUES (?, ?)").run( + "Bob", + 24, + "USA", + ); + let rows = db.prepare("SELECT * FROM users").iterate(); for (const row of rows) { t.truthy(row.name); diff --git a/bindings/javascript/src/lib.rs b/bindings/javascript/src/lib.rs index 016c47fc4..1381c4c46 100644 --- a/bindings/javascript/src/lib.rs +++ b/bindings/javascript/src/lib.rs @@ -158,9 +158,17 @@ impl Statement { } #[napi] - pub fn get(&self, env: Env) -> napi::Result { + pub fn get(&self, env: Env, args: Option>) -> napi::Result { let mut stmt = self.inner.borrow_mut(); stmt.reset(); + + if let Some(args) = args { + for (i, elem) in args.into_iter().enumerate() { + let value = from_js_value(elem)?; + stmt.bind_at(NonZeroUsize::new(i + 1).unwrap(), value); + } + } + let step = stmt.step().map_err(into_napi_error)?; match step { limbo_core::StepResult::Row => { @@ -182,35 +190,52 @@ impl Statement { } // TODO: Return Info object (https://github.com/WiseLibs/better-sqlite3/blob/master/docs/api.md#runbindparameters---object) - // The original function is variadic, check if we can do the same #[napi] pub fn run(&self, env: Env, args: Option>) -> napi::Result { + let mut stmt = self.inner.borrow_mut(); + stmt.reset(); if let Some(args) = args { for (i, elem) in args.into_iter().enumerate() { let value = from_js_value(elem)?; - self.inner - .borrow_mut() - .bind_at(NonZeroUsize::new(i + 1).unwrap(), value); + stmt.bind_at(NonZeroUsize::new(i + 1).unwrap(), value); } } - let stmt = self.inner.borrow_mut(); self.internal_all(env, stmt) } #[napi] - pub fn iterate(&self, env: Env) -> IteratorStatement { - IteratorStatement { + pub fn iterate( + &self, + env: Env, + args: Option>, + ) -> napi::Result { + let mut stmt = self.inner.borrow_mut(); + stmt.reset(); + if let Some(args) = args { + for (i, elem) in args.into_iter().enumerate() { + let value = from_js_value(elem)?; + stmt.bind_at(NonZeroUsize::new(i + 1).unwrap(), value); + } + } + + Ok(IteratorStatement { stmt: Rc::clone(&self.inner), database: self.database.clone(), env, - } + }) } #[napi] - pub fn all(&self, env: Env) -> napi::Result { + pub fn all(&self, env: Env, args: Option>) -> napi::Result { let mut stmt = self.inner.borrow_mut(); stmt.reset(); + if let Some(args) = args { + for (i, elem) in args.into_iter().enumerate() { + let value = from_js_value(elem)?; + stmt.bind_at(NonZeroUsize::new(i + 1).unwrap(), value); + } + } self.internal_all(env, stmt) } diff --git a/bindings/javascript/wrapper.js b/bindings/javascript/wrapper.js index 15a6be079..f9584835f 100644 --- a/bindings/javascript/wrapper.js +++ b/bindings/javascript/wrapper.js @@ -178,11 +178,7 @@ class Statement { * Executes the SQL statement and returns an info object. */ run(...bindParameters) { - try { - return this.stmt.run(...bindParameters); - } catch (err) { - throw convertError(err); - } + return this.stmt.run(bindParameters.flat()); } /** @@ -191,11 +187,7 @@ class Statement { * @param bindParameters - The bind parameters for executing the statement. */ get(...bindParameters) { - try { - return this.stmt.get(...bindParameters); - } catch (err) { - throw convertError(err); - } + return this.stmt.get(bindParameters.flat()); } /** @@ -204,11 +196,7 @@ class Statement { * @param bindParameters - The bind parameters for executing the statement. */ iterate(...bindParameters) { - try { - return this.stmt.iterate(...bindParameters); - } catch (err) { - throw convertError(err); - } + return this.stmt.iterate(bindParameters.flat()); } /** @@ -217,11 +205,7 @@ class Statement { * @param bindParameters - The bind parameters for executing the statement. */ all(...bindParameters) { - try { - return this.stmt.all(...bindParameters); - } catch (err) { - throw convertError(err); - } + return this.stmt.all(bindParameters.flat()); } /** @@ -240,4 +224,4 @@ class Statement { } } -module.exports = Database; +module.exports.Database = Database;