Skip to content

Commit

Permalink
compile w/o prepared statements or SQLite custom fns
Browse files Browse the repository at this point in the history
  • Loading branch information
insipx committed Aug 12, 2024
1 parent 272fce2 commit 4dc9e1f
Show file tree
Hide file tree
Showing 11 changed files with 258 additions and 250 deletions.
10 changes: 5 additions & 5 deletions diesel-wasm-sqlite/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion diesel-wasm-sqlite/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2021"
[dependencies]
# diesel = { git = "https://github.com/xmtp/diesel", branch = "insipx/wasm-backend", default-features = false, features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes"] }
diesel = "2.2"
diesel-async = { git = "https://github.com/insipx/diesel_async", branch = "insipx/wasm-async" }
diesel-async = { git = "https://github.com/insipx/diesel_async", branch = "insipx/make-stmt-cache-public", features = ["stmt-cache"] }
wasm-bindgen = "0.2.92"
wasm-bindgen-futures = "0.4.42"
log = "0.4"
Expand Down
19 changes: 17 additions & 2 deletions diesel-wasm-sqlite/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,14 +273,23 @@ export class SQLite {
}
}

create_function(database, functionName, nArg, textRep, xFunc, xStep, xFinal) {
create_function(
database,
functionName,
nArg,
textRep,
pApp,
xFunc,
xStep,
xFinal,
) {
try {
sqlite.create_function(
database,
functionName,
nArg,
textRep,
0,
pApp, // pApp is ignored
xFunc,
xStep,
xFinal,
Expand All @@ -290,4 +299,10 @@ export class SQLite {
console.log("create function err");
}
}

/*
serialize(database, zSchema, size, flags) {
return this.module._sqlite3_serialize(database, zSchema, size, flags);
}
*/
}
106 changes: 46 additions & 60 deletions diesel-wasm-sqlite/src/connection/functions.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
extern crate libsqlite3_sys as ffi;

use super::raw::RawConnection;
use super::row::PrivateSqliteRow;
use super::{Sqlite, SqliteAggregateFunction, SqliteBindValue};
use crate::backend::Backend;
use crate::deserialize::{FromSqlRow, StaticallySizedRow};
use crate::result::{DatabaseErrorKind, Error, QueryResult};
use crate::row::{Field, PartialRow, Row, RowIndex, RowSealed};
use crate::serialize::{IsNull, Output, ToSql};
use crate::sql_types::HasSqlType;
use crate::sqlite::connection::bind_collector::InternalSqliteBindValue;
use crate::sqlite::connection::sqlite_value::OwnedSqliteValue;
use crate::sqlite::SqliteValue;
use super::{/*SqliteAggregateFunction,*/ SqliteBindValue, WasmSqlite};
use crate::connection::bind_collector::InternalSqliteBindValue;
use crate::connection::sqlite_value::OwnedSqliteValue;
use crate::connection::SqliteValue;
use diesel::backend::Backend;
use diesel::deserialize::{FromSqlRow, StaticallySizedRow};
use diesel::result::{DatabaseErrorKind, Error, QueryResult};
use diesel::row::{Field, PartialRow, Row, RowIndex, RowSealed};
use diesel::serialize::{IsNull, Output, ToSql};
use diesel::sql_types::HasSqlType;
use futures::future::BoxFuture;
use futures::FutureExt;
use std::cell::{Ref, RefCell};
use std::marker::PhantomData;
use std::mem::ManuallyDrop;
use std::ops::DerefMut;
use std::rc::Rc;
use wasm_bindgen::JsValue;

pub(super) fn register<ArgsSqlType, RetSqlType, Args, Ret, F>(
conn: &RawConnection,
Expand All @@ -25,10 +26,10 @@ pub(super) fn register<ArgsSqlType, RetSqlType, Args, Ret, F>(
mut f: F,
) -> QueryResult<()>
where
F: FnMut(&RawConnection, Args) -> Ret + std::panic::UnwindSafe + Send + 'static,
Args: FromSqlRow<ArgsSqlType, Sqlite> + StaticallySizedRow<ArgsSqlType, Sqlite>,
Ret: ToSql<RetSqlType, Sqlite>,
Sqlite: HasSqlType<RetSqlType>,
F: FnMut(&RawConnection, Args) -> BoxFuture<'static, Ret>,
Args: FromSqlRow<ArgsSqlType, WasmSqlite> + StaticallySizedRow<ArgsSqlType, WasmSqlite>,
Ret: ToSql<RetSqlType, WasmSqlite>,
WasmSqlite: HasSqlType<RetSqlType>,
{
let fields_needed = Args::FIELD_COUNT;
if fields_needed > 127 {
Expand All @@ -39,13 +40,19 @@ where
}

conn.register_sql_function(fn_name, fields_needed, deterministic, move |conn, args| {
let args = build_sql_function_args::<ArgsSqlType, Args>(args)?;

Ok(f(conn, args))
async {
let args = build_sql_function_args::<ArgsSqlType, Args>(args)?;
let conn = RawConnection {
internal_connection: conn,
};
Ok(f(&conn, args).await)
}
.boxed()
})?;
Ok(())
}

/*
pub(super) fn register_noargs<RetSqlType, Ret, F>(
conn: &RawConnection,
fn_name: &str,
Expand All @@ -54,8 +61,8 @@ pub(super) fn register_noargs<RetSqlType, Ret, F>(
) -> QueryResult<()>
where
F: FnMut() -> Ret + std::panic::UnwindSafe + Send + 'static,
Ret: ToSql<RetSqlType, Sqlite>,
Sqlite: HasSqlType<RetSqlType>,
Ret: ToSql<RetSqlType, WasmSqlite>,
WasmSqlite: HasSqlType<RetSqlType>,
{
conn.register_sql_function(fn_name, 0, deterministic, move |_, _| Ok(f()))?;
Ok(())
Expand All @@ -67,9 +74,9 @@ pub(super) fn register_aggregate<ArgsSqlType, RetSqlType, Args, Ret, A>(
) -> QueryResult<()>
where
A: SqliteAggregateFunction<Args, Output = Ret> + 'static + Send + std::panic::UnwindSafe,
Args: FromSqlRow<ArgsSqlType, Sqlite> + StaticallySizedRow<ArgsSqlType, Sqlite>,
Ret: ToSql<RetSqlType, Sqlite>,
Sqlite: HasSqlType<RetSqlType>,
Args: FromSqlRow<ArgsSqlType, WasmSqlite> + StaticallySizedRow<ArgsSqlType, WasmSqlite>,
Ret: ToSql<RetSqlType, WasmSqlite>,
WasmSqlite: HasSqlType<RetSqlType>,
{
let fields_needed = Args::FIELD_COUNT;
if fields_needed > 127 {
Expand All @@ -86,12 +93,11 @@ where
Ok(())
}
*/

pub(super) fn build_sql_function_args<ArgsSqlType, Args>(
args: &mut [*mut ffi::sqlite3_value],
) -> Result<Args, Error>
pub(super) fn build_sql_function_args<ArgsSqlType, Args>(args: Vec<JsValue>) -> Result<Args, Error>
where
Args: FromSqlRow<ArgsSqlType, Sqlite>,
Args: FromSqlRow<ArgsSqlType, WasmSqlite>,
{
let row = FunctionRow::new(args);
Args::build_from_row(&row).map_err(Error::DeserializationError)
Expand All @@ -104,8 +110,8 @@ pub(super) fn process_sql_function_result<RetSqlType, Ret>(
result: &'_ Ret,
) -> QueryResult<InternalSqliteBindValue<'_>>
where
Ret: ToSql<RetSqlType, Sqlite>,
Sqlite: HasSqlType<RetSqlType>,
Ret: ToSql<RetSqlType, WasmSqlite>,
WasmSqlite: HasSqlType<RetSqlType>,
{
let mut metadata_lookup = ();
let value = SqliteBindValue {
Expand All @@ -126,7 +132,7 @@ struct FunctionRow<'a> {
// as this buffer is owned by sqlite not by diesel
args: Rc<RefCell<ManuallyDrop<PrivateSqliteRow<'a, 'static>>>>,
field_count: usize,
marker: PhantomData<&'a ffi::sqlite3_value>,
marker: PhantomData<&'a JsValue>,
}

impl<'a> Drop for FunctionRow<'a> {
Expand All @@ -148,37 +154,17 @@ impl<'a> Drop for FunctionRow<'a> {

impl<'a> FunctionRow<'a> {
#[allow(unsafe_code)] // complicated ptr cast
fn new(args: &mut [*mut ffi::sqlite3_value]) -> Self {
fn new(args: Vec<JsValue>) -> Self {
let lengths = args.len();
let args = unsafe {
Vec::from_raw_parts(
// This cast is safe because:
// * Casting from a pointer to an array to a pointer to the first array
// element is safe
// * Casting from a raw pointer to `NonNull<T>` is safe,
// because `NonNull` is #[repr(transparent)]
// * Casting from `NonNull<T>` to `OwnedSqliteValue` is safe,
// as the struct is `#[repr(transparent)]
// * Casting from `NonNull<T>` to `Option<NonNull<T>>` as the documentation
// states: "This is so that enums may use this forbidden value as a discriminant –
// Option<NonNull<T>> has the same size as *mut T"
// * The last point remains true for `OwnedSqliteValue` as `#[repr(transparent)]
// guarantees the same layout as the inner type
// * It's unsafe to drop the vector (and the vector elements)
// because of this we wrap the vector (or better the Row)
// Into `ManualDrop` to prevent the dropping
args as *mut [*mut ffi::sqlite3_value] as *mut ffi::sqlite3_value
as *mut Option<OwnedSqliteValue>,
lengths,
lengths,
)
};

Self {
field_count: lengths,
args: Rc::new(RefCell::new(ManuallyDrop::new(
PrivateSqliteRow::Duplicated {
values: args,
values: args
.into_iter()
.map(|a| Some(OwnedSqliteValue { value: a.into() }))
.collect(),
column_names: Rc::from(vec![None; lengths]),
},
))),
Expand All @@ -189,7 +175,7 @@ impl<'a> FunctionRow<'a> {

impl RowSealed for FunctionRow<'_> {}

impl<'a> Row<'a, Sqlite> for FunctionRow<'a> {
impl<'a> Row<'a, WasmSqlite> for FunctionRow<'a> {
type Field<'f> = FunctionArgument<'f> where 'a: 'f, Self: 'f;
type InnerPartialRow = Self;

Expand All @@ -200,7 +186,7 @@ impl<'a> Row<'a, Sqlite> for FunctionRow<'a> {
fn get<'b, I>(&'b self, idx: I) -> Option<Self::Field<'b>>
where
'a: 'b,
Self: crate::row::RowIndex<I>,
Self: RowIndex<I>,
{
let idx = self.idx(idx)?;
Some(FunctionArgument {
Expand Down Expand Up @@ -235,7 +221,7 @@ struct FunctionArgument<'a> {
col_idx: i32,
}

impl<'a> Field<'a, Sqlite> for FunctionArgument<'a> {
impl<'a> Field<'a, WasmSqlite> for FunctionArgument<'a> {
fn field_name(&self) -> Option<&str> {
None
}
Expand All @@ -244,7 +230,7 @@ impl<'a> Field<'a, Sqlite> for FunctionArgument<'a> {
self.value().is_none()
}

fn value(&self) -> Option<<Sqlite as Backend>::RawValue<'_>> {
fn value(&self) -> Option<<WasmSqlite as Backend>::RawValue<'_>> {
SqliteValue::new(
Ref::map(Ref::clone(&self.args), |drop| std::ops::Deref::deref(drop)),
self.col_idx,
Expand Down
Loading

0 comments on commit 4dc9e1f

Please sign in to comment.