mirror of
https://github.com/trailbaseio/trailbase
synced 2026-04-21 13:37:44 +00:00
Add a placeholder rusqlite VTab impl.
This commit is contained in:
parent
bfde60f0c4
commit
bd7cf45c3b
4 changed files with 127 additions and 17 deletions
|
|
@ -81,7 +81,7 @@ minijinja = { version = "2.1.2", default-features = false }
|
|||
parking_lot = { version = "0.12.3", default-features = false, features = ["send_guard", "arc_lock"] }
|
||||
rand = { version = "^0.9.0" }
|
||||
reqwest = { version = "0.13.1", default-features = false, features = ["rustls", "json"] }
|
||||
rusqlite = { version = "0.38.0", default-features = false, features = ["bundled", "cache", "column_decltype", "functions", "backup", "preupdate_hook"] }
|
||||
rusqlite = { version = "0.38.0", default-features = false, features = ["array", "bundled", "cache", "column_decltype", "functions", "backup", "preupdate_hook", "vtab"] }
|
||||
rust-embed = { version = "8.4.0", default-features = false, features = ["mime-guess"] }
|
||||
serde = { version = "^1.0.203", features = ["derive"] }
|
||||
serde_json = { version = "^1.0.117" }
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ interface init-endpoint {
|
|||
}
|
||||
|
||||
record sqlite-extensions {
|
||||
/// Functions returning a scalar as opposed to being "table-valued".
|
||||
/// Functions returning a scalar as opposed to aggregate or "table-valued" functions.
|
||||
scalar-functions: list<sqlite-scalar-function>,
|
||||
/// Sqlite moules.
|
||||
modules: list<sqlite-module>,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
use rusqlite::vtab::{
|
||||
Context, CreateVTab, Filters, IndexInfo, VTab, VTabConnection, VTabCursor, eponymous_only_module,
|
||||
read_only_module,
|
||||
};
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
use wasmtime::{Result, Store};
|
||||
|
|
@ -12,8 +17,14 @@ pub struct SqliteScalarFunction {
|
|||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SqliteFunctions {
|
||||
pub struct SqliteModule {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SqliteExtensions {
|
||||
pub scalar_functions: Vec<SqliteScalarFunction>,
|
||||
pub modules: Vec<SqliteModule>,
|
||||
}
|
||||
|
||||
struct SqliteStoreInternal {
|
||||
|
|
@ -38,28 +49,33 @@ impl SqliteStore {
|
|||
}
|
||||
|
||||
// Call WASM components `init` implementation.
|
||||
pub async fn initialize_sqlite_functions(
|
||||
pub async fn initialize_sqlite_extensions(
|
||||
&self,
|
||||
args: crate::InitArgs,
|
||||
) -> Result<SqliteFunctions, Error> {
|
||||
) -> Result<SqliteExtensions, Error> {
|
||||
use crate::host::exports::trailbase::component::init_endpoint::{
|
||||
Arguments, SqliteExtensions as WitSqliteExtensions,
|
||||
};
|
||||
let api = self.state.bindings.trailbase_component_init_endpoint();
|
||||
|
||||
let args = crate::host::exports::trailbase::component::init_endpoint::Arguments {
|
||||
let args = Arguments {
|
||||
version: args.version,
|
||||
};
|
||||
|
||||
let mut store = self.state.store.lock().await;
|
||||
let functions = store
|
||||
let WitSqliteExtensions {
|
||||
modules,
|
||||
scalar_functions,
|
||||
} = store
|
||||
.run_concurrent(async |accessor| -> Result<_, Error> {
|
||||
let (functions, task_exit) = api.call_init_sqlite_extensions(accessor, args).await?;
|
||||
let (extensions, task_exit) = api.call_init_sqlite_extensions(accessor, args).await?;
|
||||
task_exit.block(accessor).await;
|
||||
return Ok(functions);
|
||||
return Ok(extensions);
|
||||
})
|
||||
.await??;
|
||||
|
||||
return Ok(SqliteFunctions {
|
||||
scalar_functions: functions
|
||||
.scalar_functions
|
||||
return Ok(SqliteExtensions {
|
||||
scalar_functions: scalar_functions
|
||||
.into_iter()
|
||||
.map(|f| {
|
||||
return SqliteScalarFunction {
|
||||
|
|
@ -71,6 +87,10 @@ impl SqliteStore {
|
|||
};
|
||||
})
|
||||
.collect(),
|
||||
modules: modules
|
||||
.into_iter()
|
||||
.map(|m| return SqliteModule { name: m.name })
|
||||
.collect(),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -110,11 +130,11 @@ impl SqliteStore {
|
|||
pub fn setup_connection(
|
||||
conn: &rusqlite::Connection,
|
||||
store: SqliteStore,
|
||||
functions: &SqliteFunctions,
|
||||
extensions: SqliteExtensions,
|
||||
) -> Result<(), rusqlite::Error> {
|
||||
use crate::host::exports::trailbase::component::sqlite_function_endpoint::Value;
|
||||
|
||||
for function in &functions.scalar_functions {
|
||||
for function in &extensions.scalar_functions {
|
||||
let store = store.clone();
|
||||
let function_name = function.name.clone();
|
||||
|
||||
|
|
@ -160,5 +180,95 @@ pub fn setup_connection(
|
|||
)?;
|
||||
}
|
||||
|
||||
for module in extensions.modules {
|
||||
// TODO: call runtime to create module resource and then pass resource to Module.
|
||||
|
||||
conn
|
||||
.create_module(
|
||||
module.name.as_str(),
|
||||
// &eponymous_only_module::<WasmVTab>(),
|
||||
&read_only_module::<WasmVTab>(),
|
||||
None,
|
||||
)
|
||||
.expect("FIXME");
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// TODO: Should maybe implement UpdateVTab instead of just VTab. Should hold a WASM
|
||||
// resource.
|
||||
#[repr(C)]
|
||||
struct WasmVTab {
|
||||
/// Base class. Must be first
|
||||
base: rusqlite::vtab::sqlite3_vtab,
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
unsafe impl<'vtab> VTab<'vtab> for WasmVTab {
|
||||
type Aux = ();
|
||||
type Cursor = WasmVTabCursor<'vtab>;
|
||||
|
||||
fn connect(
|
||||
_: &mut VTabConnection,
|
||||
_aux: Option<&()>,
|
||||
_args: &[&[u8]],
|
||||
) -> rusqlite::Result<(String, Self)> {
|
||||
let vtab = Self {
|
||||
base: rusqlite::ffi::sqlite3_vtab::default(),
|
||||
};
|
||||
return Ok(("CREATE TABLE x(value)".to_owned(), vtab));
|
||||
}
|
||||
|
||||
fn best_index(&self, info: &mut IndexInfo) -> rusqlite::Result<()> {
|
||||
info.set_estimated_cost(1.);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn open(&mut self) -> rusqlite::Result<WasmVTabCursor<'_>> {
|
||||
Ok(WasmVTabCursor::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'vtab> CreateVTab<'vtab> for WasmVTab {
|
||||
const KIND: rusqlite::vtab::VTabKind = rusqlite::vtab::VTabKind::Default;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[repr(C)]
|
||||
struct WasmVTabCursor<'vtab> {
|
||||
/// Base class. Must be first
|
||||
base: rusqlite::ffi::sqlite3_vtab_cursor,
|
||||
/// The rowid
|
||||
row_id: i64,
|
||||
phantom: PhantomData<&'vtab WasmVTab>,
|
||||
}
|
||||
|
||||
unsafe impl VTabCursor for WasmVTabCursor<'_> {
|
||||
fn filter(
|
||||
&mut self,
|
||||
_idx_num: std::ffi::c_int,
|
||||
_idx_str: Option<&str>,
|
||||
_args: &Filters<'_>,
|
||||
) -> rusqlite::Result<()> {
|
||||
self.row_id = 1;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn next(&mut self) -> rusqlite::Result<()> {
|
||||
self.row_id += 1;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn eof(&self) -> bool {
|
||||
return self.row_id > 1;
|
||||
}
|
||||
|
||||
fn column(&self, ctx: &mut Context, i: std::ffi::c_int) -> rusqlite::Result<()> {
|
||||
return ctx.set_result(&self.row_id);
|
||||
}
|
||||
|
||||
fn rowid(&self) -> rusqlite::Result<i64> {
|
||||
return Ok(self.row_id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -503,12 +503,12 @@ mod tests {
|
|||
|
||||
let store = functions::SqliteStore::new(&runtime).await.unwrap();
|
||||
|
||||
let functions = store
|
||||
.initialize_sqlite_functions(InitArgs { version: None })
|
||||
let extensions = store
|
||||
.initialize_sqlite_extensions(InitArgs { version: None })
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
functions::setup_connection(conn, store, &functions).unwrap();
|
||||
functions::setup_connection(conn, store, extensions).unwrap();
|
||||
|
||||
return runtime;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue