mirror of
https://github.com/denoland/deno.git
synced 2025-01-21 13:00:36 -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::op2;
|
||||||
use deno_core::v8;
|
use deno_core::v8;
|
||||||
use deno_core::GarbageCollected;
|
use deno_core::GarbageCollected;
|
||||||
use serde::Deserialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
use super::SqliteError;
|
||||||
pub enum SqliteError {
|
|
||||||
#[error(transparent)]
|
|
||||||
SqliteError(#[from] rusqlite::Error),
|
|
||||||
#[error("Database is already in use")]
|
|
||||||
InUse,
|
|
||||||
#[error(transparent)]
|
|
||||||
Other(deno_core::error::AnyError),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
struct DatabaseSyncOptions {
|
pub struct RunStatementResult {
|
||||||
open: bool,
|
last_insert_rowid: i64,
|
||||||
enable_foreign_key_constraints: bool,
|
changes: u64,
|
||||||
}
|
|
||||||
|
|
||||||
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 StatementSync {
|
pub struct StatementSync {
|
||||||
inner: *mut libsqlite3_sys::sqlite3_stmt,
|
pub inner: *mut libsqlite3_sys::sqlite3_stmt,
|
||||||
use_big_ints: bool,
|
pub db: Rc<RefCell<Option<rusqlite::Connection>>>,
|
||||||
allow_bare_named_params: bool,
|
|
||||||
db: Rc<RefCell<Option<rusqlite::Connection>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GarbageCollected for StatementSync {}
|
impl GarbageCollected for StatementSync {}
|
||||||
|
@ -187,8 +49,7 @@ impl StatementSync {
|
||||||
return Ok(v8::Object::new(scope));
|
return Ok(v8::Object::new(scope));
|
||||||
}
|
}
|
||||||
if r != libsqlite3_sys::SQLITE_ROW {
|
if r != libsqlite3_sys::SQLITE_ROW {
|
||||||
// return Err(AnyError::msg("Failed to step statement"));
|
return Err(SqliteError::FailedStep);
|
||||||
return panic!("Failed to step statement");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let columns = libsqlite3_sys::sqlite3_column_count(raw);
|
let columns = libsqlite3_sys::sqlite3_column_count(raw);
|
||||||
|
@ -230,8 +91,7 @@ impl StatementSync {
|
||||||
}
|
}
|
||||||
libsqlite3_sys::SQLITE_NULL => v8::null(scope).into(),
|
libsqlite3_sys::SQLITE_NULL => v8::null(scope).into(),
|
||||||
_ => {
|
_ => {
|
||||||
// return Err(AnyError::msg("Unknown column type"));
|
return Err(SqliteError::UnknownColumnType);
|
||||||
return panic!("Unknown column type");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -251,8 +111,41 @@ impl StatementSync {
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fast]
|
#[serde]
|
||||||
fn run(&self) {}
|
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>(
|
fn all<'a>(
|
||||||
&self,
|
&self,
|
||||||
|
@ -272,8 +165,7 @@ impl StatementSync {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if r != libsqlite3_sys::SQLITE_ROW {
|
if r != libsqlite3_sys::SQLITE_ROW {
|
||||||
// return Err(AnyError::msg("Failed to step statement"));
|
return Err(SqliteError::FailedStep);
|
||||||
return panic!("Failed to step statement");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let columns = libsqlite3_sys::sqlite3_column_count(raw);
|
let columns = libsqlite3_sys::sqlite3_column_count(raw);
|
||||||
|
@ -316,8 +208,7 @@ impl StatementSync {
|
||||||
}
|
}
|
||||||
libsqlite3_sys::SQLITE_NULL => v8::null(scope).into(),
|
libsqlite3_sys::SQLITE_NULL => v8::null(scope).into(),
|
||||||
_ => {
|
_ => {
|
||||||
// return Err(AnyError::msg("Unknown column type"));
|
return Err(SqliteError::UnknownColumnType);
|
||||||
return panic!("Unknown column type");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -341,19 +232,12 @@ impl StatementSync {
|
||||||
Ok(arr)
|
Ok(arr)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fast]
|
|
||||||
fn set_allowed_bare_named_parameters(&self, enabled: bool) {}
|
|
||||||
|
|
||||||
#[fast]
|
|
||||||
fn set_read_bigints(&self, enabled: bool) {}
|
|
||||||
|
|
||||||
#[string]
|
#[string]
|
||||||
fn source_sql(&self) -> Result<String, SqliteError> {
|
fn source_sql(&self) -> Result<String, SqliteError> {
|
||||||
let raw = unsafe { libsqlite3_sys::sqlite3_sql(self.inner) };
|
let raw = unsafe { libsqlite3_sys::sqlite3_sql(self.inner) };
|
||||||
|
|
||||||
if raw.is_null() {
|
if raw.is_null() {
|
||||||
// return Err(AnyError::msg("Failed to get SQL"));
|
return Err(SqliteError::GetSqlFailed);
|
||||||
panic!("Failed to get SQL");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let cstr = unsafe { std::ffi::CStr::from_ptr(raw) };
|
let cstr = unsafe { std::ffi::CStr::from_ptr(raw) };
|
||||||
|
@ -363,11 +247,10 @@ impl StatementSync {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[string]
|
#[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) };
|
let raw = unsafe { libsqlite3_sys::sqlite3_expanded_sql(self.inner) };
|
||||||
if raw.is_null() {
|
if raw.is_null() {
|
||||||
// return Err(AnyError::msg("Failed to expand SQL"));
|
return Err(SqliteError::GetSqlFailed);
|
||||||
panic!("Failed to expand SQL");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let cstr = unsafe { std::ffi::CStr::from_ptr(raw) };
|
let cstr = unsafe { std::ffi::CStr::from_ptr(raw) };
|
Loading…
Add table
Reference in a new issue