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 {
Unknown,
Null,
Integer,
Real,
Text,
Blob,
}
impl TursoTypeInfo {
pub(crate) fn from_decl_type(declaration: Option<&str>) -> Self {
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);