bind/js: Partially implements pragma

Some pragmas may return more than one value, which would
break the current logic. So this cause should be handled in the future
This commit is contained in:
Diego Reis 2025-05-25 15:56:28 -03:00
parent 1ff454853b
commit 60b78b3566
4 changed files with 70 additions and 9 deletions

View file

@ -52,6 +52,12 @@ test("Empty prepared statement should throw", async (t) => {
);
});
test("Test pragma", async (t) => {
const [db] = await connect(":memory:");
t.deepEqual(typeof db.pragma("cache_size")[0].cache_size, "number");
t.deepEqual(typeof db.pragma("cache_size", { simple: true }), "number");
});
const connect = async (path) => {
const db = new Database(path);
return [db];

View file

@ -65,6 +65,12 @@ test("Empty prepared statement should throw", async (t) => {
);
});
test("Test pragma", async (t) => {
const [db] = await connect(":memory:");
t.deepEqual(typeof db.pragma("cache_size")[0].cache_size, "number");
t.deepEqual(typeof db.pragma("cache_size", { simple: true }), "number");
});
const connect = async (path) => {
const db = new Database(path);
return [db];

View file

@ -83,11 +83,6 @@ impl Database {
Ok(Statement::new(RefCell::new(stmt), self.clone(), sql))
}
#[napi]
pub fn pragma(&self) {
todo!()
}
#[napi]
pub fn backup(&self) {
todo!()
@ -128,6 +123,46 @@ impl Database {
self.conn.close().map_err(into_napi_error)?;
Ok(())
}
// We assume that every pragma only returns one result, which isn't
// true.
#[napi]
pub fn pragma(&self, env: Env, pragma: String, simple: bool) -> napi::Result<JsUnknown> {
let stmt = self.prepare(pragma.clone())?;
let mut stmt = stmt.inner.borrow_mut();
let pragma_name = pragma
.split("PRAGMA")
.filter(|s| !s.trim().is_empty())
.next()
.map(str::trim)
.unwrap();
let mut results = env.create_empty_array()?;
let step = stmt.step().map_err(into_napi_error)?;
match step {
limbo_core::StepResult::Row => {
let row = stmt.row().unwrap();
let mut obj = env.create_object()?;
for (_, value) in row.get_values().enumerate() {
let js_value = to_js_value(&env, value)?;
if simple {
return Ok(js_value);
}
obj.set_named_property(&pragma_name, js_value)?;
}
results.set_element(0, obj)?;
Ok(results.into_unknown())
}
limbo_core::StepResult::Done => Ok(env.get_undefined()?.into_unknown()),
limbo_core::StepResult::IO => todo!(),
limbo_core::StepResult::Interrupt | limbo_core::StepResult::Busy => Err(
napi::Error::new(napi::Status::GenericFailure, format!("{:?}", step)),
),
}
}
}
// TODO: Add the (parent) 'database' property
@ -142,6 +177,8 @@ pub struct Statement {
// pub busy: bool,
#[napi(writable = false)]
pub source: String,
toggle: bool,
database: Database,
inner: Rc<RefCell<limbo_core::Statement>>,
}
@ -153,6 +190,7 @@ impl Statement {
inner: Rc::new(inner),
database,
source,
toggle: false,
}
}
@ -278,9 +316,14 @@ impl Statement {
}
#[napi]
pub fn pluck() {
todo!()
pub fn pluck(&mut self, toggle: Option<bool>) {
if let Some(false) = toggle {
self.toggle = false;
}
self.toggle = true;
}
#[napi]
pub fn expand() {
todo!()

View file

@ -77,13 +77,19 @@ class Database {
pragma(source, options) {
if (options == null) options = {};
if (typeof source !== "string")
throw new TypeError("Expected first argument to be a string");
if (typeof options !== "object")
throw new TypeError("Expected second argument to be an options object");
const simple = options["simple"];
const stmt = this.prepare(`PRAGMA ${source}`, this, true);
return simple ? stmt.pluck().get() : stmt.all();
const pragma = `PRAGMA ${source}`;
return simple
? this.db.pragma(pragma, true)
: this.db.pragma(pragma, false);
}
backup(filename, options) {