use libsql::params::IntoParams;
use crate::error::{Error, Result};
use super::from_row::FromRow;
pub trait ConnExt: Sync {
fn query_raw(
&self,
sql: &str,
params: impl IntoParams + Send,
) -> impl std::future::Future<Output = std::result::Result<libsql::Rows, libsql::Error>> + Send;
fn execute_raw(
&self,
sql: &str,
params: impl IntoParams + Send,
) -> impl std::future::Future<Output = std::result::Result<u64, libsql::Error>> + Send;
fn select<'a>(&'a self, sql: &str) -> super::select::SelectBuilder<'a, Self>
where
Self: Sized,
{
super::select::SelectBuilder::new(self, sql)
}
}
impl ConnExt for libsql::Connection {
fn query_raw(
&self,
sql: &str,
params: impl IntoParams + Send,
) -> impl std::future::Future<Output = std::result::Result<libsql::Rows, libsql::Error>> + Send
{
self.query(sql, params)
}
fn execute_raw(
&self,
sql: &str,
params: impl IntoParams + Send,
) -> impl std::future::Future<Output = std::result::Result<u64, libsql::Error>> + Send {
self.execute(sql, params)
}
}
impl ConnExt for libsql::Transaction {
fn query_raw(
&self,
sql: &str,
params: impl IntoParams + Send,
) -> impl std::future::Future<Output = std::result::Result<libsql::Rows, libsql::Error>> + Send
{
self.query(sql, params)
}
fn execute_raw(
&self,
sql: &str,
params: impl IntoParams + Send,
) -> impl std::future::Future<Output = std::result::Result<u64, libsql::Error>> + Send {
self.execute(sql, params)
}
}
pub trait ConnQueryExt: ConnExt {
fn query_one<T: FromRow + Send>(
&self,
sql: &str,
params: impl IntoParams + Send,
) -> impl std::future::Future<Output = Result<T>> + Send {
async move {
let mut rows = self.query_raw(sql, params).await.map_err(Error::from)?;
let row = rows
.next()
.await
.map_err(Error::from)?
.ok_or_else(|| Error::not_found("record not found"))?;
T::from_row(&row)
}
}
fn query_optional<T: FromRow + Send>(
&self,
sql: &str,
params: impl IntoParams + Send,
) -> impl std::future::Future<Output = Result<Option<T>>> + Send {
async move {
let mut rows = self.query_raw(sql, params).await.map_err(Error::from)?;
match rows.next().await.map_err(Error::from)? {
Some(row) => Ok(Some(T::from_row(&row)?)),
None => Ok(None),
}
}
}
fn query_all<T: FromRow + Send>(
&self,
sql: &str,
params: impl IntoParams + Send,
) -> impl std::future::Future<Output = Result<Vec<T>>> + Send {
async move {
let mut rows = self.query_raw(sql, params).await.map_err(Error::from)?;
let mut result = Vec::new();
while let Some(row) = rows.next().await.map_err(Error::from)? {
result.push(T::from_row(&row)?);
}
Ok(result)
}
}
fn query_one_map<T: Send, F>(
&self,
sql: &str,
params: impl IntoParams + Send,
f: F,
) -> impl std::future::Future<Output = Result<T>> + Send
where
F: Fn(&libsql::Row) -> Result<T> + Send,
{
async move {
let mut rows = self.query_raw(sql, params).await.map_err(Error::from)?;
let row = rows
.next()
.await
.map_err(Error::from)?
.ok_or_else(|| Error::not_found("record not found"))?;
f(&row)
}
}
fn query_optional_map<T: Send, F>(
&self,
sql: &str,
params: impl IntoParams + Send,
f: F,
) -> impl std::future::Future<Output = Result<Option<T>>> + Send
where
F: Fn(&libsql::Row) -> Result<T> + Send,
{
async move {
let mut rows = self.query_raw(sql, params).await.map_err(Error::from)?;
match rows.next().await.map_err(Error::from)? {
Some(row) => Ok(Some(f(&row)?)),
None => Ok(None),
}
}
}
fn query_all_map<T: Send, F>(
&self,
sql: &str,
params: impl IntoParams + Send,
f: F,
) -> impl std::future::Future<Output = Result<Vec<T>>> + Send
where
F: Fn(&libsql::Row) -> Result<T> + Send,
{
async move {
let mut rows = self.query_raw(sql, params).await.map_err(Error::from)?;
let mut result = Vec::new();
while let Some(row) = rows.next().await.map_err(Error::from)? {
result.push(f(&row)?);
}
Ok(result)
}
}
}
impl<T: ConnExt> ConnQueryExt for T {}