mirror of
https://github.com/denoland/deno.git
synced 2025-01-21 04:52:26 -05:00
changes
This commit is contained in:
parent
72c96bf7d3
commit
87574d241e
3 changed files with 194 additions and 167 deletions
123
ext/node/ops/sqlite/database.rs
Normal file
123
ext/node/ops/sqlite/database.rs
Normal file
|
@ -0,0 +1,123 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use deno_core::op2;
|
||||
use deno_core::GarbageCollected;
|
||||
use serde::Deserialize;
|
||||
|
||||
use super::SqliteError;
|
||||
use super::StatementSync;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct DatabaseSyncOptions {
|
||||
#[serde(default = "true_fn")]
|
||||
open: bool,
|
||||
#[serde(default = "true_fn")]
|
||||
enable_foreign_key_constraints: bool,
|
||||
}
|
||||
|
||||
fn true_fn() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
impl Default for DatabaseSyncOptions {
|
||||
fn default() -> Self {
|
||||
DatabaseSyncOptions {
|
||||
open: true,
|
||||
enable_foreign_key_constraints: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DatabaseSync {
|
||||
conn: Rc<RefCell<Option<rusqlite::Connection>>>,
|
||||
options: DatabaseSyncOptions,
|
||||
location: String,
|
||||
}
|
||||
|
||||
impl GarbageCollected for DatabaseSync {}
|
||||
|
||||
#[op2]
|
||||
impl DatabaseSync {
|
||||
#[constructor]
|
||||
#[cppgc]
|
||||
fn new(
|
||||
#[string] location: String,
|
||||
#[serde] options: Option<DatabaseSyncOptions>,
|
||||
) -> Result<DatabaseSync, SqliteError> {
|
||||
let options = options.unwrap_or_default();
|
||||
|
||||
let db = if options.open {
|
||||
let db = rusqlite::Connection::open(&location)?;
|
||||
if options.enable_foreign_key_constraints {
|
||||
db.execute("PRAGMA foreign_keys = ON", [])?;
|
||||
}
|
||||
Some(db)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(DatabaseSync {
|
||||
conn: Rc::new(RefCell::new(db)),
|
||||
location,
|
||||
options,
|
||||
})
|
||||
}
|
||||
|
||||
#[fast]
|
||||
fn open(&self) -> Result<(), SqliteError> {
|
||||
let db = rusqlite::Connection::open(&self.location)?;
|
||||
if self.options.enable_foreign_key_constraints {
|
||||
db.execute("PRAGMA foreign_keys = ON", [])?;
|
||||
}
|
||||
|
||||
*self.conn.borrow_mut() = Some(db);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[fast]
|
||||
fn close(&self) {}
|
||||
|
||||
#[cppgc]
|
||||
fn prepare(&self, #[string] sql: &str) -> Result<StatementSync, SqliteError> {
|
||||
let db = self.conn.borrow();
|
||||
let db = db.as_ref().ok_or(SqliteError::InUse)?;
|
||||
|
||||
let raw_handle = unsafe { db.handle() };
|
||||
|
||||
let mut raw_stmt = std::ptr::null_mut();
|
||||
let r = unsafe {
|
||||
libsqlite3_sys::sqlite3_prepare_v2(
|
||||
raw_handle,
|
||||
sql.as_ptr() as *const i8,
|
||||
sql.len() as i32,
|
||||
&mut raw_stmt,
|
||||
std::ptr::null_mut(),
|
||||
)
|
||||
};
|
||||
|
||||
if r != libsqlite3_sys::SQLITE_OK {
|
||||
panic!("Failed to prepare statement");
|
||||
}
|
||||
|
||||
Ok(StatementSync {
|
||||
inner: raw_stmt,
|
||||
db: self.conn.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
#[fast]
|
||||
fn exec(&self, #[string] sql: &str) -> Result<(), SqliteError> {
|
||||
let db = self.conn.borrow();
|
||||
let db = db.as_ref().ok_or(SqliteError::InUse)?;
|
||||
|
||||
let mut stmt = db.prepare_cached(sql)?;
|
||||
stmt.raw_execute()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
21
ext/node/ops/sqlite/mod.rs
Normal file
21
ext/node/ops/sqlite/mod.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
mod database;
|
||||
mod statement;
|
||||
|
||||
pub use database::DatabaseSync;
|
||||
pub use statement::StatementSync;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum SqliteError {
|
||||
#[error(transparent)]
|
||||
SqliteError(#[from] rusqlite::Error),
|
||||
#[error("Database is already in use")]
|
||||
InUse,
|
||||
#[error("Failed to step statement")]
|
||||
FailedStep,
|
||||
#[error("Unknown column type")]
|
||||
UnknownColumnType,
|
||||
#[error("Failed to get SQL")]
|
||||
GetSqlFailed,
|
||||
#[error(transparent)]
|
||||
Other(deno_core::error::AnyError),
|
||||
}
|
|
@ -6,158 +6,20 @@ use std::rc::Rc;
|
|||
use deno_core::op2;
|
||||
use deno_core::v8;
|
||||
use deno_core::GarbageCollected;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum SqliteError {
|
||||
#[error(transparent)]
|
||||
SqliteError(#[from] rusqlite::Error),
|
||||
#[error("Database is already in use")]
|
||||
InUse,
|
||||
#[error(transparent)]
|
||||
Other(deno_core::error::AnyError),
|
||||
}
|
||||
use super::SqliteError;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct DatabaseSyncOptions {
|
||||
open: bool,
|
||||
enable_foreign_key_constraints: bool,
|
||||
}
|
||||
|
||||
pub struct DatabaseSync {
|
||||
conn: Rc<RefCell<Option<rusqlite::Connection>>>,
|
||||
options: DatabaseSyncOptions,
|
||||
location: String,
|
||||
}
|
||||
|
||||
impl GarbageCollected for DatabaseSync {}
|
||||
|
||||
#[op2]
|
||||
impl DatabaseSync {
|
||||
#[constructor]
|
||||
#[cppgc]
|
||||
fn new(
|
||||
#[string] location: String,
|
||||
#[serde] options: DatabaseSyncOptions,
|
||||
) -> Result<DatabaseSync, SqliteError> {
|
||||
let db = if options.open {
|
||||
let db = rusqlite::Connection::open(&location)?;
|
||||
if options.enable_foreign_key_constraints {
|
||||
db.execute("PRAGMA foreign_keys = ON", [])?;
|
||||
}
|
||||
Some(db)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(DatabaseSync {
|
||||
conn: Rc::new(RefCell::new(db)),
|
||||
location,
|
||||
options,
|
||||
})
|
||||
}
|
||||
|
||||
#[fast]
|
||||
fn open(&self) -> Result<(), SqliteError> {
|
||||
let db = rusqlite::Connection::open(&self.location)?;
|
||||
if self.options.enable_foreign_key_constraints {
|
||||
db.execute("PRAGMA foreign_keys = ON", [])?;
|
||||
}
|
||||
|
||||
*self.conn.borrow_mut() = Some(db);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[fast]
|
||||
fn close(&self) {}
|
||||
|
||||
#[cppgc]
|
||||
fn prepare(&self, #[string] sql: &str) -> Result<StatementSync, SqliteError> {
|
||||
let db = self.conn.borrow();
|
||||
let db = db.as_ref().ok_or(SqliteError::InUse)?;
|
||||
|
||||
let raw_handle = unsafe { db.handle() };
|
||||
|
||||
let mut raw_stmt = std::ptr::null_mut();
|
||||
let r = unsafe {
|
||||
libsqlite3_sys::sqlite3_prepare_v2(
|
||||
raw_handle,
|
||||
sql.as_ptr() as *const i8,
|
||||
sql.len() as i32,
|
||||
&mut raw_stmt,
|
||||
std::ptr::null_mut(),
|
||||
)
|
||||
};
|
||||
|
||||
if r != libsqlite3_sys::SQLITE_OK {
|
||||
panic!("Failed to prepare statement");
|
||||
}
|
||||
|
||||
Ok(StatementSync {
|
||||
inner: raw_stmt,
|
||||
use_big_ints: false,
|
||||
allow_bare_named_params: false,
|
||||
db: self.conn.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
#[nofast] // divy will fix this dw
|
||||
fn exec(
|
||||
&self,
|
||||
scope: &mut v8::HandleScope,
|
||||
#[string] sql: &str,
|
||||
#[varargs] params: Option<&v8::FunctionCallbackArguments>,
|
||||
) -> Result<(), SqliteError> {
|
||||
let db = self.conn.borrow();
|
||||
let db = db.as_ref().ok_or(SqliteError::InUse)?;
|
||||
|
||||
let mut stmt = db.prepare_cached(sql)?;
|
||||
if let Some(params) = params {
|
||||
bind(&mut stmt, scope, params, 1)?;
|
||||
}
|
||||
stmt.raw_execute()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn bind(
|
||||
stmt: &mut rusqlite::Statement,
|
||||
scope: &mut v8::HandleScope,
|
||||
params: &v8::FunctionCallbackArguments,
|
||||
offset: usize,
|
||||
) -> Result<(), SqliteError> {
|
||||
for index in offset..params.length() as usize {
|
||||
let value = params.get(index as i32);
|
||||
let index = (index + 1) - offset;
|
||||
if value.is_null() {
|
||||
// stmt.raw_bind_parameter(index, ())?;
|
||||
} else if value.is_boolean() {
|
||||
stmt.raw_bind_parameter(index, value.is_true())?;
|
||||
} else if value.is_int32() {
|
||||
stmt.raw_bind_parameter(index, value.integer_value(scope).unwrap())?;
|
||||
} else if value.is_number() {
|
||||
stmt.raw_bind_parameter(index, value.number_value(scope).unwrap())?;
|
||||
} else if value.is_big_int() {
|
||||
let bigint = value.to_big_int(scope).unwrap();
|
||||
let (value, _) = bigint.i64_value();
|
||||
stmt.raw_bind_parameter(index, value)?;
|
||||
} else if value.is_string() {
|
||||
stmt.raw_bind_parameter(index, value.to_rust_string_lossy(scope))?;
|
||||
}
|
||||
// TODO: Blobs
|
||||
}
|
||||
|
||||
Ok(())
|
||||
pub struct RunStatementResult {
|
||||
last_insert_rowid: i64,
|
||||
changes: u64,
|
||||
}
|
||||
|
||||
pub struct StatementSync {
|
||||
inner: *mut libsqlite3_sys::sqlite3_stmt,
|
||||
use_big_ints: bool,
|
||||
allow_bare_named_params: bool,
|
||||
db: Rc<RefCell<Option<rusqlite::Connection>>>,
|
||||
pub inner: *mut libsqlite3_sys::sqlite3_stmt,
|
||||
pub db: Rc<RefCell<Option<rusqlite::Connection>>>,
|
||||
}
|
||||
|
||||
impl GarbageCollected for StatementSync {}
|
||||
|
@ -187,8 +49,7 @@ impl StatementSync {
|
|||
return Ok(v8::Object::new(scope));
|
||||
}
|
||||
if r != libsqlite3_sys::SQLITE_ROW {
|
||||
// return Err(AnyError::msg("Failed to step statement"));
|
||||
return panic!("Failed to step statement");
|
||||
return Err(SqliteError::FailedStep);
|
||||
}
|
||||
|
||||
let columns = libsqlite3_sys::sqlite3_column_count(raw);
|
||||
|
@ -230,8 +91,7 @@ impl StatementSync {
|
|||
}
|
||||
libsqlite3_sys::SQLITE_NULL => v8::null(scope).into(),
|
||||
_ => {
|
||||
// return Err(AnyError::msg("Unknown column type"));
|
||||
return panic!("Unknown column type");
|
||||
return Err(SqliteError::UnknownColumnType);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -251,8 +111,41 @@ impl StatementSync {
|
|||
Ok(result)
|
||||
}
|
||||
|
||||
#[fast]
|
||||
fn run(&self) {}
|
||||
#[serde]
|
||||
fn run(
|
||||
&self,
|
||||
scope: &mut v8::HandleScope,
|
||||
#[varargs] params: Option<&v8::FunctionCallbackArguments>,
|
||||
) -> Result<RunStatementResult, SqliteError> {
|
||||
let raw = self.inner;
|
||||
let db = self.db.borrow();
|
||||
let db = db.as_ref().unwrap();
|
||||
|
||||
let last_insert_rowid;
|
||||
let changes;
|
||||
|
||||
unsafe {
|
||||
libsqlite3_sys::sqlite3_reset(raw);
|
||||
|
||||
loop {
|
||||
let r = libsqlite3_sys::sqlite3_step(raw);
|
||||
if r == libsqlite3_sys::SQLITE_DONE {
|
||||
break;
|
||||
}
|
||||
if r != libsqlite3_sys::SQLITE_ROW {
|
||||
return Err(SqliteError::FailedStep);
|
||||
}
|
||||
}
|
||||
|
||||
last_insert_rowid = db.last_insert_rowid();
|
||||
changes = db.changes();
|
||||
}
|
||||
|
||||
Ok(RunStatementResult {
|
||||
last_insert_rowid,
|
||||
changes,
|
||||
})
|
||||
}
|
||||
|
||||
fn all<'a>(
|
||||
&self,
|
||||
|
@ -272,8 +165,7 @@ impl StatementSync {
|
|||
break;
|
||||
}
|
||||
if r != libsqlite3_sys::SQLITE_ROW {
|
||||
// return Err(AnyError::msg("Failed to step statement"));
|
||||
return panic!("Failed to step statement");
|
||||
return Err(SqliteError::FailedStep);
|
||||
}
|
||||
|
||||
let columns = libsqlite3_sys::sqlite3_column_count(raw);
|
||||
|
@ -316,8 +208,7 @@ impl StatementSync {
|
|||
}
|
||||
libsqlite3_sys::SQLITE_NULL => v8::null(scope).into(),
|
||||
_ => {
|
||||
// return Err(AnyError::msg("Unknown column type"));
|
||||
return panic!("Unknown column type");
|
||||
return Err(SqliteError::UnknownColumnType);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -341,19 +232,12 @@ impl StatementSync {
|
|||
Ok(arr)
|
||||
}
|
||||
|
||||
#[fast]
|
||||
fn set_allowed_bare_named_parameters(&self, enabled: bool) {}
|
||||
|
||||
#[fast]
|
||||
fn set_read_bigints(&self, enabled: bool) {}
|
||||
|
||||
#[string]
|
||||
fn source_sql(&self) -> Result<String, SqliteError> {
|
||||
let raw = unsafe { libsqlite3_sys::sqlite3_sql(self.inner) };
|
||||
|
||||
if raw.is_null() {
|
||||
// return Err(AnyError::msg("Failed to get SQL"));
|
||||
panic!("Failed to get SQL");
|
||||
return Err(SqliteError::GetSqlFailed);
|
||||
}
|
||||
|
||||
let cstr = unsafe { std::ffi::CStr::from_ptr(raw) };
|
||||
|
@ -363,11 +247,10 @@ impl StatementSync {
|
|||
}
|
||||
|
||||
#[string]
|
||||
fn expanded_sql(&self) -> Result<String, SqliteError> {
|
||||
fn expanded_SQL(&self) -> Result<String, SqliteError> {
|
||||
let raw = unsafe { libsqlite3_sys::sqlite3_expanded_sql(self.inner) };
|
||||
if raw.is_null() {
|
||||
// return Err(AnyError::msg("Failed to expand SQL"));
|
||||
panic!("Failed to expand SQL");
|
||||
return Err(SqliteError::GetSqlFailed);
|
||||
}
|
||||
|
||||
let cstr = unsafe { std::ffi::CStr::from_ptr(raw) };
|
Loading…
Add table
Reference in a new issue