1use drizzle_core::error::DrizzleError;
7
8pub trait FromSQLiteValue: Sized {
19 fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError>;
21
22 fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError>;
24
25 fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError>;
27
28 fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError>;
30
31 fn from_sqlite_null() -> Result<Self, DrizzleError> {
33 Err(DrizzleError::ConversionError(
34 "unexpected NULL value".into(),
35 ))
36 }
37}
38
39pub trait DrizzleRow {
44 fn get_column<T: FromSQLiteValue>(&self, idx: usize) -> Result<T, DrizzleError>;
46
47 fn get_column_by_name<T: FromSQLiteValue>(&self, name: &str) -> Result<T, DrizzleError>;
49}
50
51macro_rules! impl_from_sqlite_value_int {
57 (i64) => {
59 impl FromSQLiteValue for i64 {
60 fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
61 Ok(value)
62 }
63
64 fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
65 value.parse().map_err(|e| {
66 DrizzleError::ConversionError(format!("cannot parse '{}' as i64: {}", value, e).into())
67 })
68 }
69
70 fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
71 Ok(value as i64)
72 }
73
74 fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
75 Err(DrizzleError::ConversionError("cannot convert BLOB to i64".into()))
76 }
77 }
78 };
79 ($($ty:ty),+ $(,)?) => {
81 $(
82 impl FromSQLiteValue for $ty {
83 fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
84 value.try_into().map_err(|e| {
85 DrizzleError::ConversionError(
86 format!("i64 {} out of range for {}: {}", value, stringify!($ty), e).into(),
87 )
88 })
89 }
90
91 fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
92 value.parse().map_err(|e| {
93 DrizzleError::ConversionError(
94 format!("cannot parse '{}' as {}: {}", value, stringify!($ty), e).into()
95 )
96 })
97 }
98
99 fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
100 Ok(value as $ty)
101 }
102
103 fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
104 Err(DrizzleError::ConversionError(
105 concat!("cannot convert BLOB to ", stringify!($ty)).into()
106 ))
107 }
108 }
109 )+
110 };
111}
112
113macro_rules! impl_from_sqlite_value_float {
115 ($($ty:ty),+ $(,)?) => {
116 $(
117 impl FromSQLiteValue for $ty {
118 fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
119 Ok(value as $ty)
120 }
121
122 fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
123 value.parse().map_err(|e| {
124 DrizzleError::ConversionError(
125 format!("cannot parse '{}' as {}: {}", value, stringify!($ty), e).into()
126 )
127 })
128 }
129
130 fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
131 Ok(value as $ty)
132 }
133
134 fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
135 Err(DrizzleError::ConversionError(
136 concat!("cannot convert BLOB to ", stringify!($ty)).into()
137 ))
138 }
139 }
140 )+
141 };
142}
143
144impl_from_sqlite_value_int!(i64);
146impl_from_sqlite_value_int!(i8, i16, i32, isize, u8, u16, u32, u64, usize);
147
148impl_from_sqlite_value_float!(f32, f64);
150
151impl FromSQLiteValue for bool {
152 fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
153 Ok(value != 0)
154 }
155
156 fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
157 match value.to_lowercase().as_str() {
158 "true" | "1" | "yes" | "on" => Ok(true),
159 "false" | "0" | "no" | "off" => Ok(false),
160 _ => Err(DrizzleError::ConversionError(
161 format!("cannot parse '{}' as bool", value).into(),
162 )),
163 }
164 }
165
166 fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
167 Ok(value != 0.0)
168 }
169
170 fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
171 Err(DrizzleError::ConversionError(
172 "cannot convert BLOB to bool".into(),
173 ))
174 }
175}
176
177impl FromSQLiteValue for String {
178 fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
179 Ok(value.to_string())
180 }
181
182 fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
183 Ok(value.to_string())
184 }
185
186 fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
187 Ok(value.to_string())
188 }
189
190 fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
191 String::from_utf8(value.to_vec()).map_err(|e| {
192 DrizzleError::ConversionError(format!("invalid UTF-8 in BLOB: {}", e).into())
193 })
194 }
195}
196
197impl FromSQLiteValue for Vec<u8> {
198 fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
199 Ok(value.to_le_bytes().to_vec())
200 }
201
202 fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
203 Ok(value.as_bytes().to_vec())
204 }
205
206 fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
207 Ok(value.to_le_bytes().to_vec())
208 }
209
210 fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
211 Ok(value.to_vec())
212 }
213}
214
215impl<T: FromSQLiteValue> FromSQLiteValue for Option<T> {
217 fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
218 T::from_sqlite_integer(value).map(Some)
219 }
220
221 fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
222 T::from_sqlite_text(value).map(Some)
223 }
224
225 fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
226 T::from_sqlite_real(value).map(Some)
227 }
228
229 fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
230 T::from_sqlite_blob(value).map(Some)
231 }
232
233 fn from_sqlite_null() -> Result<Self, DrizzleError> {
234 Ok(None)
235 }
236}
237
238#[cfg(feature = "rusqlite")]
243impl DrizzleRow for rusqlite::Row<'_> {
244 fn get_column<T: FromSQLiteValue>(&self, idx: usize) -> Result<T, DrizzleError> {
245 let value_ref = self.get_ref(idx)?;
246 match value_ref {
247 rusqlite::types::ValueRef::Integer(i) => T::from_sqlite_integer(i),
248 rusqlite::types::ValueRef::Text(s) => {
249 let s = std::str::from_utf8(s).map_err(|e| {
250 DrizzleError::ConversionError(format!("invalid UTF-8: {}", e).into())
251 })?;
252 T::from_sqlite_text(s)
253 }
254 rusqlite::types::ValueRef::Real(r) => T::from_sqlite_real(r),
255 rusqlite::types::ValueRef::Blob(b) => T::from_sqlite_blob(b),
256 rusqlite::types::ValueRef::Null => T::from_sqlite_null(),
257 }
258 }
259
260 fn get_column_by_name<T: FromSQLiteValue>(&self, name: &str) -> Result<T, DrizzleError> {
261 let idx = self.as_ref().column_index(name)?;
262 self.get_column(idx)
263 }
264}
265
266#[cfg(feature = "libsql")]
267impl DrizzleRow for libsql::Row {
268 fn get_column<T: FromSQLiteValue>(&self, idx: usize) -> Result<T, DrizzleError> {
269 let value = self.get_value(idx as i32)?;
270 match value {
271 libsql::Value::Integer(i) => T::from_sqlite_integer(i),
272 libsql::Value::Text(ref s) => T::from_sqlite_text(s),
273 libsql::Value::Real(r) => T::from_sqlite_real(r),
274 libsql::Value::Blob(ref b) => T::from_sqlite_blob(b),
275 libsql::Value::Null => T::from_sqlite_null(),
276 }
277 }
278
279 fn get_column_by_name<T: FromSQLiteValue>(&self, _name: &str) -> Result<T, DrizzleError> {
280 Err(DrizzleError::ConversionError(
282 "libsql does not support column access by name in FromRow".into(),
283 ))
284 }
285}
286
287#[cfg(feature = "turso")]
288impl DrizzleRow for turso::Row {
289 fn get_column<T: FromSQLiteValue>(&self, idx: usize) -> Result<T, DrizzleError> {
290 let value = self.get_value(idx)?;
291 if value.is_null() {
292 T::from_sqlite_null()
293 } else if let Some(&i) = value.as_integer() {
294 T::from_sqlite_integer(i)
295 } else if let Some(s) = value.as_text() {
296 T::from_sqlite_text(s)
297 } else if let Some(&r) = value.as_real() {
298 T::from_sqlite_real(r)
299 } else if let Some(b) = value.as_blob() {
300 T::from_sqlite_blob(b)
301 } else {
302 Err(DrizzleError::ConversionError(
303 "unknown SQLite value type".into(),
304 ))
305 }
306 }
307
308 fn get_column_by_name<T: FromSQLiteValue>(&self, _name: &str) -> Result<T, DrizzleError> {
309 Err(DrizzleError::ConversionError(
310 "turso does not support column access by name in FromRow".into(),
311 ))
312 }
313}
314
315#[cfg(feature = "uuid")]
320impl FromSQLiteValue for uuid::Uuid {
321 fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
322 Err(DrizzleError::ConversionError(
323 "cannot convert INTEGER to UUID".into(),
324 ))
325 }
326
327 fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
328 uuid::Uuid::parse_str(value).map_err(|e| {
329 DrizzleError::ConversionError(format!("invalid UUID string '{}': {}", value, e).into())
330 })
331 }
332
333 fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
334 Err(DrizzleError::ConversionError(
335 "cannot convert REAL to UUID".into(),
336 ))
337 }
338
339 fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
340 uuid::Uuid::from_slice(value)
341 .map_err(|e| DrizzleError::ConversionError(format!("invalid UUID bytes: {}", e).into()))
342 }
343}