1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-21 04:52:26 -05:00
This commit is contained in:
Divy Srivastava 2024-12-11 19:17:37 +05:30
parent 72c96bf7d3
commit 87574d241e
3 changed files with 194 additions and 167 deletions

View 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(())
}
}

View 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),
}

View file

@ -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) };