Skip to main content

drizzle_sqlite/traits/
value.rs

1//! Value conversion traits for `SQLite` types
2//!
3//! This module provides the `FromSQLiteValue` trait for converting `SQLite` values
4//! to Rust types, and row capability traits for unified access across drivers.
5
6use crate::prelude::*;
7use crate::values::{OwnedSQLiteValue, SQLiteValue, SQLiteValueRef};
8use drizzle_core::conv::checked_float_to_int;
9use drizzle_core::error::DrizzleError;
10
11/// Trait for custom Rust types that map to a `SQLite` column.
12///
13/// Generated by `#[derive(SQLiteEnum)]`. Implement this trait manually for
14/// custom wrappers that should be usable directly in table schemas.
15///
16/// # Associated Constants
17///
18/// - `SQLType`: The Drizzle SQL type marker used for typed expressions
19/// - `SQL_TYPE`: The `SQLite` column affinity (`"TEXT"`, `"INTEGER"`, `"BLOB"`, etc.)
20///
21/// # Required Methods
22///
23/// - `decode`: Convert a borrowed `SQLite` value read from the database into `Self`
24/// - `encode`: Convert self to a `SQLiteValue` for insertion/updates
25///
26/// The blanket `From<Self> for SQLiteValue` owns the encoded value because
27/// insert/update models may store SQL fragments after the source value is
28/// dropped. Call `encode()` directly when you need an immediate borrowed value.
29/// Override `encode_owned()` when consuming `self` can avoid cloning owned data.
30#[diagnostic::on_unimplemented(
31    message = "`{Self}` cannot be used as a SQLite column type",
32    note = "add #[derive(SQLiteEnum)] for enum types, or use a supported primitive type"
33)]
34pub trait DrizzleSQLiteColumn: Sized {
35    /// Drizzle SQL type marker for this column.
36    ///
37    /// Use one of the built-in SQLite markers, such as `Text`, `Integer`,
38    /// `Blob`, `Real`, `Numeric`, or `Any`.
39    type SQLType: drizzle_core::types::DataType;
40
41    /// `SQLite` column affinity: `"TEXT"` or `"INTEGER"`
42    const SQL_TYPE: &'static str;
43
44    /// Decode a borrowed `SQLite` value read from the database into `Self`.
45    ///
46    /// Implementations should reject unsupported storage classes with
47    /// [`DrizzleError::ConversionError`].
48    ///
49    /// # Errors
50    ///
51    /// Returns [`DrizzleError::ConversionError`] if `value` cannot be decoded
52    /// as this custom column type.
53    fn decode(value: SQLiteValueRef<'_>) -> Result<Self, DrizzleError>;
54
55    /// Convert self to a `SQLiteValue` for insertion/updates.
56    fn encode(&self) -> SQLiteValue<'_>;
57
58    /// Convert self to an owned `SQLite` value for stored bind parameters.
59    ///
60    /// The default implementation owns the borrowed result of [`encode`](Self::encode).
61    /// Override this for wrappers that can move an internal string or byte buffer
62    /// directly into the SQL parameter.
63    fn encode_owned(self) -> OwnedSQLiteValue {
64        self.encode().into_owned()
65    }
66}
67
68impl<'a, T> From<T> for SQLiteValue<'a>
69where
70    T: DrizzleSQLiteColumn,
71{
72    fn from(value: T) -> Self {
73        value.encode_owned().into()
74    }
75}
76
77/// Trait for types that can be converted from `SQLite` values.
78///
79/// `SQLite` has 5 storage classes: NULL, INTEGER, REAL, TEXT, BLOB.
80/// This trait provides conversion methods for each type.
81///
82/// # Implementation Notes
83///
84/// - Implement the methods that make sense for your type
85/// - Return `Err` for unsupported conversions
86/// - `SQLiteEnum` derive automatically implements this trait
87pub trait FromSQLiteValue: Sized {
88    /// Convert from a 64-bit integer value.
89    ///
90    /// # Errors
91    ///
92    /// Returns [`DrizzleError::ConversionError`] if `value` cannot be represented as `Self`.
93    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError>;
94
95    /// Convert from a text/string value.
96    ///
97    /// # Errors
98    ///
99    /// Returns [`DrizzleError::ConversionError`] if `value` cannot be parsed or represented as `Self`.
100    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError>;
101
102    /// Convert from a real/float value.
103    ///
104    /// # Errors
105    ///
106    /// Returns [`DrizzleError::ConversionError`] if `value` cannot be represented as `Self`.
107    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError>;
108
109    /// Convert from a blob/binary value.
110    ///
111    /// # Errors
112    ///
113    /// Returns [`DrizzleError::ConversionError`] if `value` cannot be interpreted as `Self`.
114    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError>;
115
116    /// Convert from a borrowed SQLite storage value.
117    ///
118    /// # Errors
119    ///
120    /// Returns [`DrizzleError::ConversionError`] if `value` cannot be
121    /// represented as `Self`.
122    fn from_sqlite_ref(value: SQLiteValueRef<'_>) -> Result<Self, DrizzleError> {
123        match value {
124            SQLiteValueRef::Integer(value) => Self::from_sqlite_integer(value),
125            SQLiteValueRef::Text(value) => Self::from_sqlite_text(value),
126            SQLiteValueRef::Real(value) => Self::from_sqlite_real(value),
127            SQLiteValueRef::Blob(value) => Self::from_sqlite_blob(value),
128            SQLiteValueRef::Null => Self::from_sqlite_null(),
129        }
130    }
131
132    /// Convert from a NULL value (default returns error).
133    ///
134    /// # Errors
135    ///
136    /// The default implementation always returns [`DrizzleError::ConversionError`];
137    /// override for nullable-aware types (e.g. [`Option`]).
138    fn from_sqlite_null() -> Result<Self, DrizzleError> {
139        Err(DrizzleError::ConversionError(
140            "unexpected NULL value".into(),
141        ))
142    }
143
144    /// Helper function to convert from rusqlite's `ValueRef` using `FromSQLiteValue`.
145    ///
146    /// # Errors
147    ///
148    /// Returns [`DrizzleError::ConversionError`] if the underlying conversion fails,
149    /// including UTF-8 decoding failures for TEXT values.
150    #[cfg(feature = "rusqlite")]
151    fn from_value_ref(value: ::rusqlite::types::ValueRef<'_>) -> Result<Self, DrizzleError> {
152        let value = SQLiteValueRef::try_from_rusqlite_value_ref(value)?;
153        Self::from_sqlite_ref(value)
154    }
155}
156
157impl<T> FromSQLiteValue for T
158where
159    T: DrizzleSQLiteColumn,
160{
161    fn from_sqlite_ref(value: SQLiteValueRef<'_>) -> Result<Self, DrizzleError> {
162        T::decode(value)
163    }
164
165    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
166        T::decode(SQLiteValueRef::Integer(value))
167    }
168
169    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
170        T::decode(SQLiteValueRef::Text(value))
171    }
172
173    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
174        T::decode(SQLiteValueRef::Real(value))
175    }
176
177    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
178        T::decode(SQLiteValueRef::Blob(value))
179    }
180
181    fn from_sqlite_null() -> Result<Self, DrizzleError> {
182        T::decode(SQLiteValueRef::Null)
183    }
184}
185
186/// Row capability for index-based extraction.
187pub trait DrizzleRowByIndex {
188    /// Get a column value by index.
189    ///
190    /// # Errors
191    ///
192    /// Returns [`DrizzleError`] if the index is out of range or the column value
193    /// cannot be converted to `T`.
194    fn get_column<T: FromSQLiteValue>(&self, idx: usize) -> Result<T, DrizzleError>;
195}
196
197/// Optional row capability for name-based extraction.
198pub trait DrizzleRowByName: DrizzleRowByIndex {
199    /// Get a column value by name.
200    ///
201    /// # Errors
202    ///
203    /// Returns [`DrizzleError`] if the name does not resolve to a column or the
204    /// column value cannot be converted to `T`.
205    fn get_column_by_name<T: FromSQLiteValue>(&self, name: &str) -> Result<T, DrizzleError>;
206}
207
208// =============================================================================
209// Primitive implementations
210// =============================================================================
211
212/// Macro to implement `FromSQLiteValue` for integer types (handles narrowing conversion from i64)
213macro_rules! impl_from_sqlite_value_int {
214    // Special case for i64 - no conversion needed
215    (i64) => {
216        impl FromSQLiteValue for i64 {
217            fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
218                Ok(value)
219            }
220
221            fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
222                value.parse().map_err(|e| {
223                    DrizzleError::ConversionError(format!("cannot parse '{}' as i64: {}", value, e).into())
224                })
225            }
226
227            fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
228                checked_float_to_int(value, "i64")
229            }
230
231            fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
232                Err(DrizzleError::ConversionError("cannot convert BLOB to i64".into()))
233            }
234        }
235    };
236    // General case for other integer types - uses try_into for narrowing
237    ($($ty:ty),+ $(,)?) => {
238        $(
239            impl FromSQLiteValue for $ty {
240                fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
241                    value.try_into().map_err(|e| {
242                        DrizzleError::ConversionError(
243                            format!("i64 {} out of range for {}: {}", value, stringify!($ty), e).into(),
244                        )
245                    })
246                }
247
248                fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
249                    value.parse().map_err(|e| {
250                        DrizzleError::ConversionError(
251                            format!("cannot parse '{}' as {}: {}", value, stringify!($ty), e).into()
252                        )
253                    })
254                }
255
256                fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
257                    checked_float_to_int(value, stringify!($ty))
258                }
259
260                fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
261                    Err(DrizzleError::ConversionError(
262                        concat!("cannot convert BLOB to ", stringify!($ty)).into()
263                    ))
264                }
265            }
266        )+
267    };
268}
269
270/// IEEE 754 `f64` representation of an `i64` built from two exact halves via
271/// [`From`], matching the semantics of `i as f64` without an `as`-cast.
272#[inline]
273fn i64_to_f64(i: i64) -> f64 {
274    let high = i32::try_from(i >> 32).expect("sign-extended high word fits in i32");
275    let low = u32::try_from(i & 0xFFFF_FFFF).expect("masked low word fits in u32");
276    f64::from(high) * 4_294_967_296.0_f64 + f64::from(low)
277}
278
279// Integer types
280impl_from_sqlite_value_int!(i64);
281impl_from_sqlite_value_int!(i8, i16, i32, isize, u8, u16, u32, u64, usize);
282
283// f64 — `i64` widening via split-halves is exact in the mantissa range and
284// matches direct `as` cast beyond it; no cast is needed for f64→f64.
285impl FromSQLiteValue for f64 {
286    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
287        Ok(i64_to_f64(value))
288    }
289
290    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
291        value.parse().map_err(|e| {
292            DrizzleError::ConversionError(format!("cannot parse '{value}' as f64: {e}").into())
293        })
294    }
295
296    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
297        Ok(value)
298    }
299
300    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
301        Err(DrizzleError::ConversionError(
302            "cannot convert BLOB to f64".into(),
303        ))
304    }
305}
306
307fn narrow_to_f32(value: f64) -> Result<f32, DrizzleError> {
308    // Round-trip through a decimal string so IEEE 754 round-to-nearest is
309    // applied explicitly (and clippy doesn't flag the conversion as a lossy
310    // numeric cast).
311    format!("{value}").parse::<f32>().map_err(|e| {
312        DrizzleError::ConversionError(format!("cannot convert REAL {value} to f32: {e}").into())
313    })
314}
315
316// f32 — narrowing from both `i64` and `f64` is intentionally lossy; SQLite
317// round-trips the value through `f64` storage so we defer to the standard
318// IEEE 754 narrowing conversion. These casts are the only correct semantics.
319impl FromSQLiteValue for f32 {
320    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
321        // Go via f64 (exact) then narrow to f32.
322        narrow_to_f32(i64_to_f64(value))
323    }
324
325    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
326        value.parse().map_err(|e| {
327            DrizzleError::ConversionError(format!("cannot parse '{value}' as f32: {e}").into())
328        })
329    }
330
331    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
332        narrow_to_f32(value)
333    }
334
335    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
336        Err(DrizzleError::ConversionError(
337            "cannot convert BLOB to f32".into(),
338        ))
339    }
340}
341
342impl FromSQLiteValue for bool {
343    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
344        Ok(value != 0)
345    }
346
347    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
348        match value.to_lowercase().as_str() {
349            "true" | "1" | "yes" | "on" => Ok(true),
350            "false" | "0" | "no" | "off" => Ok(false),
351            _ => Err(DrizzleError::ConversionError(
352                format!("cannot parse '{value}' as bool").into(),
353            )),
354        }
355    }
356
357    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
358        Ok(value != 0.0)
359    }
360
361    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
362        Err(DrizzleError::ConversionError(
363            "cannot convert BLOB to bool".into(),
364        ))
365    }
366}
367
368impl FromSQLiteValue for String {
369    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
370        Ok(value.to_string())
371    }
372
373    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
374        Ok(value.to_string())
375    }
376
377    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
378        Ok(value.to_string())
379    }
380
381    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
382        Self::from_utf8(value.to_vec()).map_err(|e| {
383            DrizzleError::ConversionError(format!("invalid UTF-8 in BLOB: {e}").into())
384        })
385    }
386}
387
388impl FromSQLiteValue for compact_str::CompactString {
389    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
390        Ok(Self::new(value.to_string()))
391    }
392
393    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
394        Ok(Self::new(value))
395    }
396
397    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
398        Ok(Self::new(value.to_string()))
399    }
400
401    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
402        let s = String::from_utf8(value.to_vec()).map_err(|e| {
403            DrizzleError::ConversionError(format!("invalid UTF-8 in BLOB: {e}").into())
404        })?;
405        Ok(Self::new(s))
406    }
407}
408
409impl FromSQLiteValue for Box<String> {
410    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
411        String::from_sqlite_integer(value).map(Self::new)
412    }
413
414    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
415        String::from_sqlite_text(value).map(Self::new)
416    }
417
418    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
419        String::from_sqlite_real(value).map(Self::new)
420    }
421
422    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
423        String::from_sqlite_blob(value).map(Self::new)
424    }
425}
426
427impl FromSQLiteValue for Rc<String> {
428    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
429        String::from_sqlite_integer(value).map(Self::new)
430    }
431
432    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
433        String::from_sqlite_text(value).map(Self::new)
434    }
435
436    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
437        String::from_sqlite_real(value).map(Self::new)
438    }
439
440    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
441        String::from_sqlite_blob(value).map(Self::new)
442    }
443}
444
445impl FromSQLiteValue for Arc<String> {
446    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
447        String::from_sqlite_integer(value).map(Self::new)
448    }
449
450    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
451        String::from_sqlite_text(value).map(Self::new)
452    }
453
454    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
455        String::from_sqlite_real(value).map(Self::new)
456    }
457
458    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
459        String::from_sqlite_blob(value).map(Self::new)
460    }
461}
462
463impl FromSQLiteValue for Box<str> {
464    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
465        String::from_sqlite_integer(value).map(String::into_boxed_str)
466    }
467
468    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
469        String::from_sqlite_text(value).map(String::into_boxed_str)
470    }
471
472    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
473        String::from_sqlite_real(value).map(String::into_boxed_str)
474    }
475
476    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
477        String::from_sqlite_blob(value).map(String::into_boxed_str)
478    }
479}
480
481impl FromSQLiteValue for Rc<str> {
482    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
483        String::from_sqlite_integer(value).map(Self::from)
484    }
485
486    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
487        String::from_sqlite_text(value).map(Self::from)
488    }
489
490    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
491        String::from_sqlite_real(value).map(Self::from)
492    }
493
494    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
495        String::from_sqlite_blob(value).map(Self::from)
496    }
497}
498
499impl FromSQLiteValue for Arc<str> {
500    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
501        String::from_sqlite_integer(value).map(Self::from)
502    }
503
504    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
505        String::from_sqlite_text(value).map(Self::from)
506    }
507
508    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
509        String::from_sqlite_real(value).map(Self::from)
510    }
511
512    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
513        String::from_sqlite_blob(value).map(Self::from)
514    }
515}
516
517impl FromSQLiteValue for Vec<u8> {
518    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
519        Ok(value.to_le_bytes().to_vec())
520    }
521
522    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
523        Ok(value.as_bytes().to_vec())
524    }
525
526    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
527        Ok(value.to_le_bytes().to_vec())
528    }
529
530    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
531        Ok(value.to_vec())
532    }
533}
534
535#[cfg(feature = "bytes")]
536impl FromSQLiteValue for bytes::Bytes {
537    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
538        Vec::<u8>::from_sqlite_integer(value).map(Self::from)
539    }
540
541    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
542        Vec::<u8>::from_sqlite_text(value).map(Self::from)
543    }
544
545    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
546        Vec::<u8>::from_sqlite_real(value).map(Self::from)
547    }
548
549    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
550        Ok(Self::copy_from_slice(value))
551    }
552}
553
554#[cfg(feature = "bytes")]
555impl FromSQLiteValue for bytes::BytesMut {
556    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
557        Vec::<u8>::from_sqlite_integer(value).map(|v| Self::from(v.as_slice()))
558    }
559
560    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
561        Vec::<u8>::from_sqlite_text(value).map(|v| Self::from(v.as_slice()))
562    }
563
564    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
565        Vec::<u8>::from_sqlite_real(value).map(|v| Self::from(v.as_slice()))
566    }
567
568    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
569        Ok(Self::from(value))
570    }
571}
572
573#[cfg(feature = "smallvec")]
574impl<const N: usize> FromSQLiteValue for smallvec::SmallVec<[u8; N]> {
575    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
576        Err(DrizzleError::ConversionError(
577            "cannot convert INTEGER to SmallVec<u8>, use BLOB".into(),
578        ))
579    }
580
581    fn from_sqlite_text(_value: &str) -> Result<Self, DrizzleError> {
582        Err(DrizzleError::ConversionError(
583            "cannot convert TEXT to SmallVec<u8>, use BLOB".into(),
584        ))
585    }
586
587    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
588        Err(DrizzleError::ConversionError(
589            "cannot convert REAL to SmallVec<u8>, use BLOB".into(),
590        ))
591    }
592
593    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
594        let mut out = Self::new();
595        out.extend_from_slice(value);
596        Ok(out)
597    }
598}
599
600impl FromSQLiteValue for Box<Vec<u8>> {
601    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
602        Vec::<u8>::from_sqlite_integer(value).map(Self::new)
603    }
604
605    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
606        Vec::<u8>::from_sqlite_text(value).map(Self::new)
607    }
608
609    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
610        Vec::<u8>::from_sqlite_real(value).map(Self::new)
611    }
612
613    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
614        Vec::<u8>::from_sqlite_blob(value).map(Self::new)
615    }
616}
617
618impl FromSQLiteValue for Rc<Vec<u8>> {
619    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
620        Vec::<u8>::from_sqlite_integer(value).map(Self::new)
621    }
622
623    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
624        Vec::<u8>::from_sqlite_text(value).map(Self::new)
625    }
626
627    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
628        Vec::<u8>::from_sqlite_real(value).map(Self::new)
629    }
630
631    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
632        Vec::<u8>::from_sqlite_blob(value).map(Self::new)
633    }
634}
635
636impl FromSQLiteValue for Arc<Vec<u8>> {
637    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
638        Vec::<u8>::from_sqlite_integer(value).map(Self::new)
639    }
640
641    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
642        Vec::<u8>::from_sqlite_text(value).map(Self::new)
643    }
644
645    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
646        Vec::<u8>::from_sqlite_real(value).map(Self::new)
647    }
648
649    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
650        Vec::<u8>::from_sqlite_blob(value).map(Self::new)
651    }
652}
653
654// Option<T> implementation - handles NULL values
655impl<T: FromSQLiteValue> FromSQLiteValue for Option<T> {
656    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
657        T::from_sqlite_integer(value).map(Some)
658    }
659
660    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
661        T::from_sqlite_text(value).map(Some)
662    }
663
664    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
665        T::from_sqlite_real(value).map(Some)
666    }
667
668    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
669        T::from_sqlite_blob(value).map(Some)
670    }
671
672    fn from_sqlite_null() -> Result<Self, DrizzleError> {
673        Ok(None)
674    }
675}
676
677// =============================================================================
678// Driver-specific DrizzleRow implementations
679// =============================================================================
680
681#[cfg(feature = "rusqlite")]
682impl DrizzleRowByIndex for rusqlite::Row<'_> {
683    fn get_column<T: FromSQLiteValue>(&self, idx: usize) -> Result<T, DrizzleError> {
684        let value_ref = self.get_ref(idx)?;
685        match value_ref {
686            rusqlite::types::ValueRef::Integer(i) => T::from_sqlite_integer(i),
687            rusqlite::types::ValueRef::Text(s) => {
688                let s = core::str::from_utf8(s).map_err(|e| {
689                    DrizzleError::ConversionError(format!("invalid UTF-8: {e}").into())
690                })?;
691                T::from_sqlite_text(s)
692            }
693            rusqlite::types::ValueRef::Real(r) => T::from_sqlite_real(r),
694            rusqlite::types::ValueRef::Blob(b) => T::from_sqlite_blob(b),
695            rusqlite::types::ValueRef::Null => T::from_sqlite_null(),
696        }
697    }
698}
699
700#[cfg(feature = "rusqlite")]
701impl DrizzleRowByName for rusqlite::Row<'_> {
702    fn get_column_by_name<T: FromSQLiteValue>(&self, name: &str) -> Result<T, DrizzleError> {
703        let idx = self.as_ref().column_index(name)?;
704        DrizzleRowByIndex::get_column(self, idx)
705    }
706}
707
708#[cfg(feature = "libsql")]
709impl DrizzleRowByIndex for libsql::Row {
710    fn get_column<T: FromSQLiteValue>(&self, idx: usize) -> Result<T, DrizzleError> {
711        let idx_i32 = i32::try_from(idx).map_err(|e| {
712            DrizzleError::ConversionError(format!("column index {idx} out of range: {e}").into())
713        })?;
714        let value = self.get_value(idx_i32)?;
715        match value {
716            libsql::Value::Integer(i) => T::from_sqlite_integer(i),
717            libsql::Value::Text(ref s) => T::from_sqlite_text(s),
718            libsql::Value::Real(r) => T::from_sqlite_real(r),
719            libsql::Value::Blob(ref b) => T::from_sqlite_blob(b),
720            libsql::Value::Null => T::from_sqlite_null(),
721        }
722    }
723}
724
725#[cfg(feature = "libsql")]
726impl DrizzleRowByName for libsql::Row {
727    fn get_column_by_name<T: FromSQLiteValue>(&self, name: &str) -> Result<T, DrizzleError> {
728        let idx = (0..self.column_count())
729            .find(|&i| self.column_name(i) == Some(name))
730            .ok_or_else(|| {
731                DrizzleError::ConversionError(format!("column '{name}' not found").into())
732            })?;
733
734        let idx_usize = usize::try_from(idx).map_err(|e| {
735            DrizzleError::ConversionError(format!("column index {idx} negative: {e}").into())
736        })?;
737        DrizzleRowByIndex::get_column(self, idx_usize)
738    }
739}
740
741#[cfg(feature = "turso")]
742impl DrizzleRowByIndex for turso::Row {
743    fn get_column<T: FromSQLiteValue>(&self, idx: usize) -> Result<T, DrizzleError> {
744        let value = self.get_value(idx)?;
745        if value.is_null() {
746            T::from_sqlite_null()
747        } else if let Some(&i) = value.as_integer() {
748            T::from_sqlite_integer(i)
749        } else if let Some(s) = value.as_text() {
750            T::from_sqlite_text(s)
751        } else if let Some(&r) = value.as_real() {
752            T::from_sqlite_real(r)
753        } else if let Some(b) = value.as_blob() {
754            T::from_sqlite_blob(b)
755        } else {
756            Err(DrizzleError::ConversionError(
757                "unknown SQLite value type".into(),
758            ))
759        }
760    }
761}
762
763// =============================================================================
764// UUID support (when feature enabled)
765// =============================================================================
766
767#[cfg(feature = "uuid")]
768impl FromSQLiteValue for uuid::Uuid {
769    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
770        Err(DrizzleError::ConversionError(
771            "cannot convert INTEGER to UUID".into(),
772        ))
773    }
774
775    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
776        Self::parse_str(value).map_err(|e| {
777            DrizzleError::ConversionError(format!("invalid UUID string '{value}': {e}").into())
778        })
779    }
780
781    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
782        Err(DrizzleError::ConversionError(
783            "cannot convert REAL to UUID".into(),
784        ))
785    }
786
787    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
788        Self::from_slice(value)
789            .map_err(|e| DrizzleError::ConversionError(format!("invalid UUID bytes: {e}").into()))
790    }
791}
792
793// =============================================================================
794// Chrono date/time types (parse from ISO-8601 text)
795// =============================================================================
796
797#[cfg(feature = "chrono")]
798impl FromSQLiteValue for chrono::NaiveDate {
799    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
800        Err(DrizzleError::ConversionError(
801            "cannot convert INTEGER to NaiveDate".into(),
802        ))
803    }
804
805    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
806        value.parse().map_err(|e| {
807            DrizzleError::ConversionError(
808                format!("cannot parse '{value}' as NaiveDate: {e}").into(),
809            )
810        })
811    }
812
813    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
814        Err(DrizzleError::ConversionError(
815            "cannot convert REAL to NaiveDate".into(),
816        ))
817    }
818
819    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
820        Err(DrizzleError::ConversionError(
821            "cannot convert BLOB to NaiveDate".into(),
822        ))
823    }
824}
825
826#[cfg(feature = "chrono")]
827impl FromSQLiteValue for chrono::NaiveTime {
828    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
829        Err(DrizzleError::ConversionError(
830            "cannot convert INTEGER to NaiveTime".into(),
831        ))
832    }
833
834    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
835        value.parse().map_err(|e| {
836            DrizzleError::ConversionError(
837                format!("cannot parse '{value}' as NaiveTime: {e}").into(),
838            )
839        })
840    }
841
842    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
843        Err(DrizzleError::ConversionError(
844            "cannot convert REAL to NaiveTime".into(),
845        ))
846    }
847
848    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
849        Err(DrizzleError::ConversionError(
850            "cannot convert BLOB to NaiveTime".into(),
851        ))
852    }
853}
854
855#[cfg(feature = "chrono")]
856impl FromSQLiteValue for chrono::NaiveDateTime {
857    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
858        Err(DrizzleError::ConversionError(
859            "cannot convert INTEGER to NaiveDateTime".into(),
860        ))
861    }
862
863    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
864        value.parse().map_err(|e| {
865            DrizzleError::ConversionError(
866                format!("cannot parse '{value}' as NaiveDateTime: {e}").into(),
867            )
868        })
869    }
870
871    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
872        Err(DrizzleError::ConversionError(
873            "cannot convert REAL to NaiveDateTime".into(),
874        ))
875    }
876
877    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
878        Err(DrizzleError::ConversionError(
879            "cannot convert BLOB to NaiveDateTime".into(),
880        ))
881    }
882}
883
884#[cfg(feature = "chrono")]
885impl FromSQLiteValue for chrono::DateTime<chrono::FixedOffset> {
886    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
887        Err(DrizzleError::ConversionError(
888            "cannot convert INTEGER to DateTime<FixedOffset>".into(),
889        ))
890    }
891
892    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
893        Self::parse_from_rfc3339(value).map_err(|e| {
894            DrizzleError::ConversionError(
895                format!("cannot parse '{value}' as DateTime<FixedOffset>: {e}").into(),
896            )
897        })
898    }
899
900    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
901        Err(DrizzleError::ConversionError(
902            "cannot convert REAL to DateTime<FixedOffset>".into(),
903        ))
904    }
905
906    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
907        Err(DrizzleError::ConversionError(
908            "cannot convert BLOB to DateTime<FixedOffset>".into(),
909        ))
910    }
911}
912
913#[cfg(feature = "chrono")]
914impl FromSQLiteValue for chrono::DateTime<chrono::Utc> {
915    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
916        Err(DrizzleError::ConversionError(
917            "cannot convert INTEGER to DateTime<Utc>".into(),
918        ))
919    }
920
921    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
922        value.parse().map_err(|e| {
923            DrizzleError::ConversionError(
924                format!("cannot parse '{value}' as DateTime<Utc>: {e}").into(),
925            )
926        })
927    }
928
929    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
930        Err(DrizzleError::ConversionError(
931            "cannot convert REAL to DateTime<Utc>".into(),
932        ))
933    }
934
935    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
936        Err(DrizzleError::ConversionError(
937            "cannot convert BLOB to DateTime<Utc>".into(),
938        ))
939    }
940}
941
942// =============================================================================
943// Time crate date/time types (parse from ISO-8601 text)
944// =============================================================================
945
946#[cfg(feature = "time")]
947impl FromSQLiteValue for time::Date {
948    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
949        Err(DrizzleError::ConversionError(
950            "cannot convert INTEGER to time::Date".into(),
951        ))
952    }
953
954    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
955        Self::parse(value, &time::format_description::well_known::Iso8601::DATE).map_err(|e| {
956            DrizzleError::ConversionError(
957                format!("cannot parse '{value}' as time::Date: {e}").into(),
958            )
959        })
960    }
961
962    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
963        Err(DrizzleError::ConversionError(
964            "cannot convert REAL to time::Date".into(),
965        ))
966    }
967
968    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
969        Err(DrizzleError::ConversionError(
970            "cannot convert BLOB to time::Date".into(),
971        ))
972    }
973}
974
975#[cfg(feature = "time")]
976impl FromSQLiteValue for time::Time {
977    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
978        Err(DrizzleError::ConversionError(
979            "cannot convert INTEGER to time::Time".into(),
980        ))
981    }
982
983    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
984        Self::parse(value, &time::format_description::well_known::Iso8601::TIME).map_err(|e| {
985            DrizzleError::ConversionError(
986                format!("cannot parse '{value}' as time::Time: {e}").into(),
987            )
988        })
989    }
990
991    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
992        Err(DrizzleError::ConversionError(
993            "cannot convert REAL to time::Time".into(),
994        ))
995    }
996
997    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
998        Err(DrizzleError::ConversionError(
999            "cannot convert BLOB to time::Time".into(),
1000        ))
1001    }
1002}
1003
1004#[cfg(feature = "time")]
1005impl FromSQLiteValue for time::PrimitiveDateTime {
1006    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1007        Err(DrizzleError::ConversionError(
1008            "cannot convert INTEGER to time::PrimitiveDateTime".into(),
1009        ))
1010    }
1011
1012    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1013        Self::parse(
1014            value,
1015            &time::format_description::well_known::Iso8601::DATE_TIME,
1016        )
1017        .map_err(|e| {
1018            DrizzleError::ConversionError(
1019                format!("cannot parse '{value}' as time::PrimitiveDateTime: {e}").into(),
1020            )
1021        })
1022    }
1023
1024    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1025        Err(DrizzleError::ConversionError(
1026            "cannot convert REAL to time::PrimitiveDateTime".into(),
1027        ))
1028    }
1029
1030    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1031        Err(DrizzleError::ConversionError(
1032            "cannot convert BLOB to time::PrimitiveDateTime".into(),
1033        ))
1034    }
1035}
1036
1037#[cfg(feature = "time")]
1038impl FromSQLiteValue for time::OffsetDateTime {
1039    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1040        Err(DrizzleError::ConversionError(
1041            "cannot convert INTEGER to time::OffsetDateTime".into(),
1042        ))
1043    }
1044
1045    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1046        Self::parse(value, &time::format_description::well_known::Rfc3339).map_err(|e| {
1047            DrizzleError::ConversionError(
1048                format!("cannot parse '{value}' as time::OffsetDateTime: {e}").into(),
1049            )
1050        })
1051    }
1052
1053    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1054        Err(DrizzleError::ConversionError(
1055            "cannot convert REAL to time::OffsetDateTime".into(),
1056        ))
1057    }
1058
1059    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1060        Err(DrizzleError::ConversionError(
1061            "cannot convert BLOB to time::OffsetDateTime".into(),
1062        ))
1063    }
1064}
1065
1066// =============================================================================
1067// Decimal (parse from text)
1068// =============================================================================
1069
1070#[cfg(feature = "rust-decimal")]
1071impl FromSQLiteValue for rust_decimal::Decimal {
1072    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
1073        Ok(Self::from(value))
1074    }
1075
1076    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1077        value.parse().map_err(|e| {
1078            DrizzleError::ConversionError(format!("cannot parse '{value}' as Decimal: {e}").into())
1079        })
1080    }
1081
1082    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
1083        Self::try_from(value).map_err(|e| {
1084            DrizzleError::ConversionError(
1085                format!("cannot convert REAL {value} to Decimal: {e}").into(),
1086            )
1087        })
1088    }
1089
1090    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1091        Err(DrizzleError::ConversionError(
1092            "cannot convert BLOB to Decimal".into(),
1093        ))
1094    }
1095}
1096
1097// =============================================================================
1098// Duration types
1099// =============================================================================
1100
1101#[cfg(feature = "chrono")]
1102impl FromSQLiteValue for chrono::Duration {
1103    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
1104        Ok(Self::seconds(value))
1105    }
1106
1107    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1108        // Parse seconds from the text representation
1109        let secs: i64 = value.trim_end_matches('s').parse().map_err(|e| {
1110            DrizzleError::ConversionError(
1111                format!("cannot parse '{value}' as chrono::Duration: {e}").into(),
1112            )
1113        })?;
1114        Ok(Self::seconds(secs))
1115    }
1116
1117    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
1118        let millis: i64 = format!("{:.0}", value * 1000.0).parse().map_err(|e| {
1119            DrizzleError::ConversionError(
1120                format!("cannot convert REAL {value} to chrono::Duration: {e}").into(),
1121            )
1122        })?;
1123        Ok(Self::milliseconds(millis))
1124    }
1125
1126    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1127        Err(DrizzleError::ConversionError(
1128            "cannot convert BLOB to chrono::Duration".into(),
1129        ))
1130    }
1131}
1132
1133#[cfg(feature = "time")]
1134impl FromSQLiteValue for time::Duration {
1135    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
1136        Ok(Self::seconds(value))
1137    }
1138
1139    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1140        // Parse seconds from the "Ns" text representation
1141        let secs: i64 = value.trim_end_matches('s').parse().map_err(|e| {
1142            DrizzleError::ConversionError(
1143                format!("cannot parse '{value}' as time::Duration: {e}").into(),
1144            )
1145        })?;
1146        Ok(Self::seconds(secs))
1147    }
1148
1149    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
1150        Ok(Self::seconds_f64(value))
1151    }
1152
1153    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1154        Err(DrizzleError::ConversionError(
1155            "cannot convert BLOB to time::Duration".into(),
1156        ))
1157    }
1158}
1159
1160// =============================================================================
1161// JSON support (serde_json::Value)
1162// =============================================================================
1163
1164#[cfg(feature = "serde")]
1165impl FromSQLiteValue for serde_json::Value {
1166    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
1167        Ok(Self::Number(value.into()))
1168    }
1169
1170    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1171        serde_json::from_str(value).map_err(|e| {
1172            DrizzleError::ConversionError(format!("cannot parse '{value}' as JSON: {e}").into())
1173        })
1174    }
1175
1176    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
1177        serde_json::Number::from_f64(value)
1178            .map(serde_json::Value::Number)
1179            .ok_or_else(|| {
1180                DrizzleError::ConversionError(
1181                    format!("cannot convert non-finite REAL {value} to JSON").into(),
1182                )
1183            })
1184    }
1185
1186    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
1187        serde_json::from_slice(value).map_err(|e| {
1188            DrizzleError::ConversionError(format!("cannot parse BLOB as JSON: {e}").into())
1189        })
1190    }
1191}
1192
1193// =============================================================================
1194// ArrayVec/ArrayString support
1195// =============================================================================
1196
1197#[cfg(feature = "arrayvec")]
1198impl<const N: usize> FromSQLiteValue for arrayvec::ArrayString<N> {
1199    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
1200        let s = value.to_string();
1201        Self::from(&s).map_err(|_| {
1202            DrizzleError::ConversionError(
1203                format!(
1204                    "String length {} exceeds ArrayString capacity {}",
1205                    s.len(),
1206                    N
1207                )
1208                .into(),
1209            )
1210        })
1211    }
1212
1213    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1214        Self::from(value).map_err(|_| {
1215            DrizzleError::ConversionError(
1216                format!(
1217                    "Text length {} exceeds ArrayString capacity {}",
1218                    value.len(),
1219                    N
1220                )
1221                .into(),
1222            )
1223        })
1224    }
1225
1226    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
1227        let s = value.to_string();
1228        Self::from(&s).map_err(|_| {
1229            DrizzleError::ConversionError(
1230                format!(
1231                    "String length {} exceeds ArrayString capacity {}",
1232                    s.len(),
1233                    N
1234                )
1235                .into(),
1236            )
1237        })
1238    }
1239
1240    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
1241        let s = String::from_utf8(value.to_vec())
1242            .map_err(|e| DrizzleError::ConversionError(format!("invalid UTF-8: {e}").into()))?;
1243        Self::from(&s).map_err(|_| {
1244            DrizzleError::ConversionError(
1245                format!(
1246                    "String length {} exceeds ArrayString capacity {}",
1247                    s.len(),
1248                    N
1249                )
1250                .into(),
1251            )
1252        })
1253    }
1254}
1255
1256#[cfg(feature = "arrayvec")]
1257impl<const N: usize> FromSQLiteValue for arrayvec::ArrayVec<u8, N> {
1258    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1259        Err(DrizzleError::ConversionError(
1260            "cannot convert INTEGER to ArrayVec<u8>, use BLOB".into(),
1261        ))
1262    }
1263
1264    fn from_sqlite_text(_value: &str) -> Result<Self, DrizzleError> {
1265        Err(DrizzleError::ConversionError(
1266            "cannot convert TEXT to ArrayVec<u8>, use BLOB".into(),
1267        ))
1268    }
1269
1270    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1271        Err(DrizzleError::ConversionError(
1272            "cannot convert REAL to ArrayVec<u8>, use BLOB".into(),
1273        ))
1274    }
1275
1276    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
1277        Self::try_from(value).map_err(|_| {
1278            DrizzleError::ConversionError(
1279                format!(
1280                    "Blob length {} exceeds ArrayVec capacity {}",
1281                    value.len(),
1282                    N
1283                )
1284                .into(),
1285            )
1286        })
1287    }
1288}