From 92e4cfc123a1d26265128634850a2b73bac761c2 Mon Sep 17 00:00:00 2001 From: wires Date: Fri, 24 Oct 2025 11:29:46 -0400 Subject: first draft of sqlite wrapper --- wyrd_sqlite/src/from_sql.rs | 85 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 wyrd_sqlite/src/from_sql.rs (limited to 'wyrd_sqlite/src/from_sql.rs') diff --git a/wyrd_sqlite/src/from_sql.rs b/wyrd_sqlite/src/from_sql.rs new file mode 100644 index 0000000..3b149e8 --- /dev/null +++ b/wyrd_sqlite/src/from_sql.rs @@ -0,0 +1,85 @@ +use std::num::{NonZero, TryFromIntError}; + +pub enum Value<'a> { + Int(i64), + Float(f64), + Text(&'a str), + Blob(&'a [u8]), + Null, +} + +// this is an owned trait to get around some problems with blanket implementations +pub trait FromSql: Sized { + type Error: std::error::Error; + + fn try_from_sql(value: Value<'_>) -> Result; +} + +#[derive(Debug, thiserror::Error)] +#[error("invalid type")] +pub struct InvalidTypeError; + +#[derive(Debug, thiserror::Error)] +pub enum FromSqlIntError { + #[error(transparent)] + InvalidType(#[from] InvalidTypeError), + #[error(transparent)] + TryFromInt(#[from] TryFromIntError), +} + +impl FromSql for i64 { + type Error = FromSqlIntError; + + fn try_from_sql(value: Value<'_>) -> Result { + if let Value::Int(i) = value { + Ok(i) + } else { + Err(InvalidTypeError.into()) + } + } +} + +impl FromSql for NonZero { + type Error = FromSqlIntError; + + fn try_from_sql(value: Value) -> Result { + let i: i64 = FromSql::try_from_sql(value)?; + Ok(i.try_into()?) + } +} + +macro_rules! int_impl { + ($($source:ty),+) => {$( + impl FromSql for $source { + type Error = FromSqlIntError; + + fn try_from_sql(value: Value<'_>) -> Result { + let i: i64 = FromSql::try_from_sql(value)?; + Ok(i.try_into()?) + } + } + + impl FromSql for NonZero<$source> { + type Error = FromSqlIntError; + + fn try_from_sql(value: Value<'_>) -> Result { + let i: NonZero = FromSql::try_from_sql(value)?; + Ok(i.try_into()?) + } + } + )*} +} + +int_impl!(i8, i16, i32, u8, u16, u32, u64); + +impl<'a, T: FromSql> FromSql for Option { + type Error = T::Error; + + fn try_from_sql(value: Value<'_>) -> Result { + if let Value::Null = value { + Ok(None) + } else { + FromSql::try_from_sql(value).map(Some) + } + } +} -- cgit 1.4.1