tank-core 0.31.0

Core of Tank: the Rust data layer. This is intended to be used by drivers to implement a backend.
Documentation
use crate::{Driver, Prepared, Query, RawQuery};
use std::{
    any::Any,
    borrow::Cow,
    fmt::{self, Write},
};

/// Dyn compatible version of `Query`
#[derive(Debug)]
pub enum DynQuery {
    Raw(RawQuery),
    Prepared(Box<dyn Prepared>),
}

impl DynQuery {
    pub fn new(value: String) -> Self {
        Self::Raw(RawQuery(value))
    }
    pub fn with_capacity(capacity: usize) -> Self {
        Self::new(String::with_capacity(capacity))
    }
    pub fn clear(&mut self) {
        match self {
            Self::Raw(RawQuery(value)) => value.clear(),
            Self::Prepared(..) => *self = Self::Raw(Default::default()),
        }
    }
    pub fn buffer(&mut self) -> &mut String {
        if !matches!(self, Self::Raw(..)) {
            log::error!("DynQuery::buffer changed the query to raw, deleting the previous content");
            *self = Self::Raw(Default::default())
        }
        let Self::Raw(RawQuery(value)) = self else {
            unreachable!();
        };
        value
    }
    pub fn as_prepared<D: Driver>(&mut self) -> Option<&mut D::Prepared> {
        if let Self::Prepared(prepared) = self {
            return (&mut **prepared as &mut dyn Any).downcast_mut::<D::Prepared>();
        }
        None
    }
    pub fn as_str<'s>(&'s self) -> Cow<'s, str> {
        match self {
            Self::Raw(RawQuery(sql)) => Cow::Borrowed(sql),
            Self::Prepared(v) => Cow::Owned(format!("{:?}", *v)),
        }
    }
    pub fn push_str(&mut self, s: &str) {
        self.buffer().push_str(s);
    }
    pub fn push(&mut self, c: char) {
        self.buffer().push(c);
    }
    pub fn len(&self) -> usize {
        match self {
            Self::Raw(RawQuery(sql)) => sql.len(),
            Self::Prepared(..) => 0,
        }
    }
    pub fn is_empty(&self) -> bool {
        match self {
            Self::Raw(RawQuery(sql)) => sql.is_empty(),
            Self::Prepared(..) => true,
        }
    }

    pub fn into_query<D: Driver>(self, _driver: D) -> Query<D> {
        self.into()
    }
}

impl Default for DynQuery {
    fn default() -> Self {
        Self::Raw(Default::default())
    }
}

impl Write for DynQuery {
    fn write_char(&mut self, c: char) -> fmt::Result {
        self.push(c);
        Ok(())
    }
    fn write_str(&mut self, s: &str) -> fmt::Result {
        self.push_str(s);
        Ok(())
    }
}

impl<D: Driver> From<Query<D>> for DynQuery {
    fn from(value: Query<D>) -> Self {
        match value {
            Query::Raw(v) => Self::Raw(v),
            Query::Prepared(p) => Self::Prepared(Box::new(p)),
        }
    }
}

impl<D: Driver> From<DynQuery> for Query<D> {
    fn from(value: DynQuery) -> Self {
        match value {
            DynQuery::Raw(r) => Self::Raw(r),
            DynQuery::Prepared(p) => match p.as_any().downcast::<D::Prepared>() {
                Ok(p) => Query::Prepared(*p),
                Err(..) => Query::raw(Default::default()),
            },
        }
    }
}

impl From<DynQuery> for String {
    fn from(value: DynQuery) -> Self {
        match value {
            DynQuery::Raw(RawQuery(value)) => value,
            DynQuery::Prepared(value) => format!("{:?}", value),
        }
    }
}