use duckdb::ToSql;
use duckdb::types::ToSqlOutput;
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum Param {
Null,
Bool(bool),
Int(i64),
UInt(u64),
HugeInt(i128),
UHugeInt(u128),
Float(f64),
Text(String),
Blob(Vec<u8>),
}
impl ToSql for Param {
fn to_sql(&self) -> duckdb::Result<ToSqlOutput<'_>> {
use duckdb::types::{Value, ValueRef};
Ok(match self {
Self::Null => ToSqlOutput::Owned(Value::Null),
Self::Bool(v) => ToSqlOutput::Owned(Value::Boolean(*v)),
Self::Int(v) => ToSqlOutput::Owned(Value::BigInt(*v)),
Self::UInt(v) => ToSqlOutput::Owned(Value::UBigInt(*v)),
Self::HugeInt(v) => ToSqlOutput::Owned(Value::HugeInt(*v)),
Self::UHugeInt(v) => ToSqlOutput::Owned(Value::UHugeInt(*v)),
Self::Float(v) => ToSqlOutput::Owned(Value::Double(*v)),
Self::Text(v) => ToSqlOutput::Borrowed(ValueRef::Text(v.as_bytes())),
Self::Blob(v) => ToSqlOutput::Borrowed(ValueRef::Blob(v)),
})
}
}
macro_rules! from_scalar {
($variant:ident($target:ty): $($source:ty),+) => {
$(
impl From<$source> for Param {
fn from(value: $source) -> Self {
Self::$variant(<$target>::from(value))
}
}
)+
};
}
from_scalar!(Bool(bool): bool);
from_scalar!(Int(i64): i8, i16, i32, i64);
from_scalar!(UInt(u64): u8, u16, u32, u64);
from_scalar!(HugeInt(i128): i128);
from_scalar!(UHugeInt(u128): u128);
impl From<isize> for Param {
fn from(value: isize) -> Self {
Self::Int(i64::try_from(value).unwrap_or(i64::MAX))
}
}
impl From<usize> for Param {
fn from(value: usize) -> Self {
Self::UInt(u64::try_from(value).unwrap_or(u64::MAX))
}
}
from_scalar!(Float(f64): f32, f64);
from_scalar!(Text(String): String, &str, &String);
from_scalar!(Blob(Vec<u8>): Vec<u8>, &[u8]);
impl<T: Into<Self>> From<Option<T>> for Param {
fn from(value: Option<T>) -> Self {
value.map_or(Self::Null, Into::into)
}
}
#[cfg(test)]
mod tests;