use crate::wit_bindgen;
#[doc(hidden)]
pub mod wit {
#![allow(missing_docs)]
use crate::wit_bindgen;
wit_bindgen::generate!({
runtime_path: "crate::wit_bindgen::rt",
world: "spin-sdk-sqlite",
path: "wit",
generate_all,
});
pub use spin::sqlite::sqlite;
}
#[doc(inline)]
pub use wit::sqlite::{Error, Value};
pub struct Connection(wit::sqlite::Connection);
impl Connection {
pub async fn open_default() -> Result<Self, Error> {
Self::open("default").await
}
pub async fn open(database: impl AsRef<str>) -> Result<Self, Error> {
wit::sqlite::Connection::open_async(database.as_ref().to_string())
.await
.map(Connection)
}
pub async fn execute(
&self,
statement: impl AsRef<str>,
parameters: impl IntoIterator<Item = Value>,
) -> Result<QueryResult, Error> {
let (columns, rows, result) = self
.0
.execute_async(
statement.as_ref().to_string(),
parameters.into_iter().collect(),
)
.await?;
Ok(QueryResult {
columns,
rows,
result,
})
}
pub async fn last_insert_rowid(&self) -> i64 {
self.0.last_insert_rowid_async().await
}
pub async fn changes(&self) -> u64 {
self.0.changes_async().await
}
}
pub struct QueryResult {
columns: Vec<String>,
rows: wit_bindgen::StreamReader<RowResult>,
result: wit_bindgen::FutureReader<Result<(), Error>>,
}
impl QueryResult {
pub fn columns(&self) -> &[String] {
&self.columns
}
pub async fn next(&mut self) -> Option<RowResult> {
self.rows.next().await
}
pub async fn result(self) -> Result<(), Error> {
self.result.await
}
pub async fn collect(self) -> Result<Vec<RowResult>, Error> {
let rows = self.rows.collect().await;
self.result.await?;
Ok(rows)
}
#[allow(clippy::type_complexity, reason = "that's what the inner bits are")]
pub fn into_inner(
self,
) -> (
Vec<String>,
wit_bindgen::StreamReader<RowResult>,
wit_bindgen::FutureReader<Result<(), Error>>,
) {
(self.columns, self.rows, self.result)
}
}
#[doc(inline)]
pub use wit::sqlite::RowResult;
impl RowResult {
pub fn get<'a, T: TryFrom<&'a Value>>(&'a self, index: usize) -> Option<T> {
self.values.get(index).and_then(|c| c.try_into().ok())
}
}
impl<'a> TryFrom<&'a Value> for bool {
type Error = ();
fn try_from(value: &'a Value) -> Result<Self, Self::Error> {
match value {
Value::Integer(i) => Ok(*i != 0),
_ => Err(()),
}
}
}
macro_rules! int_conversions {
($($t:ty),*) => {
$(impl<'a> TryFrom<&'a Value> for $t {
type Error = ();
fn try_from(value: &'a Value) -> Result<Self, Self::Error> {
match value {
Value::Integer(i) => (*i).try_into().map_err(|_| ()),
_ => Err(()),
}
}
})*
};
}
int_conversions!(u8, u16, u32, u64, i8, i16, i32, i64, usize, isize);
impl<'a> TryFrom<&'a Value> for f64 {
type Error = ();
fn try_from(value: &'a Value) -> Result<Self, Self::Error> {
match value {
Value::Real(f) => Ok(*f),
_ => Err(()),
}
}
}
impl<'a> TryFrom<&'a Value> for &'a str {
type Error = ();
fn try_from(value: &'a Value) -> Result<Self, Self::Error> {
match value {
Value::Text(s) => Ok(s.as_str()),
Value::Blob(b) => std::str::from_utf8(b).map_err(|_| ()),
_ => Err(()),
}
}
}
impl<'a> TryFrom<&'a Value> for &'a [u8] {
type Error = ();
fn try_from(value: &'a Value) -> Result<Self, Self::Error> {
match value {
Value::Blob(b) => Ok(b.as_slice()),
Value::Text(s) => Ok(s.as_bytes()),
_ => Err(()),
}
}
}