sqlx-turso-driver 0.0.1

An asynchronous SQLx driver for embedded Turso databases
use crate::{Turso, TursoValueRef};
use sqlx_core::{
    decode::Decode,
    encode::{Encode, IsNull},
    error::BoxDynError,
    type_info::TypeInfo,
    types::Type,
};
use std::fmt;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TursoTypeInfo {
    /// No storage class is available from the prepared column's declaration.
    Unknown,
    Null,
    Integer,
    Real,
    Text,
    Blob,
}
impl TursoTypeInfo {
    pub(crate) fn from_decl_type(declaration: Option<&str>) -> Self {
        // Preserve only known storage-class declarations. Do not infer expression
        // types or pretend arbitrary SQLite affinities are runtime storage classes.
        match declaration.map(str::to_ascii_uppercase).as_deref() {
            Some("INTEGER") => Self::Integer,
            Some("REAL") => Self::Real,
            Some("TEXT") => Self::Text,
            Some("BLOB") => Self::Blob,
            _ => Self::Unknown,
        }
    }
}
impl TypeInfo for TursoTypeInfo {
    fn is_null(&self) -> bool {
        *self == Self::Null
    }
    fn name(&self) -> &str {
        match self {
            Self::Unknown => "UNKNOWN",
            Self::Null => "NULL",
            Self::Integer => "INTEGER",
            Self::Real => "REAL",
            Self::Text => "TEXT",
            Self::Blob => "BLOB",
        }
    }
}
impl fmt::Display for TursoTypeInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.name())
    }
}

macro_rules! impl_type {
    ($type:ty, $info:ident) => {
        impl Type<Turso> for $type {
            fn type_info() -> TursoTypeInfo {
                TursoTypeInfo::$info
            }
        }
    };
}

impl_type!(i64, Integer);
impl Encode<'_, Turso> for i64 {
    fn encode_by_ref(&self, buffer: &mut Vec<turso::Value>) -> Result<IsNull, BoxDynError> {
        buffer.push(turso::Value::Integer(*self));
        Ok(IsNull::No)
    }
}
impl Decode<'_, Turso> for i64 {
    fn decode(value: TursoValueRef<'_>) -> Result<Self, BoxDynError> {
        match value.0.0 {
            turso::Value::Integer(value) => Ok(value),
            turso::Value::Null => Err(sqlx_core::error::UnexpectedNullError.into()),
            _ => Err("expected a Turso INTEGER".into()),
        }
    }
}
macro_rules! integer {
    ($($type:ty),+ $(,)?) => {$ (
        impl_type!($type, Integer);
        impl Encode<'_, Turso> for $type {
            fn encode_by_ref(&self, buffer: &mut Vec<turso::Value>) -> Result<IsNull, BoxDynError> {
                let value = i64::try_from(*self)?;
                <i64 as Encode<Turso>>::encode(value, buffer)
            }
        }
        impl Decode<'_, Turso> for $type {
            fn decode(value: TursoValueRef<'_>) -> Result<Self, BoxDynError> {
                Ok(Self::try_from(<i64 as Decode<Turso>>::decode(value)?)?)
            }
        }
    )+};
}
integer!(i8, i16, i32, u8, u16, u32, u64);

impl_type!(bool, Integer);
impl Encode<'_, Turso> for bool {
    fn encode_by_ref(&self, buffer: &mut Vec<turso::Value>) -> Result<IsNull, BoxDynError> {
        <i64 as Encode<Turso>>::encode(i64::from(*self), buffer)
    }
}
impl Decode<'_, Turso> for bool {
    fn decode(value: TursoValueRef<'_>) -> Result<Self, BoxDynError> {
        Ok(<i64 as Decode<Turso>>::decode(value)? != 0)
    }
}

impl_type!(f64, Real);
impl Encode<'_, Turso> for f64 {
    fn encode_by_ref(&self, buffer: &mut Vec<turso::Value>) -> Result<IsNull, BoxDynError> {
        buffer.push(turso::Value::Real(*self));
        Ok(IsNull::No)
    }
}
impl Decode<'_, Turso> for f64 {
    fn decode(value: TursoValueRef<'_>) -> Result<Self, BoxDynError> {
        match value.0.0 {
            turso::Value::Real(value) => Ok(value),
            turso::Value::Null => Err(sqlx_core::error::UnexpectedNullError.into()),
            _ => Err("expected a Turso REAL".into()),
        }
    }
}
impl_type!(f32, Real);
impl Encode<'_, Turso> for f32 {
    fn encode_by_ref(&self, buffer: &mut Vec<turso::Value>) -> Result<IsNull, BoxDynError> {
        <f64 as Encode<Turso>>::encode(f64::from(*self), buffer)
    }
}
impl Decode<'_, Turso> for f32 {
    fn decode(value: TursoValueRef<'_>) -> Result<Self, BoxDynError> {
        Ok(<f64 as Decode<Turso>>::decode(value)? as f32)
    }
}

impl_type!(str, Text);
impl_type!(String, Text);
impl Encode<'_, Turso> for &str {
    fn encode_by_ref(&self, buffer: &mut Vec<turso::Value>) -> Result<IsNull, BoxDynError> {
        buffer.push(turso::Value::Text((*self).to_owned()));
        Ok(IsNull::No)
    }
}
impl Encode<'_, Turso> for String {
    fn encode(self, buffer: &mut Vec<turso::Value>) -> Result<IsNull, BoxDynError> {
        buffer.push(turso::Value::Text(self));
        Ok(IsNull::No)
    }
    fn encode_by_ref(&self, buffer: &mut Vec<turso::Value>) -> Result<IsNull, BoxDynError> {
        <&str as Encode<Turso>>::encode(self.as_str(), buffer)
    }
}
impl<'r> Decode<'r, Turso> for &'r str {
    fn decode(value: TursoValueRef<'r>) -> Result<Self, BoxDynError> {
        match &value.0.0 {
            turso::Value::Text(value) => Ok(value),
            turso::Value::Null => Err(sqlx_core::error::UnexpectedNullError.into()),
            _ => Err("expected a Turso TEXT".into()),
        }
    }
}
impl Decode<'_, Turso> for String {
    fn decode(value: TursoValueRef<'_>) -> Result<Self, BoxDynError> {
        Ok(<&str as Decode<Turso>>::decode(value)?.to_owned())
    }
}

impl_type!([u8], Blob);
impl_type!(Vec<u8>, Blob);
impl Encode<'_, Turso> for &[u8] {
    fn encode_by_ref(&self, buffer: &mut Vec<turso::Value>) -> Result<IsNull, BoxDynError> {
        buffer.push(turso::Value::Blob(self.to_vec()));
        Ok(IsNull::No)
    }
}
impl Encode<'_, Turso> for Vec<u8> {
    fn encode(self, buffer: &mut Vec<turso::Value>) -> Result<IsNull, BoxDynError> {
        buffer.push(turso::Value::Blob(self));
        Ok(IsNull::No)
    }
    fn encode_by_ref(&self, buffer: &mut Vec<turso::Value>) -> Result<IsNull, BoxDynError> {
        <&[u8] as Encode<Turso>>::encode(self.as_slice(), buffer)
    }
}
impl<'r> Decode<'r, Turso> for &'r [u8] {
    fn decode(value: TursoValueRef<'r>) -> Result<Self, BoxDynError> {
        match &value.0.0 {
            turso::Value::Blob(value) => Ok(value),
            turso::Value::Null => Err(sqlx_core::error::UnexpectedNullError.into()),
            _ => Err("expected a Turso BLOB".into()),
        }
    }
}
impl Decode<'_, Turso> for Vec<u8> {
    fn decode(value: TursoValueRef<'_>) -> Result<Self, BoxDynError> {
        Ok(<&[u8] as Decode<Turso>>::decode(value)?.to_vec())
    }
}
sqlx_core::impl_encode_for_option!(Turso);