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    // Unsigned 64-bit widths: stored with their bits reinterpreted as i64
439    // (see `From<u64> for SQLiteValue`), so a negative INTEGER is a value
440    // above `i64::MAX`.
441    (unsigned64: $($ty:ty),+ $(,)?) => {
442        $(
443            impl FromSQLiteValue for $ty {
444                fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
445                    unsigned_from_stored_bits(value, stringify!($ty))
446                }
447
448                fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
449                    value.parse().map_err(|e| {
450                        DrizzleError::ConversionError(
451                            format!("cannot parse '{}' as {}: {}", value, stringify!($ty), e).into()
452                        )
453                    })
454                }
455
456                fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
457                    checked_float_to_int(value, stringify!($ty))
458                }
459
460                fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
461                    Err(DrizzleError::ConversionError(
462                        concat!("cannot convert BLOB to ", stringify!($ty)).into()
463                    ))
464                }
465            }
466        )+
467    };
468    // General case for other integer types - uses try_into for narrowing
469    ($($ty:ty),+ $(,)?) => {
470        $(
471            impl FromSQLiteValue for $ty {
472                fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
473                    value.try_into().map_err(|e| {
474                        DrizzleError::ConversionError(
475                            format!("i64 {} out of range for {}: {}", value, stringify!($ty), e).into(),
476                        )
477                    })
478                }
479
480                fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
481                    value.parse().map_err(|e| {
482                        DrizzleError::ConversionError(
483                            format!("cannot parse '{}' as {}: {}", value, stringify!($ty), e).into()
484                        )
485                    })
486                }
487
488                fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
489                    checked_float_to_int(value, stringify!($ty))
490                }
491
492                fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
493                    Err(DrizzleError::ConversionError(
494                        concat!("cannot convert BLOB to ", stringify!($ty)).into()
495                    ))
496                }
497            }
498        )+
499    };
500}
501
502/// Reads a `u64`/`usize` INTEGER, whose bits were stored reinterpreted as
503/// `i64`.
504fn unsigned_from_stored_bits<T>(value: i64, name: &str) -> Result<T, DrizzleError>
505where
506    T: TryFrom<u64>,
507    T::Error: core::fmt::Display,
508{
509    T::try_from(value.cast_unsigned()).map_err(|e| {
510        DrizzleError::ConversionError(format!("i64 {value} out of range for {name}: {e}").into())
511    })
512}
513
514/// IEEE 754 `f64` representation of an `i64` built from two exact halves via
515/// [`From`], matching the semantics of `i as f64` without an `as`-cast.
516#[inline]
517fn i64_to_f64(i: i64) -> f64 {
518    let high = i32::try_from(i >> 32).expect("sign-extended high word fits in i32");
519    let low = u32::try_from(i & 0xFFFF_FFFF).expect("masked low word fits in u32");
520    f64::from(high) * 4_294_967_296.0_f64 + f64::from(low)
521}
522
523// Integer types
524impl_from_sqlite_value_int!(i64);
525impl_from_sqlite_value_int!(i8, i16, i32, isize, u8, u16, u32);
526impl_from_sqlite_value_int!(unsigned64: u64, usize);
527
528// f64 — `i64` widening via split-halves is exact in the mantissa range and
529// matches direct `as` cast beyond it; no cast is needed for f64→f64.
530impl FromSQLiteValue for f64 {
531    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
532        Ok(i64_to_f64(value))
533    }
534
535    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
536        value.parse().map_err(|e| {
537            DrizzleError::ConversionError(format!("cannot parse '{value}' as f64: {e}").into())
538        })
539    }
540
541    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
542        Ok(value)
543    }
544
545    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
546        Err(DrizzleError::ConversionError(
547            "cannot convert BLOB to f64".into(),
548        ))
549    }
550}
551
552fn narrow_to_f32(value: f64) -> Result<f32, DrizzleError> {
553    // Round-trip through a decimal string so IEEE 754 round-to-nearest is
554    // applied explicitly (and clippy doesn't flag the conversion as a lossy
555    // numeric cast).
556    format!("{value}").parse::<f32>().map_err(|e| {
557        DrizzleError::ConversionError(format!("cannot convert REAL {value} to f32: {e}").into())
558    })
559}
560
561// f32 — narrowing from both `i64` and `f64` is intentionally lossy; SQLite
562// round-trips the value through `f64` storage so we defer to the standard
563// IEEE 754 narrowing conversion. These casts are the only correct semantics.
564impl FromSQLiteValue for f32 {
565    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
566        // Go via f64 (exact) then narrow to f32.
567        narrow_to_f32(i64_to_f64(value))
568    }
569
570    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
571        value.parse().map_err(|e| {
572            DrizzleError::ConversionError(format!("cannot parse '{value}' as f32: {e}").into())
573        })
574    }
575
576    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
577        narrow_to_f32(value)
578    }
579
580    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
581        Err(DrizzleError::ConversionError(
582            "cannot convert BLOB to f32".into(),
583        ))
584    }
585}
586
587impl FromSQLiteValue for bool {
588    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
589        Ok(value != 0)
590    }
591
592    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
593        match value.to_lowercase().as_str() {
594            "true" | "1" | "yes" | "on" => Ok(true),
595            "false" | "0" | "no" | "off" => Ok(false),
596            _ => Err(DrizzleError::ConversionError(
597                format!("cannot parse '{value}' as bool").into(),
598            )),
599        }
600    }
601
602    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
603        Ok(value != 0.0)
604    }
605
606    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
607        Err(DrizzleError::ConversionError(
608            "cannot convert BLOB to bool".into(),
609        ))
610    }
611}
612
613impl FromSQLiteValue for String {
614    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
615        Ok(value.to_string())
616    }
617
618    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
619        Ok(value.to_string())
620    }
621
622    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
623        Ok(value.to_string())
624    }
625
626    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
627        Self::from_utf8(value.to_vec()).map_err(|e| {
628            DrizzleError::ConversionError(format!("invalid UTF-8 in BLOB: {e}").into())
629        })
630    }
631}
632
633impl FromSQLiteValue for compact_str::CompactString {
634    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
635        Ok(Self::new(value.to_string()))
636    }
637
638    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
639        Ok(Self::new(value))
640    }
641
642    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
643        Ok(Self::new(value.to_string()))
644    }
645
646    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
647        let s = String::from_utf8(value.to_vec()).map_err(|e| {
648            DrizzleError::ConversionError(format!("invalid UTF-8 in BLOB: {e}").into())
649        })?;
650        Ok(Self::new(s))
651    }
652}
653
654impl FromSQLiteValue for Box<String> {
655    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
656        String::from_sqlite_integer(value).map(Self::new)
657    }
658
659    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
660        String::from_sqlite_text(value).map(Self::new)
661    }
662
663    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
664        String::from_sqlite_real(value).map(Self::new)
665    }
666
667    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
668        String::from_sqlite_blob(value).map(Self::new)
669    }
670}
671
672impl FromSQLiteValue for Rc<String> {
673    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
674        String::from_sqlite_integer(value).map(Self::new)
675    }
676
677    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
678        String::from_sqlite_text(value).map(Self::new)
679    }
680
681    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
682        String::from_sqlite_real(value).map(Self::new)
683    }
684
685    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
686        String::from_sqlite_blob(value).map(Self::new)
687    }
688}
689
690impl FromSQLiteValue for Arc<String> {
691    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
692        String::from_sqlite_integer(value).map(Self::new)
693    }
694
695    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
696        String::from_sqlite_text(value).map(Self::new)
697    }
698
699    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
700        String::from_sqlite_real(value).map(Self::new)
701    }
702
703    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
704        String::from_sqlite_blob(value).map(Self::new)
705    }
706}
707
708impl FromSQLiteValue for Box<str> {
709    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
710        String::from_sqlite_integer(value).map(String::into_boxed_str)
711    }
712
713    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
714        String::from_sqlite_text(value).map(String::into_boxed_str)
715    }
716
717    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
718        String::from_sqlite_real(value).map(String::into_boxed_str)
719    }
720
721    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
722        String::from_sqlite_blob(value).map(String::into_boxed_str)
723    }
724}
725
726impl FromSQLiteValue for Rc<str> {
727    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
728        String::from_sqlite_integer(value).map(Self::from)
729    }
730
731    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
732        String::from_sqlite_text(value).map(Self::from)
733    }
734
735    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
736        String::from_sqlite_real(value).map(Self::from)
737    }
738
739    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
740        String::from_sqlite_blob(value).map(Self::from)
741    }
742}
743
744impl FromSQLiteValue for Arc<str> {
745    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
746        String::from_sqlite_integer(value).map(Self::from)
747    }
748
749    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
750        String::from_sqlite_text(value).map(Self::from)
751    }
752
753    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
754        String::from_sqlite_real(value).map(Self::from)
755    }
756
757    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
758        String::from_sqlite_blob(value).map(Self::from)
759    }
760}
761
762impl FromSQLiteValue for Vec<u8> {
763    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
764        Ok(value.to_le_bytes().to_vec())
765    }
766
767    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
768        Ok(value.as_bytes().to_vec())
769    }
770
771    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
772        Ok(value.to_le_bytes().to_vec())
773    }
774
775    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
776        Ok(value.to_vec())
777    }
778}
779
780#[cfg(feature = "bytes")]
781impl FromSQLiteValue for bytes::Bytes {
782    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
783        Vec::<u8>::from_sqlite_integer(value).map(Self::from)
784    }
785
786    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
787        Vec::<u8>::from_sqlite_text(value).map(Self::from)
788    }
789
790    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
791        Vec::<u8>::from_sqlite_real(value).map(Self::from)
792    }
793
794    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
795        Ok(Self::copy_from_slice(value))
796    }
797}
798
799#[cfg(feature = "bytes")]
800impl FromSQLiteValue for bytes::BytesMut {
801    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
802        Vec::<u8>::from_sqlite_integer(value).map(|v| Self::from(v.as_slice()))
803    }
804
805    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
806        Vec::<u8>::from_sqlite_text(value).map(|v| Self::from(v.as_slice()))
807    }
808
809    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
810        Vec::<u8>::from_sqlite_real(value).map(|v| Self::from(v.as_slice()))
811    }
812
813    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
814        Ok(Self::from(value))
815    }
816}
817
818#[cfg(feature = "smallvec")]
819impl<const N: usize> FromSQLiteValue for smallvec::SmallVec<[u8; N]> {
820    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
821        Err(DrizzleError::ConversionError(
822            "cannot convert INTEGER to SmallVec<u8>, use BLOB".into(),
823        ))
824    }
825
826    fn from_sqlite_text(_value: &str) -> Result<Self, DrizzleError> {
827        Err(DrizzleError::ConversionError(
828            "cannot convert TEXT to SmallVec<u8>, use BLOB".into(),
829        ))
830    }
831
832    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
833        Err(DrizzleError::ConversionError(
834            "cannot convert REAL to SmallVec<u8>, use BLOB".into(),
835        ))
836    }
837
838    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
839        let mut out = Self::new();
840        out.extend_from_slice(value);
841        Ok(out)
842    }
843}
844
845impl FromSQLiteValue for Box<Vec<u8>> {
846    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
847        Vec::<u8>::from_sqlite_integer(value).map(Self::new)
848    }
849
850    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
851        Vec::<u8>::from_sqlite_text(value).map(Self::new)
852    }
853
854    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
855        Vec::<u8>::from_sqlite_real(value).map(Self::new)
856    }
857
858    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
859        Vec::<u8>::from_sqlite_blob(value).map(Self::new)
860    }
861}
862
863impl FromSQLiteValue for Rc<Vec<u8>> {
864    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
865        Vec::<u8>::from_sqlite_integer(value).map(Self::new)
866    }
867
868    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
869        Vec::<u8>::from_sqlite_text(value).map(Self::new)
870    }
871
872    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
873        Vec::<u8>::from_sqlite_real(value).map(Self::new)
874    }
875
876    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
877        Vec::<u8>::from_sqlite_blob(value).map(Self::new)
878    }
879}
880
881impl FromSQLiteValue for Arc<Vec<u8>> {
882    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
883        Vec::<u8>::from_sqlite_integer(value).map(Self::new)
884    }
885
886    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
887        Vec::<u8>::from_sqlite_text(value).map(Self::new)
888    }
889
890    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
891        Vec::<u8>::from_sqlite_real(value).map(Self::new)
892    }
893
894    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
895        Vec::<u8>::from_sqlite_blob(value).map(Self::new)
896    }
897}
898
899// Option<T> implementation - handles NULL values
900impl<T: FromSQLiteValue> FromSQLiteValue for Option<T> {
901    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
902        T::from_sqlite_integer(value).map(Some)
903    }
904
905    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
906        T::from_sqlite_text(value).map(Some)
907    }
908
909    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
910        T::from_sqlite_real(value).map(Some)
911    }
912
913    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
914        T::from_sqlite_blob(value).map(Some)
915    }
916
917    fn from_sqlite_null() -> Result<Self, DrizzleError> {
918        Ok(None)
919    }
920}
921
922// =============================================================================
923// Driver-specific DrizzleRow implementations
924// =============================================================================
925
926#[cfg(feature = "rusqlite")]
927impl DrizzleRowByIndex for rusqlite::Row<'_> {
928    fn get_column<T: FromSQLiteValue>(&self, idx: usize) -> Result<T, DrizzleError> {
929        let value_ref = self.get_ref(idx)?;
930        match value_ref {
931            rusqlite::types::ValueRef::Integer(i) => T::from_sqlite_integer(i),
932            rusqlite::types::ValueRef::Text(s) => {
933                let s = core::str::from_utf8(s).map_err(|e| {
934                    DrizzleError::ConversionError(format!("invalid UTF-8: {e}").into())
935                })?;
936                T::from_sqlite_text(s)
937            }
938            rusqlite::types::ValueRef::Real(r) => T::from_sqlite_real(r),
939            rusqlite::types::ValueRef::Blob(b) => T::from_sqlite_blob(b),
940            rusqlite::types::ValueRef::Null => T::from_sqlite_null(),
941        }
942    }
943}
944
945#[cfg(feature = "rusqlite")]
946impl DrizzleRowByName for rusqlite::Row<'_> {
947    fn get_column_by_name<T: FromSQLiteValue>(&self, name: &str) -> Result<T, DrizzleError> {
948        let idx = self.as_ref().column_index(name)?;
949        DrizzleRowByIndex::get_column(self, idx)
950    }
951}
952
953#[cfg(feature = "libsql")]
954impl DrizzleRowByIndex for libsql::Row {
955    fn get_column<T: FromSQLiteValue>(&self, idx: usize) -> Result<T, DrizzleError> {
956        let idx_i32 = i32::try_from(idx).map_err(|e| {
957            DrizzleError::ConversionError(format!("column index {idx} out of range: {e}").into())
958        })?;
959        let value = self.get_value(idx_i32)?;
960        match value {
961            libsql::Value::Integer(i) => T::from_sqlite_integer(i),
962            libsql::Value::Text(ref s) => T::from_sqlite_text(s),
963            libsql::Value::Real(r) => T::from_sqlite_real(r),
964            libsql::Value::Blob(ref b) => T::from_sqlite_blob(b),
965            libsql::Value::Null => T::from_sqlite_null(),
966        }
967    }
968}
969
970#[cfg(feature = "libsql")]
971impl DrizzleRowByName for libsql::Row {
972    fn get_column_by_name<T: FromSQLiteValue>(&self, name: &str) -> Result<T, DrizzleError> {
973        let idx = (0..self.column_count())
974            .find(|&i| self.column_name(i) == Some(name))
975            .ok_or_else(|| {
976                DrizzleError::ConversionError(format!("column '{name}' not found").into())
977            })?;
978
979        let idx_usize = usize::try_from(idx).map_err(|e| {
980            DrizzleError::ConversionError(format!("column index {idx} negative: {e}").into())
981        })?;
982        DrizzleRowByIndex::get_column(self, idx_usize)
983    }
984}
985
986#[cfg(feature = "turso")]
987impl DrizzleRowByIndex for turso::Row {
988    fn get_column<T: FromSQLiteValue>(&self, idx: usize) -> Result<T, DrizzleError> {
989        let value = self.get_value(idx)?;
990        if value.is_null() {
991            T::from_sqlite_null()
992        } else if let Some(&i) = value.as_integer() {
993            T::from_sqlite_integer(i)
994        } else if let Some(s) = value.as_text() {
995            T::from_sqlite_text(s)
996        } else if let Some(&r) = value.as_real() {
997            T::from_sqlite_real(r)
998        } else if let Some(b) = value.as_blob() {
999            T::from_sqlite_blob(b)
1000        } else {
1001            Err(DrizzleError::ConversionError(
1002                "unknown SQLite value type".into(),
1003            ))
1004        }
1005    }
1006}
1007
1008// =============================================================================
1009// UUID support (when feature enabled)
1010// =============================================================================
1011
1012#[cfg(feature = "uuid")]
1013impl FromSQLiteValue for uuid::Uuid {
1014    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1015        Err(DrizzleError::ConversionError(
1016            "cannot convert INTEGER to UUID".into(),
1017        ))
1018    }
1019
1020    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1021        Self::parse_str(value).map_err(|e| {
1022            DrizzleError::ConversionError(format!("invalid UUID string '{value}': {e}").into())
1023        })
1024    }
1025
1026    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1027        Err(DrizzleError::ConversionError(
1028            "cannot convert REAL to UUID".into(),
1029        ))
1030    }
1031
1032    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
1033        Self::from_slice(value)
1034            .map_err(|e| DrizzleError::ConversionError(format!("invalid UUID bytes: {e}").into()))
1035    }
1036}
1037
1038// =============================================================================
1039// Chrono date/time types (parse from ISO-8601 text)
1040// =============================================================================
1041
1042#[cfg(feature = "chrono")]
1043impl FromSQLiteValue for chrono::NaiveDate {
1044    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1045        Err(DrizzleError::ConversionError(
1046            "cannot convert INTEGER to NaiveDate".into(),
1047        ))
1048    }
1049
1050    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1051        value.parse().map_err(|e| {
1052            DrizzleError::ConversionError(
1053                format!("cannot parse '{value}' as NaiveDate: {e}").into(),
1054            )
1055        })
1056    }
1057
1058    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1059        Err(DrizzleError::ConversionError(
1060            "cannot convert REAL to NaiveDate".into(),
1061        ))
1062    }
1063
1064    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1065        Err(DrizzleError::ConversionError(
1066            "cannot convert BLOB to NaiveDate".into(),
1067        ))
1068    }
1069}
1070
1071#[cfg(feature = "chrono")]
1072impl FromSQLiteValue for chrono::NaiveTime {
1073    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1074        Err(DrizzleError::ConversionError(
1075            "cannot convert INTEGER to NaiveTime".into(),
1076        ))
1077    }
1078
1079    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1080        value.parse().map_err(|e| {
1081            DrizzleError::ConversionError(
1082                format!("cannot parse '{value}' as NaiveTime: {e}").into(),
1083            )
1084        })
1085    }
1086
1087    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1088        Err(DrizzleError::ConversionError(
1089            "cannot convert REAL to NaiveTime".into(),
1090        ))
1091    }
1092
1093    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1094        Err(DrizzleError::ConversionError(
1095            "cannot convert BLOB to NaiveTime".into(),
1096        ))
1097    }
1098}
1099
1100#[cfg(feature = "chrono")]
1101impl FromSQLiteValue for chrono::NaiveDateTime {
1102    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1103        Err(DrizzleError::ConversionError(
1104            "cannot convert INTEGER to NaiveDateTime".into(),
1105        ))
1106    }
1107
1108    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1109        chrono_text::naive(value).map_err(|e| {
1110            DrizzleError::ConversionError(
1111                format!("cannot parse '{value}' as NaiveDateTime: {e}").into(),
1112            )
1113        })
1114    }
1115
1116    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1117        Err(DrizzleError::ConversionError(
1118            "cannot convert REAL to NaiveDateTime".into(),
1119        ))
1120    }
1121
1122    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1123        Err(DrizzleError::ConversionError(
1124            "cannot convert BLOB to NaiveDateTime".into(),
1125        ))
1126    }
1127}
1128
1129#[cfg(feature = "chrono")]
1130impl FromSQLiteValue for chrono::DateTime<chrono::FixedOffset> {
1131    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1132        Err(DrizzleError::ConversionError(
1133            "cannot convert INTEGER to DateTime<FixedOffset>".into(),
1134        ))
1135    }
1136
1137    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1138        chrono_text::fixed(value).map_err(|e| {
1139            DrizzleError::ConversionError(
1140                format!("cannot parse '{value}' as DateTime<FixedOffset>: {e}").into(),
1141            )
1142        })
1143    }
1144
1145    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1146        Err(DrizzleError::ConversionError(
1147            "cannot convert REAL to DateTime<FixedOffset>".into(),
1148        ))
1149    }
1150
1151    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1152        Err(DrizzleError::ConversionError(
1153            "cannot convert BLOB to DateTime<FixedOffset>".into(),
1154        ))
1155    }
1156}
1157
1158#[cfg(feature = "chrono")]
1159impl FromSQLiteValue for chrono::DateTime<chrono::Utc> {
1160    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1161        Err(DrizzleError::ConversionError(
1162            "cannot convert INTEGER to DateTime<Utc>".into(),
1163        ))
1164    }
1165
1166    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1167        chrono_text::utc(value).map_err(|e| {
1168            DrizzleError::ConversionError(
1169                format!("cannot parse '{value}' as DateTime<Utc>: {e}").into(),
1170            )
1171        })
1172    }
1173
1174    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1175        Err(DrizzleError::ConversionError(
1176            "cannot convert REAL to DateTime<Utc>".into(),
1177        ))
1178    }
1179
1180    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1181        Err(DrizzleError::ConversionError(
1182            "cannot convert BLOB to DateTime<Utc>".into(),
1183        ))
1184    }
1185}
1186
1187// =============================================================================
1188// Text parsers for chrono and time, and the time crate's date/time types
1189// =============================================================================
1190
1191/// Parsers for the text chrono values are stored as.
1192///
1193/// The SQLite conversions write a `NaiveDateTime` with a space between date
1194/// and time, as SQLite's own date and time functions do, and chrono's
1195/// `FromStr` reads only ISO 8601's `T`. Each parser accepts both, and reads a
1196/// date and time without an offset as UTC.
1197#[cfg(feature = "chrono")]
1198pub(crate) mod chrono_text {
1199    use chrono::{DateTime, FixedOffset, NaiveDateTime, Offset, ParseResult, Utc};
1200
1201    /// SQLite's `YYYY-MM-DD HH:MM:SS[.fraction]`, or ISO 8601.
1202    pub(crate) fn naive(text: &str) -> ParseResult<NaiveDateTime> {
1203        NaiveDateTime::parse_from_str(text, "%Y-%m-%d %H:%M:%S%.f").or_else(|_| text.parse())
1204    }
1205
1206    /// RFC 3339, or a date and time without an offset, which is UTC.
1207    pub(crate) fn fixed(text: &str) -> ParseResult<DateTime<FixedOffset>> {
1208        DateTime::parse_from_rfc3339(text).or_else(|error| {
1209            naive(text)
1210                .map(|value| DateTime::from_naive_utc_and_offset(value, Utc.fix()))
1211                .map_err(|_| error)
1212        })
1213    }
1214
1215    /// A date and time with an offset, or without one, which is UTC.
1216    pub(crate) fn utc(text: &str) -> ParseResult<DateTime<Utc>> {
1217        text.parse().or_else(|error| {
1218            naive(text)
1219                .map(|value| DateTime::from_naive_utc_and_offset(value, Utc))
1220                .map_err(|_| error)
1221        })
1222    }
1223}
1224
1225/// Parsers for the text `time` values are stored as.
1226///
1227/// Each accepts what the SQLite conversions write and the forms SQLite's own
1228/// date and time functions produce (`HH:MM:SS`, a space between date and time,
1229/// no offset for UTC).
1230#[cfg(feature = "time")]
1231pub(crate) mod time_text {
1232    use time::format_description::well_known::{Iso8601, Rfc3339};
1233    use time::macros::format_description;
1234
1235    /// `HH:MM:SS[.fraction]`. Versions before 0.2.0 wrote ISO 8601's `T`
1236    /// prefix, which is accepted too.
1237    pub(crate) fn time(text: &str) -> Result<time::Time, time::error::Parse> {
1238        let text = text.strip_prefix('T').unwrap_or(text);
1239        time::Time::parse(
1240            text,
1241            format_description!("[hour]:[minute]:[second].[subsecond]"),
1242        )
1243        .or_else(|_| time::Time::parse(text, format_description!("[hour]:[minute]:[second]")))
1244    }
1245
1246    /// ISO 8601, or SQLite's `YYYY-MM-DD HH:MM:SS[.fraction]`.
1247    pub(crate) fn primitive(text: &str) -> Result<time::PrimitiveDateTime, time::error::Parse> {
1248        time::PrimitiveDateTime::parse(text, &Iso8601::DATE_TIME)
1249            .or_else(|_| {
1250                time::PrimitiveDateTime::parse(
1251                    text,
1252                    format_description!(
1253                        "[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]"
1254                    ),
1255                )
1256            })
1257            .or_else(|_| {
1258                time::PrimitiveDateTime::parse(
1259                    text,
1260                    format_description!("[year]-[month]-[day] [hour]:[minute]:[second]"),
1261                )
1262            })
1263    }
1264
1265    /// RFC 3339, or a date and time without an offset, which is UTC.
1266    pub(crate) fn offset(text: &str) -> Result<time::OffsetDateTime, time::error::Parse> {
1267        time::OffsetDateTime::parse(text, &Rfc3339).or_else(|error| {
1268            primitive(text)
1269                .map(time::PrimitiveDateTime::assume_utc)
1270                .map_err(|_| error)
1271        })
1272    }
1273}
1274
1275#[cfg(feature = "time")]
1276impl FromSQLiteValue for time::Date {
1277    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1278        Err(DrizzleError::ConversionError(
1279            "cannot convert INTEGER to time::Date".into(),
1280        ))
1281    }
1282
1283    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1284        Self::parse(value, &time::format_description::well_known::Iso8601::DATE).map_err(|e| {
1285            DrizzleError::ConversionError(
1286                format!("cannot parse '{value}' as time::Date: {e}").into(),
1287            )
1288        })
1289    }
1290
1291    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1292        Err(DrizzleError::ConversionError(
1293            "cannot convert REAL to time::Date".into(),
1294        ))
1295    }
1296
1297    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1298        Err(DrizzleError::ConversionError(
1299            "cannot convert BLOB to time::Date".into(),
1300        ))
1301    }
1302}
1303
1304#[cfg(feature = "time")]
1305impl FromSQLiteValue for time::Time {
1306    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1307        Err(DrizzleError::ConversionError(
1308            "cannot convert INTEGER to time::Time".into(),
1309        ))
1310    }
1311
1312    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1313        time_text::time(value).map_err(|e| {
1314            DrizzleError::ConversionError(
1315                format!("cannot parse '{value}' as time::Time: {e}").into(),
1316            )
1317        })
1318    }
1319
1320    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1321        Err(DrizzleError::ConversionError(
1322            "cannot convert REAL to time::Time".into(),
1323        ))
1324    }
1325
1326    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1327        Err(DrizzleError::ConversionError(
1328            "cannot convert BLOB to time::Time".into(),
1329        ))
1330    }
1331}
1332
1333#[cfg(feature = "time")]
1334impl FromSQLiteValue for time::PrimitiveDateTime {
1335    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1336        Err(DrizzleError::ConversionError(
1337            "cannot convert INTEGER to time::PrimitiveDateTime".into(),
1338        ))
1339    }
1340
1341    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1342        time_text::primitive(value).map_err(|e| {
1343            DrizzleError::ConversionError(
1344                format!("cannot parse '{value}' as time::PrimitiveDateTime: {e}").into(),
1345            )
1346        })
1347    }
1348
1349    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1350        Err(DrizzleError::ConversionError(
1351            "cannot convert REAL to time::PrimitiveDateTime".into(),
1352        ))
1353    }
1354
1355    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1356        Err(DrizzleError::ConversionError(
1357            "cannot convert BLOB to time::PrimitiveDateTime".into(),
1358        ))
1359    }
1360}
1361
1362#[cfg(feature = "time")]
1363impl FromSQLiteValue for time::OffsetDateTime {
1364    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1365        Err(DrizzleError::ConversionError(
1366            "cannot convert INTEGER to time::OffsetDateTime".into(),
1367        ))
1368    }
1369
1370    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1371        time_text::offset(value).map_err(|e| {
1372            DrizzleError::ConversionError(
1373                format!("cannot parse '{value}' as time::OffsetDateTime: {e}").into(),
1374            )
1375        })
1376    }
1377
1378    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1379        Err(DrizzleError::ConversionError(
1380            "cannot convert REAL to time::OffsetDateTime".into(),
1381        ))
1382    }
1383
1384    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1385        Err(DrizzleError::ConversionError(
1386            "cannot convert BLOB to time::OffsetDateTime".into(),
1387        ))
1388    }
1389}
1390
1391// =============================================================================
1392// jiff (parse from ISO 8601 text)
1393// =============================================================================
1394
1395/// Parses SQLite text as the jiff value named `name`.
1396#[cfg(feature = "jiff")]
1397fn parse_jiff<T: core::str::FromStr<Err = jiff::Error>>(
1398    value: &str,
1399    name: &str,
1400) -> Result<T, DrizzleError> {
1401    value.parse().map_err(|e: jiff::Error| {
1402        DrizzleError::ConversionError(format!("cannot parse '{value}' as {name}: {e}").into())
1403    })
1404}
1405
1406/// Implements [`FromSQLiteValue`] for jiff types, which SQLite stores as text.
1407#[cfg(feature = "jiff")]
1408macro_rules! impl_from_sqlite_value_jiff {
1409    ($($ty:ty => $name:literal, $parse:expr;)+) => {$(
1410        impl FromSQLiteValue for $ty {
1411            fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1412                Err(DrizzleError::ConversionError(
1413                    concat!("cannot convert INTEGER to ", $name).into(),
1414                ))
1415            }
1416
1417            fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1418                $parse(value)
1419            }
1420
1421            fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1422                Err(DrizzleError::ConversionError(
1423                    concat!("cannot convert REAL to ", $name).into(),
1424                ))
1425            }
1426
1427            fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1428                Err(DrizzleError::ConversionError(
1429                    concat!("cannot convert BLOB to ", $name).into(),
1430                ))
1431            }
1432        }
1433    )+};
1434}
1435
1436#[cfg(feature = "jiff")]
1437impl_from_sqlite_value_jiff! {
1438    jiff::civil::Date => "jiff::civil::Date",
1439        |value| parse_jiff(value, "jiff::civil::Date");
1440    jiff::civil::Time => "jiff::civil::Time",
1441        |value| parse_jiff(value, "jiff::civil::Time");
1442    jiff::civil::DateTime => "jiff::civil::DateTime",
1443        |value| parse_jiff(value, "jiff::civil::DateTime");
1444    // RFC 3339 as the conversion writes it; text without an offset (as
1445    // SQLite's own `CURRENT_TIMESTAMP` writes) is UTC.
1446    jiff::Timestamp => "jiff::Timestamp", |value: &str| {
1447        value.parse().or_else(|_| {
1448            let civil: jiff::civil::DateTime = parse_jiff(value, "jiff::Timestamp")?;
1449            jiff::tz::Offset::UTC.to_timestamp(civil).map_err(|e| {
1450                DrizzleError::ConversionError(
1451                    format!("cannot convert '{value}' to jiff::Timestamp: {e}").into(),
1452                )
1453            })
1454        })
1455    };
1456}
1457
1458// =============================================================================
1459// Decimal (parse from text)
1460// =============================================================================
1461
1462#[cfg(feature = "rust-decimal")]
1463impl FromSQLiteValue for rust_decimal::Decimal {
1464    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
1465        Ok(Self::from(value))
1466    }
1467
1468    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1469        value.parse().map_err(|e| {
1470            DrizzleError::ConversionError(format!("cannot parse '{value}' as Decimal: {e}").into())
1471        })
1472    }
1473
1474    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
1475        Self::try_from(value).map_err(|e| {
1476            DrizzleError::ConversionError(
1477                format!("cannot convert REAL {value} to Decimal: {e}").into(),
1478            )
1479        })
1480    }
1481
1482    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1483        Err(DrizzleError::ConversionError(
1484            "cannot convert BLOB to Decimal".into(),
1485        ))
1486    }
1487}
1488
1489// =============================================================================
1490// Duration types
1491// =============================================================================
1492
1493#[cfg(feature = "chrono")]
1494impl FromSQLiteValue for chrono::Duration {
1495    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
1496        Ok(Self::seconds(value))
1497    }
1498
1499    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1500        let error = || {
1501            DrizzleError::ConversionError(
1502                format!("cannot parse '{value}' as chrono::Duration").into(),
1503            )
1504        };
1505        let (negative, secs, nanos) = crate::values::duration::parse(value).ok_or_else(error)?;
1506        let secs = i64::try_from(secs).map_err(|_| error())?;
1507        let duration = Self::new(secs, nanos).ok_or_else(error)?;
1508        Ok(if negative { -duration } else { duration })
1509    }
1510
1511    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
1512        let millis: i64 = format!("{:.0}", value * 1000.0).parse().map_err(|e| {
1513            DrizzleError::ConversionError(
1514                format!("cannot convert REAL {value} to chrono::Duration: {e}").into(),
1515            )
1516        })?;
1517        Ok(Self::milliseconds(millis))
1518    }
1519
1520    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1521        Err(DrizzleError::ConversionError(
1522            "cannot convert BLOB to chrono::Duration".into(),
1523        ))
1524    }
1525}
1526
1527#[cfg(feature = "time")]
1528impl FromSQLiteValue for time::Duration {
1529    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
1530        Ok(Self::seconds(value))
1531    }
1532
1533    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1534        let error = || {
1535            DrizzleError::ConversionError(
1536                format!("cannot parse '{value}' as time::Duration").into(),
1537            )
1538        };
1539        let (negative, secs, nanos) = crate::values::duration::parse(value).ok_or_else(error)?;
1540        let secs = i64::try_from(secs).map_err(|_| error())?;
1541        // `nanos` is below 1_000_000_000, so it always fits in an i32.
1542        let duration = Self::new(secs, nanos as i32);
1543        Ok(if negative { -duration } else { duration })
1544    }
1545
1546    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
1547        Ok(Self::seconds_f64(value))
1548    }
1549
1550    fn from_sqlite_blob(_value: &[u8]) -> Result<Self, DrizzleError> {
1551        Err(DrizzleError::ConversionError(
1552            "cannot convert BLOB to time::Duration".into(),
1553        ))
1554    }
1555}
1556
1557// =============================================================================
1558// JSON support (serde_json::Value)
1559// =============================================================================
1560
1561#[cfg(feature = "serde")]
1562impl FromSQLiteValue for serde_json::Value {
1563    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
1564        Ok(Self::Number(value.into()))
1565    }
1566
1567    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1568        serde_json::from_str(value).map_err(|e| {
1569            DrizzleError::ConversionError(format!("cannot parse '{value}' as JSON: {e}").into())
1570        })
1571    }
1572
1573    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
1574        serde_json::Number::from_f64(value)
1575            .map(serde_json::Value::Number)
1576            .ok_or_else(|| {
1577                DrizzleError::ConversionError(
1578                    format!("cannot convert non-finite REAL {value} to JSON").into(),
1579                )
1580            })
1581    }
1582
1583    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
1584        serde_json::from_slice(value).map_err(|e| {
1585            DrizzleError::ConversionError(format!("cannot parse BLOB as JSON: {e}").into())
1586        })
1587    }
1588}
1589
1590// =============================================================================
1591// ArrayVec/ArrayString support
1592// =============================================================================
1593
1594#[cfg(feature = "arrayvec")]
1595impl<const N: usize> FromSQLiteValue for arrayvec::ArrayString<N> {
1596    fn from_sqlite_integer(value: i64) -> Result<Self, DrizzleError> {
1597        let s = value.to_string();
1598        Self::from(&s).map_err(|_| {
1599            DrizzleError::ConversionError(
1600                format!(
1601                    "String length {} exceeds ArrayString capacity {}",
1602                    s.len(),
1603                    N
1604                )
1605                .into(),
1606            )
1607        })
1608    }
1609
1610    fn from_sqlite_text(value: &str) -> Result<Self, DrizzleError> {
1611        Self::from(value).map_err(|_| {
1612            DrizzleError::ConversionError(
1613                format!(
1614                    "Text length {} exceeds ArrayString capacity {}",
1615                    value.len(),
1616                    N
1617                )
1618                .into(),
1619            )
1620        })
1621    }
1622
1623    fn from_sqlite_real(value: f64) -> Result<Self, DrizzleError> {
1624        let s = value.to_string();
1625        Self::from(&s).map_err(|_| {
1626            DrizzleError::ConversionError(
1627                format!(
1628                    "String length {} exceeds ArrayString capacity {}",
1629                    s.len(),
1630                    N
1631                )
1632                .into(),
1633            )
1634        })
1635    }
1636
1637    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
1638        let s = String::from_utf8(value.to_vec())
1639            .map_err(|e| DrizzleError::ConversionError(format!("invalid UTF-8: {e}").into()))?;
1640        Self::from(&s).map_err(|_| {
1641            DrizzleError::ConversionError(
1642                format!(
1643                    "String length {} exceeds ArrayString capacity {}",
1644                    s.len(),
1645                    N
1646                )
1647                .into(),
1648            )
1649        })
1650    }
1651}
1652
1653#[cfg(feature = "arrayvec")]
1654impl<const N: usize> FromSQLiteValue for arrayvec::ArrayVec<u8, N> {
1655    fn from_sqlite_integer(_value: i64) -> Result<Self, DrizzleError> {
1656        Err(DrizzleError::ConversionError(
1657            "cannot convert INTEGER to ArrayVec<u8>, use BLOB".into(),
1658        ))
1659    }
1660
1661    fn from_sqlite_text(_value: &str) -> Result<Self, DrizzleError> {
1662        Err(DrizzleError::ConversionError(
1663            "cannot convert TEXT to ArrayVec<u8>, use BLOB".into(),
1664        ))
1665    }
1666
1667    fn from_sqlite_real(_value: f64) -> Result<Self, DrizzleError> {
1668        Err(DrizzleError::ConversionError(
1669            "cannot convert REAL to ArrayVec<u8>, use BLOB".into(),
1670        ))
1671    }
1672
1673    fn from_sqlite_blob(value: &[u8]) -> Result<Self, DrizzleError> {
1674        Self::try_from(value).map_err(|_| {
1675            DrizzleError::ConversionError(
1676                format!(
1677                    "Blob length {} exceeds ArrayVec capacity {}",
1678                    value.len(),
1679                    N
1680                )
1681                .into(),
1682            )
1683        })
1684    }
1685}