wires

summary refs log tree commit diff
path: root/wyrd_sqlite/src/from_sql.rs
diff options
context:
space:
mode:
authorwires <wires@noreply.wires.systems>2025-10-24 11:29:46 -0400
committerwires <wires@noreply.wires.systems>2025-10-24 11:29:46 -0400
commit92e4cfc123a1d26265128634850a2b73bac761c2 (patch)
treebdbab6c9ac4a8e981888700e16a7e79b1afb3b27 /wyrd_sqlite/src/from_sql.rs
parentinitial commit (diff)
downloadwyrd-92e4cfc123a1d26265128634850a2b73bac761c2.tar.gz
first draft of sqlite wrapper HEAD main
Diffstat (limited to '')
-rw-r--r--wyrd_sqlite/src/from_sql.rs85
1 files changed, 85 insertions, 0 deletions
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<Self, Self::Error>;
+}
+
+#[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<Self, Self::Error> {
+        if let Value::Int(i) = value {
+            Ok(i)
+        } else {
+            Err(InvalidTypeError.into())
+        }
+    }
+}
+
+impl FromSql for NonZero<i64> {
+    type Error = FromSqlIntError;
+
+    fn try_from_sql(value: Value) -> Result<Self, Self::Error> {
+        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<Self, Self::Error> {
+                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<Self, Self::Error> {
+                let i: NonZero<i64> = 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<T> {
+    type Error = T::Error;
+
+    fn try_from_sql(value: Value<'_>) -> Result<Self, Self::Error> {
+        if let Value::Null = value {
+            Ok(None)
+        } else {
+            FromSql::try_from_sql(value).map(Some)
+        }
+    }
+}