use std::fmt;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use keelson_core::{Query, QueryType, Value};
use crate::error::ExecError;
use crate::row::Row;
pub type ExecFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Family {
Postgres,
MySql,
Sqlite,
}
impl Family {
pub fn as_str(self) -> &'static str {
match self {
Family::Postgres => "postgresql",
Family::MySql => "mysql",
Family::Sqlite => "sqlite",
}
}
}
impl fmt::Display for Family {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct Statement {
pub sql: String,
pub args: Vec<Value>,
pub query_type: QueryType,
}
impl Statement {
pub fn new(sql: impl Into<String>, args: Vec<Value>) -> Self {
Statement {
sql: sql.into(),
args,
query_type: QueryType::Unknown,
}
}
pub fn from_query(q: &(impl Query + ?Sized)) -> Result<Self, ExecError> {
let (sql, args) = q.build()?;
Ok(Statement {
sql,
args,
query_type: q.query_type(),
})
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[non_exhaustive]
pub struct ExecResult {
pub rows_affected: u64,
pub last_insert_id: Option<i64>,
}
impl ExecResult {
pub fn new(rows_affected: u64, last_insert_id: Option<i64>) -> Self {
ExecResult {
rows_affected,
last_insert_id,
}
}
}
pub trait Executor: Send + Sync + fmt::Debug {
fn family(&self) -> Family;
fn fetch(&self, stmt: Statement) -> ExecFuture<'_, Result<Vec<Row>, ExecError>>;
fn execute(&self, stmt: Statement) -> ExecFuture<'_, Result<ExecResult, ExecError>>;
}
impl<E: Executor + ?Sized> Executor for &E {
fn family(&self) -> Family {
(**self).family()
}
fn fetch(&self, stmt: Statement) -> ExecFuture<'_, Result<Vec<Row>, ExecError>> {
(**self).fetch(stmt)
}
fn execute(&self, stmt: Statement) -> ExecFuture<'_, Result<ExecResult, ExecError>> {
(**self).execute(stmt)
}
}
impl<E: Executor + ?Sized> Executor for Arc<E> {
fn family(&self) -> Family {
(**self).family()
}
fn fetch(&self, stmt: Statement) -> ExecFuture<'_, Result<Vec<Row>, ExecError>> {
(**self).fetch(stmt)
}
fn execute(&self, stmt: Statement) -> ExecFuture<'_, Result<ExecResult, ExecError>> {
(**self).execute(stmt)
}
}
impl<E: Executor + ?Sized> Executor for Box<E> {
fn family(&self) -> Family {
(**self).family()
}
fn fetch(&self, stmt: Statement) -> ExecFuture<'_, Result<Vec<Row>, ExecError>> {
(**self).fetch(stmt)
}
fn execute(&self, stmt: Statement) -> ExecFuture<'_, Result<ExecResult, ExecError>> {
(**self).execute(stmt)
}
}
pub trait StreamExecutor: Executor {
fn fetch_stream(&self, stmt: Statement) -> ExecFuture<'_, Result<RowStream, ExecError>>;
}
pub struct RowStream {
rx: tokio::sync::mpsc::Receiver<Result<Row, ExecError>>,
}
impl fmt::Debug for RowStream {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RowStream").finish_non_exhaustive()
}
}
impl RowStream {
pub fn new(rx: tokio::sync::mpsc::Receiver<Result<Row, ExecError>>) -> Self {
RowStream { rx }
}
pub async fn next(&mut self) -> Option<Result<Row, ExecError>> {
self.rx.recv().await
}
}