Skip to main content

drizzle_sqlite/traits/
value.rs

1//! Traits for decoding `SQLite` values into Rust types and for custom
2//! column types.
3//!
4//! [`FromSQLiteValue`] decodes one cell. [`DrizzleRowByIndex`] reads cells
5//! from a rusqlite, libsql or turso row by position, and
6//! [`DrizzleRowByName`] reads rusqlite and libsql rows by column name.
7//! Implement [`DrizzleSQLiteColumn`] to use your own type as a
8//! column in a `#[SQLiteTable]`.
9
10use crate::prelude::*;
11use crate::values::{OwnedSQLiteValue, SQLiteValue, SQLiteValueRef};
12use drizzle_core::conv::checked_float_to_int;
13use drizzle_core::error::DrizzleError;
14
15/// The `SQLite` type affinity of a SQL type marker such as
16/// [`Integer`](crate::types::Integer) or [`Text`](crate::types::Text).
17pub trait SQLiteAffinity: drizzle_core::types::DataType {
18    /// The affinity as written in DDL (`"INTEGER"`, `"TEXT"`, ...).
19    const SQL_TYPE: &'static str;
20}
21
22macro_rules! impl_sqlite_affinity {
23    ($($marker:ty => $sql_type:literal),+ $(,)?) => {
24        $(
25            impl SQLiteAffinity for $marker {
26                const SQL_TYPE: &'static str = $sql_type;
27            }
28        )+
29    };
30}
31
32impl_sqlite_affinity! {
33    crate::types::Integer => "INTEGER",
34    crate::types::Text => "TEXT",
35    crate::types::Blob => "BLOB",
36    crate::types::Real => "REAL",
37    crate::types::Numeric => "NUMERIC",
38    crate::types::Any => "ANY",
39}
40
41/// A Rust type that can be stored in a `SQLite` column.
42///
43/// `#[derive(SQLiteEnum)]` implements this for enums. Implement it by hand to
44/// use your own type as a field of a `#[SQLiteTable]`: [`SQLType`] picks the
45/// column's affinity, [`decode`] reads a cell, and [`encode`] writes one.
46/// Implementing it also gives the type [`FromSQLiteValue`] and
47/// `From<T> for SQLiteValue`.
48///
49/// `From<T> for SQLiteValue` goes through [`encode_owned`], because insert
50/// and update models keep their values after the source is dropped. Override
51/// `encode_owned` when the type can hand over its buffer without copying.
52///
53/// [`SQLType`]: Self::SQLType
54/// [`decode`]: Self::decode
55/// [`encode`]: Self::encode
56/// [`encode_owned`]: Self::encode_owned
57///
58/// # Examples
59///
60/// A `u32` stored as four big-endian bytes:
61///
62/// ```
63/// use drizzle_core::error::DrizzleError;
64/// use drizzle_sqlite::traits::{DrizzleSQLiteColumn, FromSQLiteValue};
65/// use drizzle_sqlite::types::Blob;
66/// use drizzle_sqlite::values::{SQLiteValue, SQLiteValueRef};
67/// use std::borrow::Cow;
68///
69/// struct U32Be(u32);
70///
71/// impl DrizzleSQLiteColumn for U32Be {
72///     type SQLType = Blob;
73///
74///     fn decode(value: SQLiteValueRef<'_>) -> Result<Self, DrizzleError> {
75///         let SQLiteValueRef::Blob(bytes) = value else {
76///             return Err(DrizzleError::ConversionError("expected a BLOB".into()));
77///         };
78///         let bytes: [u8; 4] = bytes
79///             .try_into()
80///             .map_err(|_| DrizzleError::ConversionError("expected 4 bytes".into()))?;
81///         Ok(Self(u32::from_be_bytes(bytes)))
82///     }
83///
84///     fn encode(&self) -> SQLiteValue<'_> {
85///         SQLiteValue::Blob(Cow::Owned(self.0.to_be_bytes().to_vec()))
86///     }
87/// }
88///
89/// let value = SQLiteValue::from(U32Be(7));
90/// assert_eq!(value, SQLiteValue::Blob(Cow::Borrowed(&[0, 0, 0, 7][..])));
91/// assert_eq!(U32Be::from_sqlite_blob(&[0, 0, 1, 0]).unwrap().0, 256);
92/// assert!(U32Be::from_sqlite_text("7").is_err());
93/// ```
94#[diagnostic::on_unimplemented(
95    message = "`{Self}` cannot be used as a SQLite column type",
96    note = "add #[derive(SQLiteEnum)] for enum types, or use a supported primitive type"
97)]
98pub trait DrizzleSQLiteColumn: Sized {
99    /// The SQL type marker of the column: one of the markers in
100    /// [`crate::types`] (`Integer`, `Text`, `Blob`, `Real`, `Numeric`, `Any`).
101    ///
102    /// It sets the column's affinity in DDL and which expressions the column
103    /// can be used in.
104    type SQLType: SQLiteAffinity;
105
106    /// The affinity as written in DDL. Defaults to the affinity of
107    /// [`SQLType`](Self::SQLType).
108    ///
109    /// Kept for source compatibility. Schema generation reads the affinity
110    /// from `SQLType`, so overriding this constant does not change the
111    /// column type.
112    const SQL_TYPE: &'static str = <Self::SQLType as SQLiteAffinity>::SQL_TYPE;
113
114    /// Decodes a cell read from the database.
115    ///
116    /// Reject storage classes the type does not accept (including `NULL`)
117    /// with [`DrizzleError::ConversionError`].
118    ///
119    /// # Errors
120    ///
121    /// Returns [`DrizzleError::ConversionError`] if `value` cannot be decoded
122    /// as this custom column type.
123    fn decode(value: SQLiteValueRef<'_>) -> Result<Self, DrizzleError>;
124
125    /// Encodes the value as a bind parameter, borrowing from `self` where
126    /// possible.
127    fn encode(&self) -> SQLiteValue<'_>;
128
129    /// Encodes the value as an owned bind parameter.
130    ///
131    /// The default calls [`encode`](Self::encode) and copies the result.
132    /// Override it when the type can move its string or byte buffer into the
133    /// value instead.
134    fn encode_owned(self) -> OwnedSQLiteValue {
135        self.encode().into_owned()
136    }
137
138    /// Decodes a cell from the JSON produced by the relational query API
139    /// (`query` feature).
140    ///
141    /// The default unwraps the storage-class tag with
142    /// [`decode_projected_sqlite_value`] and calls [`decode`](Self::decode).
143    ///
144    /// # Errors
145    ///
146    /// Returns [`DrizzleError::ConversionError`] if the JSON is not a valid
147    /// tagged value or [`decode`](Self::decode) rejects it.
148    #[cfg(feature = "query")]
149    fn decode_json(value: &serde_json::Value) -> Result<Self, DrizzleError> {
150        let value = decode_projected_sqlite_value(value)?;
151        let value = value.as_value();
152        Self::decode(value.as_ref())
153    }
154}
155
156/// Decodes a tagged cell from the JSON produced by the relational query API.
157///
158/// Custom column types are projected as
159/// `{"$drizzle_storage": <typeof(column)>, "$drizzle_value": <value>}`, with
160/// BLOBs as hex strings. Keeping the storage class means a TEXT cell in a
161/// BLOB column decodes as TEXT, rather than being read as hex bytes. JSON
162/// `null` decodes as [`OwnedSQLiteValue::Null`].
163///
164/// # Errors
165///
166/// Returns [`DrizzleError::ConversionError`] if the object or its tags are
167/// missing, the storage class is unknown, the value does not match its
168/// storage class, or the BLOB hex is invalid.
169///
170/// # Examples
171///
172/// ```
173/// use drizzle_sqlite::traits::decode_projected_sqlite_value;
174/// use drizzle_sqlite::values::OwnedSQLiteValue;
175///
176/// let cell = serde_json::json!({"$drizzle_storage": "blob", "$drizzle_value": "00ff"});
177/// let value = decode_projected_sqlite_value(&cell).unwrap();
178/// assert_eq!(value, OwnedSQLiteValue::Blob(vec![0x00, 0xff].into_boxed_slice()));
179/// assert!(decode_projected_sqlite_value(&serde_json::json!("00ff")).is_err());
180/// ```
181#[cfg(feature = "query")]
182pub fn decode_projected_sqlite_value(
183    value: &serde_json::Value,
184) -> Result<OwnedSQLiteValue, DrizzleError> {
185    if value.is_null() {
186        return Ok(OwnedSQLiteValue::Null);
187    }
188
189    let object = value.as_object().ok_or_else(|| {
190        DrizzleError::ConversionError("SQLite query value is missing its storage tag".into())
191    })?;
192    let storage = object
193        .get("$drizzle_storage")
194        .and_then(serde_json::Value::as_str)
195        .ok_or_else(|| {
196            DrizzleError::ConversionError("SQLite query value has no valid $drizzle_storage".into())
197        })?;
198    let value = object.get("$drizzle_value").ok_or_else(|| {
199        DrizzleError::ConversionError("SQLite query value has no $drizzle_value".into())
200    })?;
201
202    match storage {
203        "integer" => value
204            .as_i64()
205            .map(OwnedSQLiteValue::Integer)
206            .ok_or_else(|| {
207                DrizzleError::ConversionError(
208                    "SQLite INTEGER query value is not a JSON integer".into(),
209                )
210            }),
211        "real" => value.as_f64().map(OwnedSQLiteValue::Real).ok_or_else(|| {
212            DrizzleError::ConversionError("SQLite REAL query value is not a JSON number".into())
213        }),
214        "text" => value
215            .as_str()
216            .map(|value| OwnedSQLiteValue::Text(value.to_owned()))
217            .ok_or_else(|| {
218                DrizzleError::ConversionError("SQLite TEXT query value is not a JSON string".into())
219            }),
220        "blob" => value
221            .as_str()
222            .ok_or_else(|| {
223                DrizzleError::ConversionError("SQLite BLOB query value is not a hex string".into())
224            })
225            .and_then(decode_projected_blob)
226            .map(|value| OwnedSQLiteValue::Blob(value.into_boxed_slice())),
227        other => Err(DrizzleError::ConversionError(
228            format!("unknown SQLite query storage class `{other}`").into(),
229        )),
230    }
231}
232
233#[cfg(feature = "query")]
234fn decode_projected_blob(value: &str) -> Result<Vec<u8>, DrizzleError> {
235    let (chunks, remainder) = value.as_bytes().as_chunks::<2>();
236    let mut bytes = Vec::with_capacity(value.len() / 2);
237    for chunk in chunks {
238        let high = decode_hex_nibble(chunk[0])?;
239        let low = decode_hex_nibble(chunk[1])?;
240        bytes.push((high << 4) | low);
241    }
242    if !remainder.is_empty() {
243        return Err(DrizzleError::ConversionError(
244            "hex-encoded SQLite BLOB has odd length".into(),
245        ));
246    }
247    Ok(bytes)
248}
249
250#[cfg(feature = "query")]
251fn decode_hex_nibble(value: u8) -> Result<u8, DrizzleError> {
252    match value {
253        b'0'..=b'9' => Ok(value - b'0'),
254        b'a'..=b'f' => Ok(value - b'a' + 10),
255        b'A'..=b'F' => Ok(value - b'A' + 10),
256        _ => Err(DrizzleError::ConversionError(
257            "SQLite BLOB query value contains a non-hex byte".into(),
258        )),
259    }
260}
261
262impl<'a, T> From<T> for SQLiteValue<'a>
263where
264    T: DrizzleSQLiteColumn,
265{
266    fn from(value: T) -> Self {
267        value.encode_owned().into()
268    }
269}
270
271/// Decodes a Rust value from a `SQLite` value.
272///
273/// `SQLite` has five storage classes (NULL, INTEGER, REAL, TEXT, BLOB), and
274/// this trait has one method per class. Return
275/// [`DrizzleError::ConversionError`] from the ones your type does not
276/// accept. `NULL` is rejected unless you override
277/// [`from_sqlite_null`](Self::from_sqlite_null), as `Option<T>` does.
278///
279/// Every [`DrizzleSQLiteColumn`] type (including `#[derive(SQLiteEnum)]`
280/// enums) gets this trait through a blanket impl, so implement
281/// `DrizzleSQLiteColumn` instead when the type is also used as a column.
282pub trait FromSQLiteValue: Sized {
283    /// Decodes an INTEGER.
284    ///
285    /// # Errors
286    ///
287    /// Returns [`DrizzleError::ConversionError`] if `value` cannot be represented as `Self`.
288    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError>;
289
290    /// Decodes a TEXT value.
291    ///
292    /// # Errors
293    ///
294    /// Returns [`DrizzleError::ConversionError`] if `value` cannot be parsed or represented as `Self`.
295    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError>;
296
297    /// Decodes a REAL value.
298    ///
299    /// # Errors
300    ///
301    /// Returns [`DrizzleError::ConversionError`] if `value` cannot be represented as `Self`.
302    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError>;
303
304    /// Decodes a BLOB.
305    ///
306    /// # Errors
307    ///
308    /// Returns [`DrizzleError::ConversionError`] if `value` cannot be interpreted as `Self`.
309    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError>;
310
311    /// Decodes any borrowed value by calling the method for its storage
312    /// class.
313    ///
314    /// # Errors
315    ///
316    /// Returns [`DrizzleError::ConversionError`] if `value` cannot be
317    /// represented as `Self`.
318    fn from_sqlite_ref(value: SQLiteValueRef<'_>) -> Result<Self, DrizzleError> {
319        match value {
320            SQLiteValueRef::Integer(value) => Self::from_sqlite_integer(value),
321            SQLiteValueRef::Text(value) => Self::from_sqlite_text(value),
322            SQLiteValueRef::Real(value) => Self::from_sqlite_real(value),
323            SQLiteValueRef::Blob(value) => Self::from_sqlite_blob(value),
324            SQLiteValueRef::Null => Self::from_sqlite_null(),
325        }
326    }
327
328    /// Decodes `NULL`.
329    ///
330    /// # Errors
331    ///
332    /// The default implementation always returns [`DrizzleError::ConversionError`];
333    /// override for nullable-aware types (e.g. [`Option`]).
334    fn from_sqlite_null() -> Result<Self, DrizzleError> {
335        Err(DrizzleError::ConversionError(
336            "unexpected NULL value".into(),
337        ))
338    }
339
340    /// Decodes a rusqlite `ValueRef`.
341    ///
342    /// # Errors
343    ///
344    /// Returns [`DrizzleError::ConversionError`] if the underlying conversion fails,
345    /// including UTF-8 decoding failures for TEXT values.
346    #[cfg(feature = "rusqlite")]
347    fn from_value_ref(value: ::rusqlite::types::ValueRef<'_>) -> Result<Self, DrizzleError> {
348        let value = SQLiteValueRef::try_from_rusqlite_value_ref(value)?;
349        Self::from_sqlite_ref(value)
350    }
351}
352
353impl<T> FromSQLiteValue for T
354where
355    T: DrizzleSQLiteColumn,
356{
357    fn from_sqlite_ref(value: SQLiteValueRef<'_>) -> Result<Self, DrizzleError> {
358        T::decode(value)
359    }
360
361    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
362        T::decode(SQLiteValueRef::Integer(value))
363    }
364
365    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
366        T::decode(SQLiteValueRef::Text(value))
367    }
368
369    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
370        T::decode(SQLiteValueRef::Real(value))
371    }
372
373    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
374        T::decode(SQLiteValueRef::Blob(value))
375    }
376
377    fn from_sqlite_null() -> Result<Self, DrizzleError> {
378        T::decode(SQLiteValueRef::Null)
379    }
380}
381
382/// A driver row whose columns can be read by position.
383///
384/// Implemented for `rusqlite::Row`, `libsql::Row` and `turso::Row` when the
385/// matching feature is enabled.
386pub trait DrizzleRowByIndex {
387    /// Reads and decodes the column at `idx` (0-based).
388    ///
389    /// # Errors
390    ///
391    /// Returns [`DrizzleError`] if the index is out of range or the column value
392    /// cannot be converted to `T`.
393    fn get_column<T: FromSQLiteValue>(&self, idx: usize) -> Result<T, DrizzleError>;
394}
395
396/// A driver row whose columns can also be read by name.
397///
398/// Implemented for `rusqlite::Row` and `libsql::Row` when the matching
399/// feature is enabled.
400pub trait DrizzleRowByName: DrizzleRowByIndex {
401    /// Reads and decodes the column called `name`.
402    ///
403    /// # Errors
404    ///
405    /// Returns [`DrizzleError`] if the name does not resolve to a column or the
406    /// column value cannot be converted to `T`.
407    fn get_column_by_name<T: FromSQLiteValue>(&self, name: &str) -> Result<T, DrizzleError>;
408}
409
410// =============================================================================
411// Primitive implementations
412// =============================================================================
413
414/// Macro to implement `FromSQLiteValue` for integer types (handles narrowing conversion from i64)
415macro_rules! impl_from_sqlite_value_int {
416    // Special case for i64 - no conversion needed
417    (i64) => {
418        impl FromSQLiteValue for i64 {
419            fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
420                Ok(value)
421            }
422
423            fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
424                value.parse().map_err(|e| {
425                    DrizzleError::ConversionError(format!("cannot parse '{}' as i64: {}", value, e).into())
426                })
427            }
428
429            fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
430                checked_float_to_int(value, "i64")
431            }
432
433            fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
434                Err(DrizzleError::ConversionError("cannot convert BLOB to i64".into()))
435            }
436        }
437    };
438    // General case for other integer types - uses try_into for narrowing
439    ($($ty:ty),+ $(,)?) => {
440        $(
441            impl FromSQLiteValue for $ty {
442                fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
443                    value.try_into().map_err(|e| {
444                        DrizzleError::ConversionError(
445                            format!("i64 {} out of range for {}: {}", value, stringify!($ty), e).into(),
446                        )
447                    })
448                }
449
450                fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
451                    value.parse().map_err(|e| {
452                        DrizzleError::ConversionError(
453                            format!("cannot parse '{}' as {}: {}", value, stringify!($ty), e).into()
454                        )
455                    })
456                }
457
458                fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
459                    checked_float_to_int(value, stringify!($ty))
460                }
461
462                fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
463                    Err(DrizzleError::ConversionError(
464                        concat!("cannot convert BLOB to ", stringify!($ty)).into()
465                    ))
466                }
467            }
468        )+
469    };
470}
471
472/// IEEE 754 `f64` representation of an `i64` built from two exact halves via
473/// [`From`], matching the semantics of `i as f64` without an `as`-cast.
474#[inline]
475fn i64_to_f64(i: i64) -> f64 {
476    let high = i32::try_from(i >> 32).expect("sign-extended high word fits in i32");
477    let low = u32::try_from(i & 0xFFFF_FFFF).expect("masked low word fits in u32");
478    f64::from(high) * 4_294_967_296.0_f64 + f64::from(low)
479}
480
481// Integer types
482impl_from_sqlite_value_int!(i64);
483impl_from_sqlite_value_int!(i8, i16, i32, isize, u8, u16, u32, u64, usize);
484
485// f64 — `i64` widening via split-halves is exact in the mantissa range and
486// matches direct `as` cast beyond it; no cast is needed for f64→f64.
487impl FromSQLiteValue for f64 {
488    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
489        Ok(i64_to_f64(value))
490    }
491
492    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
493        value.parse().map_err(|e| {
494            DrizzleError::ConversionError(format!("cannot parse '{value}' as f64: {e}").into())
495        })
496    }
497
498    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
499        Ok(value)
500    }
501
502    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
503        Err(DrizzleError::ConversionError(
504            "cannot convert BLOB to f64".into(),
505        ))
506    }
507}
508
509fn narrow_to_f32(value: f64) -> Result<f32, DrizzleError> {
510    // Round-trip through a decimal string so IEEE 754 round-to-nearest is
511    // applied explicitly (and clippy doesn't flag the conversion as a lossy
512    // numeric cast).
513    format!("{value}").parse::<f32>().map_err(|e| {
514        DrizzleError::ConversionError(format!("cannot convert REAL {value} to f32: {e}").into())
515    })
516}
517
518// f32 — narrowing from both `i64` and `f64` is intentionally lossy; SQLite
519// round-trips the value through `f64` storage so we defer to the standard
520// IEEE 754 narrowing conversion. These casts are the only correct semantics.
521impl FromSQLiteValue for f32 {
522    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
523        // Go via f64 (exact) then narrow to f32.
524        narrow_to_f32(i64_to_f64(value))
525    }
526
527    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
528        value.parse().map_err(|e| {
529            DrizzleError::ConversionError(format!("cannot parse '{value}' as f32: {e}").into())
530        })
531    }
532
533    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
534        narrow_to_f32(value)
535    }
536
537    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
538        Err(DrizzleError::ConversionError(
539            "cannot convert BLOB to f32".into(),
540        ))
541    }
542}
543
544impl FromSQLiteValue for bool {
545    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
546        Ok(value != 0)
547    }
548
549    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
550        match value.to_lowercase().as_str() {
551            "true" | "1" | "yes" | "on" => Ok(true),
552            "false" | "0" | "no" | "off" => Ok(false),
553            _ => Err(DrizzleError::ConversionError(
554                format!("cannot parse '{value}' as bool").into(),
555            )),
556        }
557    }
558
559    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
560        Ok(value != 0.0)
561    }
562
563    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
564        Err(DrizzleError::ConversionError(
565            "cannot convert BLOB to bool".into(),
566        ))
567    }
568}
569
570impl FromSQLiteValue for String {
571    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
572        Ok(value.to_string())
573    }
574
575    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
576        Ok(value.to_string())
577    }
578
579    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
580        Ok(value.to_string())
581    }
582
583    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
584        Self::from_utf8(value.to_vec()).map_err(|e| {
585            DrizzleError::ConversionError(format!("invalid UTF-8 in BLOB: {e}").into())
586        })
587    }
588}
589
590impl FromSQLiteValue for compact_str::CompactString {
591    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
592        Ok(Self::new(value.to_string()))
593    }
594
595    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
596        Ok(Self::new(value))
597    }
598
599    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
600        Ok(Self::new(value.to_string()))
601    }
602
603    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
604        let s = String::from_utf8(value.to_vec()).map_err(|e| {
605            DrizzleError::ConversionError(format!("invalid UTF-8 in BLOB: {e}").into())
606        })?;
607        Ok(Self::new(s))
608    }
609}
610
611impl FromSQLiteValue for Box<String> {
612    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
613        String::from_sqlite_integer(value).map(Self::new)
614    }
615
616    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
617        String::from_sqlite_text(value).map(Self::new)
618    }
619
620    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
621        String::from_sqlite_real(value).map(Self::new)
622    }
623
624    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
625        String::from_sqlite_blob(value).map(Self::new)
626    }
627}
628
629impl FromSQLiteValue for Rc<String> {
630    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
631        String::from_sqlite_integer(value).map(Self::new)
632    }
633
634    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
635        String::from_sqlite_text(value).map(Self::new)
636    }
637
638    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
639        String::from_sqlite_real(value).map(Self::new)
640    }
641
642    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
643        String::from_sqlite_blob(value).map(Self::new)
644    }
645}
646
647impl FromSQLiteValue for Arc<String> {
648    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
649        String::from_sqlite_integer(value).map(Self::new)
650    }
651
652    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
653        String::from_sqlite_text(value).map(Self::new)
654    }
655
656    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
657        String::from_sqlite_real(value).map(Self::new)
658    }
659
660    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
661        String::from_sqlite_blob(value).map(Self::new)
662    }
663}
664
665impl FromSQLiteValue for Box<str> {
666    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
667        String::from_sqlite_integer(value).map(String::into_boxed_str)
668    }
669
670    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
671        String::from_sqlite_text(value).map(String::into_boxed_str)
672    }
673
674    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
675        String::from_sqlite_real(value).map(String::into_boxed_str)
676    }
677
678    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
679        String::from_sqlite_blob(value).map(String::into_boxed_str)
680    }
681}
682
683impl FromSQLiteValue for Rc<str> {
684    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
685        String::from_sqlite_integer(value).map(Self::from)
686    }
687
688    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
689        String::from_sqlite_text(value).map(Self::from)
690    }
691
692    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
693        String::from_sqlite_real(value).map(Self::from)
694    }
695
696    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
697        String::from_sqlite_blob(value).map(Self::from)
698    }
699}
700
701impl FromSQLiteValue for Arc<str> {
702    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
703        String::from_sqlite_integer(value).map(Self::from)
704    }
705
706    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
707        String::from_sqlite_text(value).map(Self::from)
708    }
709
710    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
711        String::from_sqlite_real(value).map(Self::from)
712    }
713
714    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
715        String::from_sqlite_blob(value).map(Self::from)
716    }
717}
718
719impl FromSQLiteValue for Vec<u8> {
720    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
721        Ok(value.to_le_bytes().to_vec())
722    }
723
724    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
725        Ok(value.as_bytes().to_vec())
726    }
727
728    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
729        Ok(value.to_le_bytes().to_vec())
730    }
731
732    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
733        Ok(value.to_vec())
734    }
735}
736
737#[cfg(feature = "bytes")]
738impl FromSQLiteValue for bytes::Bytes {
739    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
740        Vec::<u8>::from_sqlite_integer(value).map(Self::from)
741    }
742
743    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
744        Vec::<u8>::from_sqlite_text(value).map(Self::from)
745    }
746
747    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
748        Vec::<u8>::from_sqlite_real(value).map(Self::from)
749    }
750
751    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
752        Ok(Self::copy_from_slice(value))
753    }
754}
755
756#[cfg(feature = "bytes")]
757impl FromSQLiteValue for bytes::BytesMut {
758    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
759        Vec::<u8>::from_sqlite_integer(value).map(|v| Self::from(v.as_slice()))
760    }
761
762    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
763        Vec::<u8>::from_sqlite_text(value).map(|v| Self::from(v.as_slice()))
764    }
765
766    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
767        Vec::<u8>::from_sqlite_real(value).map(|v| Self::from(v.as_slice()))
768    }
769
770    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
771        Ok(Self::from(value))
772    }
773}
774
775#[cfg(feature = "smallvec")]
776impl<const N: usize> FromSQLiteValue for smallvec::SmallVec<[u8; N]> {
777    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
778        Err(DrizzleError::ConversionError(
779            "cannot convert INTEGER to SmallVec<u8>, use BLOB".into(),
780        ))
781    }
782
783    fn from_sqlite_text(_value: &str) -> Result<Self, DrizzleError> {
784        Err(DrizzleError::ConversionError(
785            "cannot convert TEXT to SmallVec<u8>, use BLOB".into(),
786        ))
787    }
788
789    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
790        Err(DrizzleError::ConversionError(
791            "cannot convert REAL to SmallVec<u8>, use BLOB".into(),
792        ))
793    }
794
795    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
796        let mut out = Self::new();
797        out.extend_from_slice(value);
798        Ok(out)
799    }
800}
801
802impl FromSQLiteValue for Box<Vec<u8>> {
803    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
804        Vec::<u8>::from_sqlite_integer(value).map(Self::new)
805    }
806
807    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
808        Vec::<u8>::from_sqlite_text(value).map(Self::new)
809    }
810
811    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
812        Vec::<u8>::from_sqlite_real(value).map(Self::new)
813    }
814
815    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
816        Vec::<u8>::from_sqlite_blob(value).map(Self::new)
817    }
818}
819
820impl FromSQLiteValue for Rc<Vec<u8>> {
821    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
822        Vec::<u8>::from_sqlite_integer(value).map(Self::new)
823    }
824
825    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
826        Vec::<u8>::from_sqlite_text(value).map(Self::new)
827    }
828
829    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
830        Vec::<u8>::from_sqlite_real(value).map(Self::new)
831    }
832
833    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
834        Vec::<u8>::from_sqlite_blob(value).map(Self::new)
835    }
836}
837
838impl FromSQLiteValue for Arc<Vec<u8>> {
839    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
840        Vec::<u8>::from_sqlite_integer(value).map(Self::new)
841    }
842
843    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
844        Vec::<u8>::from_sqlite_text(value).map(Self::new)
845    }
846
847    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
848        Vec::<u8>::from_sqlite_real(value).map(Self::new)
849    }
850
851    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
852        Vec::<u8>::from_sqlite_blob(value).map(Self::new)
853    }
854}
855
856// Option<T> implementation - handles NULL values
857impl<T: FromSQLiteValue> FromSQLiteValue for Option<T> {
858    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
859        T::from_sqlite_integer(value).map(Some)
860    }
861
862    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
863        T::from_sqlite_text(value).map(Some)
864    }
865
866    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
867        T::from_sqlite_real(value).map(Some)
868    }
869
870    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
871        T::from_sqlite_blob(value).map(Some)
872    }
873
874    fn from_sqlite_null() -> Result<Self, DrizzleError> {
875        Ok(None)
876    }
877}
878
879// =============================================================================
880// Driver-specific DrizzleRow implementations
881// =============================================================================
882
883#[cfg(feature = "rusqlite")]
884impl DrizzleRowByIndex for rusqlite::Row<'_> {
885    fn get_column<T: FromSQLiteValue>(&self, idx: usize) -> Result<T, DrizzleError> {
886        let value_ref = self.get_ref(idx)?;
887        match value_ref {
888            rusqlite::types::ValueRef::Integer(i) => T::from_sqlite_integer(i),
889            rusqlite::types::ValueRef::Text(s) => {
890                let s = core::str::from_utf8(s).map_err(|e| {
891                    DrizzleError::ConversionError(format!("invalid UTF-8: {e}").into())
892                })?;
893                T::from_sqlite_text(s)
894            }
895            rusqlite::types::ValueRef::Real(r) => T::from_sqlite_real(r),
896            rusqlite::types::ValueRef::Blob(b) => T::from_sqlite_blob(b),
897            rusqlite::types::ValueRef::Null => T::from_sqlite_null(),
898        }
899    }
900}
901
902#[cfg(feature = "rusqlite")]
903impl DrizzleRowByName for rusqlite::Row<'_> {
904    fn get_column_by_name<T: FromSQLiteValue>(&self, name: &str) -> Result<T, DrizzleError> {
905        let idx = self.as_ref().column_index(name)?;
906        DrizzleRowByIndex::get_column(self, idx)
907    }
908}
909
910#[cfg(feature = "libsql")]
911impl DrizzleRowByIndex for libsql::Row {
912    fn get_column<T: FromSQLiteValue>(&self, idx: usize) -> Result<T, DrizzleError> {
913        let idx_i32 = i32::try_from(idx).map_err(|e| {
914            DrizzleError::ConversionError(format!("column index {idx} out of range: {e}").into())
915        })?;
916        let value = self.get_value(idx_i32)?;
917        match value {
918            libsql::Value::Integer(i) => T::from_sqlite_integer(i),
919            libsql::Value::Text(ref s) => T::from_sqlite_text(s),
920            libsql::Value::Real(r) => T::from_sqlite_real(r),
921            libsql::Value::Blob(ref b) => T::from_sqlite_blob(b),
922            libsql::Value::Null => T::from_sqlite_null(),
923        }
924    }
925}
926
927#[cfg(feature = "libsql")]
928impl DrizzleRowByName for libsql::Row {
929    fn get_column_by_name<T: FromSQLiteValue>(&self, name: &str) -> Result<T, DrizzleError> {
930        let idx = (0..self.column_count())
931            .find(|&i| self.column_name(i) == Some(name))
932            .ok_or_else(|| {
933                DrizzleError::ConversionError(format!("column '{name}' not found").into())
934            })?;
935
936        let idx_usize = usize::try_from(idx).map_err(|e| {
937            DrizzleError::ConversionError(format!("column index {idx} negative: {e}").into())
938        })?;
939        DrizzleRowByIndex::get_column(self, idx_usize)
940    }
941}
942
943#[cfg(feature = "turso")]
944impl DrizzleRowByIndex for turso::Row {
945    fn get_column<T: FromSQLiteValue>(&self, idx: usize) -> Result<T, DrizzleError> {
946        let value = self.get_value(idx)?;
947        if value.is_null() {
948            T::from_sqlite_null()
949        } else if let Some(&i) = value.as_integer() {
950            T::from_sqlite_integer(i)
951        } else if let Some(s) = value.as_text() {
952            T::from_sqlite_text(s)
953        } else if let Some(&r) = value.as_real() {
954            T::from_sqlite_real(r)
955        } else if let Some(b) = value.as_blob() {
956            T::from_sqlite_blob(b)
957        } else {
958            Err(DrizzleError::ConversionError(
959                "unknown SQLite value type".into(),
960            ))
961        }
962    }
963}
964
965// =============================================================================
966// UUID support (when feature enabled)
967// =============================================================================
968
969#[cfg(feature = "uuid")]
970impl FromSQLiteValue for uuid::Uuid {
971    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
972        Err(DrizzleError::ConversionError(
973            "cannot convert INTEGER to UUID".into(),
974        ))
975    }
976
977    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
978        Self::parse_str(value).map_err(|e| {
979            DrizzleError::ConversionError(format!("invalid UUID string '{value}': {e}").into())
980        })
981    }
982
983    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
984        Err(DrizzleError::ConversionError(
985            "cannot convert REAL to UUID".into(),
986        ))
987    }
988
989    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
990        Self::from_slice(value)
991            .map_err(|e| DrizzleError::ConversionError(format!("invalid UUID bytes: {e}").into()))
992    }
993}
994
995// =============================================================================
996// Chrono date/time types (parse from ISO-8601 text)
997// =============================================================================
998
999#[cfg(feature = "chrono")]
1000impl FromSQLiteValue for chrono::NaiveDate {
1001    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1002        Err(DrizzleError::ConversionError(
1003            "cannot convert INTEGER to NaiveDate".into(),
1004        ))
1005    }
1006
1007    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1008        value.parse().map_err(|e| {
1009            DrizzleError::ConversionError(
1010                format!("cannot parse '{value}' as NaiveDate: {e}").into(),
1011            )
1012        })
1013    }
1014
1015    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1016        Err(DrizzleError::ConversionError(
1017            "cannot convert REAL to NaiveDate".into(),
1018        ))
1019    }
1020
1021    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1022        Err(DrizzleError::ConversionError(
1023            "cannot convert BLOB to NaiveDate".into(),
1024        ))
1025    }
1026}
1027
1028#[cfg(feature = "chrono")]
1029impl FromSQLiteValue for chrono::NaiveTime {
1030    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1031        Err(DrizzleError::ConversionError(
1032            "cannot convert INTEGER to NaiveTime".into(),
1033        ))
1034    }
1035
1036    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1037        value.parse().map_err(|e| {
1038            DrizzleError::ConversionError(
1039                format!("cannot parse '{value}' as NaiveTime: {e}").into(),
1040            )
1041        })
1042    }
1043
1044    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1045        Err(DrizzleError::ConversionError(
1046            "cannot convert REAL to NaiveTime".into(),
1047        ))
1048    }
1049
1050    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1051        Err(DrizzleError::ConversionError(
1052            "cannot convert BLOB to NaiveTime".into(),
1053        ))
1054    }
1055}
1056
1057#[cfg(feature = "chrono")]
1058impl FromSQLiteValue for chrono::NaiveDateTime {
1059    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1060        Err(DrizzleError::ConversionError(
1061            "cannot convert INTEGER to NaiveDateTime".into(),
1062        ))
1063    }
1064
1065    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1066        chrono_text::naive(value).map_err(|e| {
1067            DrizzleError::ConversionError(
1068                format!("cannot parse '{value}' as NaiveDateTime: {e}").into(),
1069            )
1070        })
1071    }
1072
1073    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1074        Err(DrizzleError::ConversionError(
1075            "cannot convert REAL to NaiveDateTime".into(),
1076        ))
1077    }
1078
1079    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1080        Err(DrizzleError::ConversionError(
1081            "cannot convert BLOB to NaiveDateTime".into(),
1082        ))
1083    }
1084}
1085
1086#[cfg(feature = "chrono")]
1087impl FromSQLiteValue for chrono::DateTime<chrono::FixedOffset> {
1088    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1089        Err(DrizzleError::ConversionError(
1090            "cannot convert INTEGER to DateTime<FixedOffset>".into(),
1091        ))
1092    }
1093
1094    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1095        chrono_text::fixed(value).map_err(|e| {
1096            DrizzleError::ConversionError(
1097                format!("cannot parse '{value}' as DateTime<FixedOffset>: {e}").into(),
1098            )
1099        })
1100    }
1101
1102    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1103        Err(DrizzleError::ConversionError(
1104            "cannot convert REAL to DateTime<FixedOffset>".into(),
1105        ))
1106    }
1107
1108    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1109        Err(DrizzleError::ConversionError(
1110            "cannot convert BLOB to DateTime<FixedOffset>".into(),
1111        ))
1112    }
1113}
1114
1115#[cfg(feature = "chrono")]
1116impl FromSQLiteValue for chrono::DateTime<chrono::Utc> {
1117    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1118        Err(DrizzleError::ConversionError(
1119            "cannot convert INTEGER to DateTime<Utc>".into(),
1120        ))
1121    }
1122
1123    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1124        chrono_text::utc(value).map_err(|e| {
1125            DrizzleError::ConversionError(
1126                format!("cannot parse '{value}' as DateTime<Utc>: {e}").into(),
1127            )
1128        })
1129    }
1130
1131    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1132        Err(DrizzleError::ConversionError(
1133            "cannot convert REAL to DateTime<Utc>".into(),
1134        ))
1135    }
1136
1137    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1138        Err(DrizzleError::ConversionError(
1139            "cannot convert BLOB to DateTime<Utc>".into(),
1140        ))
1141    }
1142}
1143
1144// =============================================================================
1145// Text parsers for chrono and time, and the time crate's date/time types
1146// =============================================================================
1147
1148/// Parsers for the text chrono values are stored as.
1149///
1150/// The SQLite conversions write a `NaiveDateTime` with a space between date
1151/// and time, as SQLite's own date and time functions do, and chrono's
1152/// `FromStr` reads only ISO 8601's `T`. Each parser accepts both, and reads a
1153/// date and time without an offset as UTC.
1154#[cfg(feature = "chrono")]
1155pub(crate) mod chrono_text {
1156    use chrono::{DateTime, FixedOffset, NaiveDateTime, Offset, ParseResult, Utc};
1157
1158    /// SQLite's `YYYY-MM-DD HH:MM:SS[.fraction]`, or ISO 8601.
1159    pub(crate) fn naive(text: &str) -> ParseResult<NaiveDateTime> {
1160        NaiveDateTime::parse_from_str(text, "%Y-%m-%d %H:%M:%S%.f").or_else(|_| text.parse())
1161    }
1162
1163    /// RFC 3339, or a date and time without an offset, which is UTC.
1164    pub(crate) fn fixed(text: &str) -> ParseResult<DateTime<FixedOffset>> {
1165        DateTime::parse_from_rfc3339(text).or_else(|error| {
1166            naive(text)
1167                .map(|value| DateTime::from_naive_utc_and_offset(value, Utc.fix()))
1168                .map_err(|_| error)
1169        })
1170    }
1171
1172    /// A date and time with an offset, or without one, which is UTC.
1173    pub(crate) fn utc(text: &str) -> ParseResult<DateTime<Utc>> {
1174        text.parse().or_else(|error| {
1175            naive(text)
1176                .map(|value| DateTime::from_naive_utc_and_offset(value, Utc))
1177                .map_err(|_| error)
1178        })
1179    }
1180}
1181
1182/// Parsers for the text `time` values are stored as.
1183///
1184/// Each accepts what the SQLite conversions write and the forms SQLite's own
1185/// date and time functions produce (`HH:MM:SS`, a space between date and time,
1186/// no offset for UTC).
1187#[cfg(feature = "time")]
1188pub(crate) mod time_text {
1189    use time::format_description::well_known::{Iso8601, Rfc3339};
1190    use time::macros::format_description;
1191
1192    /// `HH:MM:SS[.fraction]`. Versions before 0.2.0 wrote ISO 8601's `T`
1193    /// prefix, which is accepted too.
1194    pub(crate) fn time(text: &str) -> Result<time::Time, time::error::Parse> {
1195        let text = text.strip_prefix('T').unwrap_or(text);
1196        time::Time::parse(
1197            text,
1198            format_description!("[hour]:[minute]:[second].[subsecond]"),
1199        )
1200        .or_else(|_| time::Time::parse(text, format_description!("[hour]:[minute]:[second]")))
1201    }
1202
1203    /// ISO 8601, or SQLite's `YYYY-MM-DD HH:MM:SS[.fraction]`.
1204    pub(crate) fn primitive(text: &str) -> Result<time::PrimitiveDateTime, time::error::Parse> {
1205        time::PrimitiveDateTime::parse(text, &Iso8601::DATE_TIME)
1206            .or_else(|_| {
1207                time::PrimitiveDateTime::parse(
1208                    text,
1209                    format_description!(
1210                        "[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]"
1211                    ),
1212                )
1213            })
1214            .or_else(|_| {
1215                time::PrimitiveDateTime::parse(
1216                    text,
1217                    format_description!("[year]-[month]-[day] [hour]:[minute]:[second]"),
1218                )
1219            })
1220    }
1221
1222    /// RFC 3339, or a date and time without an offset, which is UTC.
1223    pub(crate) fn offset(text: &str) -> Result<time::OffsetDateTime, time::error::Parse> {
1224        time::OffsetDateTime::parse(text, &Rfc3339).or_else(|error| {
1225            primitive(text)
1226                .map(time::PrimitiveDateTime::assume_utc)
1227                .map_err(|_| error)
1228        })
1229    }
1230}
1231
1232#[cfg(feature = "time")]
1233impl FromSQLiteValue for time::Date {
1234    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1235        Err(DrizzleError::ConversionError(
1236            "cannot convert INTEGER to time::Date".into(),
1237        ))
1238    }
1239
1240    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1241        Self::parse(value, &time::format_description::well_known::Iso8601::DATE).map_err(|e| {
1242            DrizzleError::ConversionError(
1243                format!("cannot parse '{value}' as time::Date: {e}").into(),
1244            )
1245        })
1246    }
1247
1248    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1249        Err(DrizzleError::ConversionError(
1250            "cannot convert REAL to time::Date".into(),
1251        ))
1252    }
1253
1254    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1255        Err(DrizzleError::ConversionError(
1256            "cannot convert BLOB to time::Date".into(),
1257        ))
1258    }
1259}
1260
1261#[cfg(feature = "time")]
1262impl FromSQLiteValue for time::Time {
1263    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1264        Err(DrizzleError::ConversionError(
1265            "cannot convert INTEGER to time::Time".into(),
1266        ))
1267    }
1268
1269    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1270        time_text::time(value).map_err(|e| {
1271            DrizzleError::ConversionError(
1272                format!("cannot parse '{value}' as time::Time: {e}").into(),
1273            )
1274        })
1275    }
1276
1277    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1278        Err(DrizzleError::ConversionError(
1279            "cannot convert REAL to time::Time".into(),
1280        ))
1281    }
1282
1283    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1284        Err(DrizzleError::ConversionError(
1285            "cannot convert BLOB to time::Time".into(),
1286        ))
1287    }
1288}
1289
1290#[cfg(feature = "time")]
1291impl FromSQLiteValue for time::PrimitiveDateTime {
1292    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1293        Err(DrizzleError::ConversionError(
1294            "cannot convert INTEGER to time::PrimitiveDateTime".into(),
1295        ))
1296    }
1297
1298    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1299        time_text::primitive(value).map_err(|e| {
1300            DrizzleError::ConversionError(
1301                format!("cannot parse '{value}' as time::PrimitiveDateTime: {e}").into(),
1302            )
1303        })
1304    }
1305
1306    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1307        Err(DrizzleError::ConversionError(
1308            "cannot convert REAL to time::PrimitiveDateTime".into(),
1309        ))
1310    }
1311
1312    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1313        Err(DrizzleError::ConversionError(
1314            "cannot convert BLOB to time::PrimitiveDateTime".into(),
1315        ))
1316    }
1317}
1318
1319#[cfg(feature = "time")]
1320impl FromSQLiteValue for time::OffsetDateTime {
1321    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1322        Err(DrizzleError::ConversionError(
1323            "cannot convert INTEGER to time::OffsetDateTime".into(),
1324        ))
1325    }
1326
1327    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1328        time_text::offset(value).map_err(|e| {
1329            DrizzleError::ConversionError(
1330                format!("cannot parse '{value}' as time::OffsetDateTime: {e}").into(),
1331            )
1332        })
1333    }
1334
1335    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1336        Err(DrizzleError::ConversionError(
1337            "cannot convert REAL to time::OffsetDateTime".into(),
1338        ))
1339    }
1340
1341    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1342        Err(DrizzleError::ConversionError(
1343            "cannot convert BLOB to time::OffsetDateTime".into(),
1344        ))
1345    }
1346}
1347
1348// =============================================================================
1349// jiff (parse from ISO 8601 text)
1350// =============================================================================
1351
1352/// Parses SQLite text as the jiff value named `name`.
1353#[cfg(feature = "jiff")]
1354fn parse_jiff<T: core::str::FromStr<Err = jiff::Error>>(
1355    value: &str,
1356    name: &str,
1357) -> Result<T, DrizzleError> {
1358    value.parse().map_err(|e: jiff::Error| {
1359        DrizzleError::ConversionError(format!("cannot parse '{value}' as {name}: {e}").into())
1360    })
1361}
1362
1363/// Implements [`FromSQLiteValue`] for jiff types, which SQLite stores as text.
1364#[cfg(feature = "jiff")]
1365macro_rules! impl_from_sqlite_value_jiff {
1366    ($($ty:ty => $name:literal, $parse:expr;)+) => {$(
1367        impl FromSQLiteValue for $ty {
1368            fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1369                Err(DrizzleError::ConversionError(
1370                    concat!("cannot convert INTEGER to ", $name).into(),
1371                ))
1372            }
1373
1374            fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1375                $parse(value)
1376            }
1377
1378            fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1379                Err(DrizzleError::ConversionError(
1380                    concat!("cannot convert REAL to ", $name).into(),
1381                ))
1382            }
1383
1384            fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1385                Err(DrizzleError::ConversionError(
1386                    concat!("cannot convert BLOB to ", $name).into(),
1387                ))
1388            }
1389        }
1390    )+};
1391}
1392
1393#[cfg(feature = "jiff")]
1394impl_from_sqlite_value_jiff! {
1395    jiff::civil::Date => "jiff::civil::Date",
1396        |value| parse_jiff(value, "jiff::civil::Date");
1397    jiff::civil::Time => "jiff::civil::Time",
1398        |value| parse_jiff(value, "jiff::civil::Time");
1399    jiff::civil::DateTime => "jiff::civil::DateTime",
1400        |value| parse_jiff(value, "jiff::civil::DateTime");
1401    // RFC 3339 as the conversion writes it; text without an offset (as
1402    // SQLite's own `CURRENT_TIMESTAMP` writes) is UTC.
1403    jiff::Timestamp => "jiff::Timestamp", |value: &str| {
1404        value.parse().or_else(|_| {
1405            let civil: jiff::civil::DateTime = parse_jiff(value, "jiff::Timestamp")?;
1406            jiff::tz::Offset::UTC.to_timestamp(civil).map_err(|e| {
1407                DrizzleError::ConversionError(
1408                    format!("cannot convert '{value}' to jiff::Timestamp: {e}").into(),
1409                )
1410            })
1411        })
1412    };
1413}
1414
1415// =============================================================================
1416// Decimal (parse from text)
1417// =============================================================================
1418
1419#[cfg(feature = "rust-decimal")]
1420impl FromSQLiteValue for rust_decimal::Decimal {
1421    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
1422        Ok(Self::from(value))
1423    }
1424
1425    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1426        value.parse().map_err(|e| {
1427            DrizzleError::ConversionError(format!("cannot parse '{value}' as Decimal: {e}").into())
1428        })
1429    }
1430
1431    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
1432        Self::try_from(value).map_err(|e| {
1433            DrizzleError::ConversionError(
1434                format!("cannot convert REAL {value} to Decimal: {e}").into(),
1435            )
1436        })
1437    }
1438
1439    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1440        Err(DrizzleError::ConversionError(
1441            "cannot convert BLOB to Decimal".into(),
1442        ))
1443    }
1444}
1445
1446// =============================================================================
1447// Duration types
1448// =============================================================================
1449
1450#[cfg(feature = "chrono")]
1451impl FromSQLiteValue for chrono::Duration {
1452    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
1453        Ok(Self::seconds(value))
1454    }
1455
1456    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1457        let error = || {
1458            DrizzleError::ConversionError(
1459                format!("cannot parse '{value}' as chrono::Duration").into(),
1460            )
1461        };
1462        let (negative, secs, nanos) = crate::values::duration::parse(value).ok_or_else(error)?;
1463        let secs = i64::try_from(secs).map_err(|_| error())?;
1464        let duration = Self::new(secs, nanos).ok_or_else(error)?;
1465        Ok(if negative { -duration } else { duration })
1466    }
1467
1468    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
1469        let millis: i64 = format!("{:.0}", value * 1000.0).parse().map_err(|e| {
1470            DrizzleError::ConversionError(
1471                format!("cannot convert REAL {value} to chrono::Duration: {e}").into(),
1472            )
1473        })?;
1474        Ok(Self::milliseconds(millis))
1475    }
1476
1477    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1478        Err(DrizzleError::ConversionError(
1479            "cannot convert BLOB to chrono::Duration".into(),
1480        ))
1481    }
1482}
1483
1484#[cfg(feature = "time")]
1485impl FromSQLiteValue for time::Duration {
1486    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
1487        Ok(Self::seconds(value))
1488    }
1489
1490    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1491        let error = || {
1492            DrizzleError::ConversionError(
1493                format!("cannot parse '{value}' as time::Duration").into(),
1494            )
1495        };
1496        let (negative, secs, nanos) = crate::values::duration::parse(value).ok_or_else(error)?;
1497        let secs = i64::try_from(secs).map_err(|_| error())?;
1498        // `nanos` is below 1_000_000_000, so it always fits in an i32.
1499        let duration = Self::new(secs, nanos as i32);
1500        Ok(if negative { -duration } else { duration })
1501    }
1502
1503    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
1504        Ok(Self::seconds_f64(value))
1505    }
1506
1507    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1508        Err(DrizzleError::ConversionError(
1509            "cannot convert BLOB to time::Duration".into(),
1510        ))
1511    }
1512}
1513
1514// =============================================================================
1515// JSON support (serde_json::Value)
1516// =============================================================================
1517
1518#[cfg(feature = "serde")]
1519impl FromSQLiteValue for serde_json::Value {
1520    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
1521        Ok(Self::Number(value.into()))
1522    }
1523
1524    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1525        serde_json::from_str(value).map_err(|e| {
1526            DrizzleError::ConversionError(format!("cannot parse '{value}' as JSON: {e}").into())
1527        })
1528    }
1529
1530    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
1531        serde_json::Number::from_f64(value)
1532            .map(serde_json::Value::Number)
1533            .ok_or_else(|| {
1534                DrizzleError::ConversionError(
1535                    format!("cannot convert non-finite REAL {value} to JSON").into(),
1536                )
1537            })
1538    }
1539
1540    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
1541        serde_json::from_slice(value).map_err(|e| {
1542            DrizzleError::ConversionError(format!("cannot parse BLOB as JSON: {e}").into())
1543        })
1544    }
1545}
1546
1547// =============================================================================
1548// ArrayVec/ArrayString support
1549// =============================================================================
1550
1551#[cfg(feature = "arrayvec")]
1552impl<const N: usize> FromSQLiteValue for arrayvec::ArrayString<N> {
1553    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
1554        let s = value.to_string();
1555        Self::from(&s).map_err(|_| {
1556            DrizzleError::ConversionError(
1557                format!(
1558                    "String length {} exceeds ArrayString capacity {}",
1559                    s.len(),
1560                    N
1561                )
1562                .into(),
1563            )
1564        })
1565    }
1566
1567    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1568        Self::from(value).map_err(|_| {
1569            DrizzleError::ConversionError(
1570                format!(
1571                    "Text length {} exceeds ArrayString capacity {}",
1572                    value.len(),
1573                    N
1574                )
1575                .into(),
1576            )
1577        })
1578    }
1579
1580    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
1581        let s = value.to_string();
1582        Self::from(&s).map_err(|_| {
1583            DrizzleError::ConversionError(
1584                format!(
1585                    "String length {} exceeds ArrayString capacity {}",
1586                    s.len(),
1587                    N
1588                )
1589                .into(),
1590            )
1591        })
1592    }
1593
1594    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
1595        let s = String::from_utf8(value.to_vec())
1596            .map_err(|e| DrizzleError::ConversionError(format!("invalid UTF-8: {e}").into()))?;
1597        Self::from(&s).map_err(|_| {
1598            DrizzleError::ConversionError(
1599                format!(
1600                    "String length {} exceeds ArrayString capacity {}",
1601                    s.len(),
1602                    N
1603                )
1604                .into(),
1605            )
1606        })
1607    }
1608}
1609
1610#[cfg(feature = "arrayvec")]
1611impl<const N: usize> FromSQLiteValue for arrayvec::ArrayVec<u8, N> {
1612    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1613        Err(DrizzleError::ConversionError(
1614            "cannot convert INTEGER to ArrayVec<u8>, use BLOB".into(),
1615        ))
1616    }
1617
1618    fn from_sqlite_text(_value: &str) -> Result<Self, DrizzleError> {
1619        Err(DrizzleError::ConversionError(
1620            "cannot convert TEXT to ArrayVec<u8>, use BLOB".into(),
1621        ))
1622    }
1623
1624    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1625        Err(DrizzleError::ConversionError(
1626            "cannot convert REAL to ArrayVec<u8>, use BLOB".into(),
1627        ))
1628    }
1629
1630    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
1631        Self::try_from(value).map_err(|_| {
1632            DrizzleError::ConversionError(
1633                format!(
1634                    "Blob length {} exceeds ArrayVec capacity {}",
1635                    value.len(),
1636                    N
1637                )
1638                .into(),
1639            )
1640        })
1641    }
1642}