drizzle_sqlite/
values.rs

1//! SQLite value conversion traits and types
2
3use crate::traits::FromSQLiteValue;
4use drizzle_core::{SQL, ToSQL, error::DrizzleError};
5
6mod insert;
7mod owned;
8pub use insert::*;
9pub use owned::OwnedSQLiteValue;
10
11#[cfg(feature = "rusqlite")]
12use rusqlite::types::FromSql;
13#[cfg(feature = "turso")]
14use turso::IntoValue;
15#[cfg(feature = "uuid")]
16use uuid::Uuid;
17
18use std::borrow::Cow;
19
20//------------------------------------------------------------------------------
21// SQLiteValue Definition
22//------------------------------------------------------------------------------
23
24/// Represents a SQLite value
25#[derive(Debug, Clone, PartialEq, PartialOrd, Default)]
26pub enum SQLiteValue<'a> {
27    /// Integer value (i64)
28    Integer(i64),
29    /// Real value (f64)
30    Real(f64),
31    /// Text value (borrowed or owned string)
32    Text(Cow<'a, str>),
33    /// Blob value (borrowed or owned binary data)
34    Blob(Cow<'a, [u8]>),
35    /// NULL value
36    #[default]
37    Null,
38}
39
40impl<'a> SQLiteValue<'a> {
41    /// Convert this SQLite value to a Rust type using the `FromSQLiteValue` trait.
42    ///
43    /// This provides a unified conversion interface for all types that implement
44    /// `FromSQLiteValue`, including primitives and enum types.
45    ///
46    /// # Example
47    /// ```ignore
48    /// let value = SQLiteValue::Integer(42);
49    /// let num: i64 = value.convert()?;
50    /// ```
51    pub fn convert<T: FromSQLiteValue>(self) -> Result<T, DrizzleError> {
52        match self {
53            SQLiteValue::Integer(i) => T::from_sqlite_integer(i),
54            SQLiteValue::Text(s) => T::from_sqlite_text(&s),
55            SQLiteValue::Real(r) => T::from_sqlite_real(r),
56            SQLiteValue::Blob(b) => T::from_sqlite_blob(&b),
57            SQLiteValue::Null => T::from_sqlite_null(),
58        }
59    }
60
61    /// Convert a reference to this SQLite value to a Rust type.
62    pub fn convert_ref<T: FromSQLiteValue>(&self) -> Result<T, DrizzleError> {
63        match self {
64            SQLiteValue::Integer(i) => T::from_sqlite_integer(*i),
65            SQLiteValue::Text(s) => T::from_sqlite_text(s),
66            SQLiteValue::Real(r) => T::from_sqlite_real(*r),
67            SQLiteValue::Blob(b) => T::from_sqlite_blob(b),
68            SQLiteValue::Null => T::from_sqlite_null(),
69        }
70    }
71}
72
73impl<'a> ToSQL<'a, SQLiteValue<'a>> for SQLiteValue<'a> {
74    fn to_sql(&self) -> SQL<'a, SQLiteValue<'a>> {
75        SQL::param(self.clone())
76    }
77}
78impl<'a> From<OwnedSQLiteValue> for SQLiteValue<'a> {
79    fn from(value: OwnedSQLiteValue) -> Self {
80        match value {
81            OwnedSQLiteValue::Integer(f) => SQLiteValue::Integer(f),
82            OwnedSQLiteValue::Real(r) => SQLiteValue::Real(r),
83            OwnedSQLiteValue::Text(v) => SQLiteValue::Text(Cow::Owned(v)),
84            OwnedSQLiteValue::Blob(v) => SQLiteValue::Blob(Cow::Owned(v.into())),
85            OwnedSQLiteValue::Null => SQLiteValue::Null,
86        }
87    }
88}
89impl<'a> From<&'a OwnedSQLiteValue> for SQLiteValue<'a> {
90    fn from(value: &'a OwnedSQLiteValue) -> Self {
91        match value {
92            OwnedSQLiteValue::Integer(f) => SQLiteValue::Integer(*f),
93            OwnedSQLiteValue::Real(r) => SQLiteValue::Real(*r),
94            OwnedSQLiteValue::Text(v) => SQLiteValue::Text(Cow::Borrowed(v)),
95            OwnedSQLiteValue::Blob(v) => SQLiteValue::Blob(Cow::Borrowed(v)),
96            OwnedSQLiteValue::Null => SQLiteValue::Null,
97        }
98    }
99}
100impl<'a> From<&'a SQLiteValue<'a>> for SQLiteValue<'a> {
101    fn from(value: &'a SQLiteValue<'a>) -> Self {
102        match value {
103            SQLiteValue::Integer(f) => SQLiteValue::Integer(*f),
104            SQLiteValue::Real(r) => SQLiteValue::Real(*r),
105            SQLiteValue::Text(v) => SQLiteValue::Text(Cow::Borrowed(v)),
106            SQLiteValue::Blob(v) => SQLiteValue::Blob(Cow::Borrowed(v)),
107            SQLiteValue::Null => SQLiteValue::Null,
108        }
109    }
110}
111impl<'a> From<Cow<'a, SQLiteValue<'a>>> for SQLiteValue<'a> {
112    fn from(value: Cow<'a, SQLiteValue<'a>>) -> Self {
113        match value {
114            Cow::Borrowed(r) => r.into(),
115            Cow::Owned(o) => o,
116        }
117    }
118}
119impl<'a> From<&'a Cow<'a, SQLiteValue<'a>>> for SQLiteValue<'a> {
120    fn from(value: &'a Cow<'a, SQLiteValue<'a>>) -> Self {
121        match value {
122            Cow::Borrowed(r) => (*r).into(),
123            Cow::Owned(o) => o.into(),
124        }
125    }
126}
127
128impl<'a> std::fmt::Display for SQLiteValue<'a> {
129    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130        let value = match self {
131            SQLiteValue::Integer(i) => i.to_string(),
132            SQLiteValue::Real(r) => r.to_string(),
133            SQLiteValue::Text(cow) => cow.to_string(),
134            SQLiteValue::Blob(cow) => String::from_utf8_lossy(cow).to_string(),
135            SQLiteValue::Null => String::new(),
136        };
137        write!(f, "{value}")
138    }
139}
140
141impl<'a> From<SQL<'a, SQLiteValue<'a>>> for SQLiteValue<'a> {
142    fn from(_value: SQL<'a, SQLiteValue<'a>>) -> Self {
143        unimplemented!()
144    }
145}
146
147impl<'a> FromIterator<OwnedSQLiteValue> for Vec<SQLiteValue<'a>> {
148    fn from_iter<T: IntoIterator<Item = OwnedSQLiteValue>>(iter: T) -> Self {
149        iter.into_iter().map(SQLiteValue::from).collect()
150    }
151}
152
153impl<'a> FromIterator<&'a OwnedSQLiteValue> for Vec<SQLiteValue<'a>> {
154    fn from_iter<T: IntoIterator<Item = &'a OwnedSQLiteValue>>(iter: T) -> Self {
155        iter.into_iter().map(SQLiteValue::from).collect()
156    }
157}
158
159//------------------------------------------------------------------------------
160// Database Driver Implementations
161//------------------------------------------------------------------------------
162
163// Implement rusqlite::ToSql for SQLiteValue when the rusqlite feature is enabled
164#[cfg(feature = "rusqlite")]
165impl<'a> rusqlite::ToSql for SQLiteValue<'a> {
166    fn to_sql(&self) -> ::rusqlite::Result<::rusqlite::types::ToSqlOutput<'_>> {
167        match self {
168            SQLiteValue::Null => Ok(rusqlite::types::ToSqlOutput::Owned(
169                rusqlite::types::Value::Null,
170            )),
171            SQLiteValue::Integer(i) => Ok(rusqlite::types::ToSqlOutput::Owned(
172                rusqlite::types::Value::Integer(*i),
173            )),
174            SQLiteValue::Real(f) => Ok(rusqlite::types::ToSqlOutput::Owned(
175                rusqlite::types::Value::Real(*f),
176            )),
177            SQLiteValue::Text(s) => Ok(rusqlite::types::ToSqlOutput::Borrowed(
178                rusqlite::types::ValueRef::Text(s.as_bytes()),
179            )),
180            SQLiteValue::Blob(b) => Ok(rusqlite::types::ToSqlOutput::Borrowed(
181                rusqlite::types::ValueRef::Blob(b.as_ref()),
182            )),
183        }
184    }
185}
186
187#[cfg(feature = "rusqlite")]
188impl<'a> FromSql for SQLiteValue<'a> {
189    fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
190        let result = match value {
191            rusqlite::types::ValueRef::Null => SQLiteValue::Null,
192            rusqlite::types::ValueRef::Integer(i) => SQLiteValue::Integer(i),
193            rusqlite::types::ValueRef::Real(r) => SQLiteValue::Real(r),
194            rusqlite::types::ValueRef::Text(items) => {
195                SQLiteValue::Text(String::from_utf8_lossy(items).into_owned().into())
196            }
197            rusqlite::types::ValueRef::Blob(items) => SQLiteValue::Blob(items.to_vec().into()),
198        };
199        Ok(result)
200    }
201}
202
203#[cfg(feature = "rusqlite")]
204impl<'a> From<rusqlite::types::Value> for SQLiteValue<'a> {
205    fn from(value: rusqlite::types::Value) -> Self {
206        match value {
207            rusqlite::types::Value::Null => SQLiteValue::Null,
208            rusqlite::types::Value::Integer(i) => SQLiteValue::Integer(i),
209            rusqlite::types::Value::Real(r) => SQLiteValue::Real(r),
210            rusqlite::types::Value::Text(s) => SQLiteValue::Text(s.into()),
211            rusqlite::types::Value::Blob(b) => SQLiteValue::Blob(b.into()),
212        }
213    }
214}
215
216#[cfg(feature = "rusqlite")]
217impl<'a> From<rusqlite::types::ValueRef<'a>> for SQLiteValue<'a> {
218    fn from(value: rusqlite::types::ValueRef<'a>) -> Self {
219        match value {
220            rusqlite::types::ValueRef::Null => SQLiteValue::Null,
221            rusqlite::types::ValueRef::Integer(i) => SQLiteValue::Integer(i),
222            rusqlite::types::ValueRef::Real(r) => SQLiteValue::Real(r),
223            rusqlite::types::ValueRef::Text(items) => {
224                SQLiteValue::Text(String::from_utf8_lossy(items).into_owned().into())
225            }
226            rusqlite::types::ValueRef::Blob(items) => SQLiteValue::Blob(items.to_vec().into()),
227        }
228    }
229}
230
231#[cfg(feature = "turso")]
232impl<'a> IntoValue for SQLiteValue<'a> {
233    fn into_value(self) -> turso::Result<turso::Value> {
234        let result = match self {
235            SQLiteValue::Integer(i) => turso::Value::Integer(i),
236            SQLiteValue::Real(r) => turso::Value::Real(r),
237            SQLiteValue::Text(cow) => turso::Value::Text(cow.into()),
238            SQLiteValue::Blob(cow) => turso::Value::Blob(cow.into()),
239            SQLiteValue::Null => turso::Value::Null,
240        };
241        Ok(result)
242    }
243}
244
245#[cfg(feature = "turso")]
246impl<'a> IntoValue for &SQLiteValue<'a> {
247    fn into_value(self) -> turso::Result<turso::Value> {
248        let result = match self {
249            SQLiteValue::Integer(i) => turso::Value::Integer(*i),
250            SQLiteValue::Real(r) => turso::Value::Real(*r),
251            SQLiteValue::Text(cow) => turso::Value::Text(cow.to_string()),
252            SQLiteValue::Blob(cow) => turso::Value::Blob(cow.to_vec()),
253            SQLiteValue::Null => turso::Value::Null,
254        };
255        Ok(result)
256    }
257}
258
259#[cfg(feature = "turso")]
260impl<'a> From<SQLiteValue<'a>> for turso::Value {
261    fn from(value: SQLiteValue<'a>) -> Self {
262        match value {
263            SQLiteValue::Integer(i) => turso::Value::Integer(i),
264            SQLiteValue::Real(r) => turso::Value::Real(r),
265            SQLiteValue::Text(cow) => turso::Value::Text(cow.to_string()),
266            SQLiteValue::Blob(cow) => turso::Value::Blob(cow.to_vec()),
267            SQLiteValue::Null => turso::Value::Null,
268        }
269    }
270}
271
272#[cfg(feature = "turso")]
273impl<'a> From<&SQLiteValue<'a>> for turso::Value {
274    fn from(value: &SQLiteValue<'a>) -> Self {
275        match value {
276            SQLiteValue::Integer(i) => turso::Value::Integer(*i),
277            SQLiteValue::Real(r) => turso::Value::Real(*r),
278            SQLiteValue::Text(cow) => turso::Value::Text(cow.to_string()),
279            SQLiteValue::Blob(cow) => turso::Value::Blob(cow.to_vec()),
280            SQLiteValue::Null => turso::Value::Null,
281        }
282    }
283}
284
285#[cfg(feature = "libsql")]
286impl<'a> From<SQLiteValue<'a>> for libsql::Value {
287    fn from(value: SQLiteValue<'a>) -> Self {
288        match value {
289            SQLiteValue::Integer(i) => libsql::Value::Integer(i),
290            SQLiteValue::Real(r) => libsql::Value::Real(r),
291            SQLiteValue::Text(cow) => libsql::Value::Text(cow.to_string()),
292            SQLiteValue::Blob(cow) => libsql::Value::Blob(cow.to_vec()),
293            SQLiteValue::Null => libsql::Value::Null,
294        }
295    }
296}
297
298#[cfg(feature = "libsql")]
299impl<'a> From<&SQLiteValue<'a>> for libsql::Value {
300    fn from(value: &SQLiteValue<'a>) -> Self {
301        match value {
302            SQLiteValue::Integer(i) => libsql::Value::Integer(*i),
303            SQLiteValue::Real(r) => libsql::Value::Real(*r),
304            SQLiteValue::Text(cow) => libsql::Value::Text(cow.to_string()),
305            SQLiteValue::Blob(cow) => libsql::Value::Blob(cow.to_vec()),
306            SQLiteValue::Null => libsql::Value::Null,
307        }
308    }
309}
310
311// Implement core traits required by Drizzle
312impl<'a> drizzle_core::traits::SQLParam for SQLiteValue<'a> {}
313
314impl<'a> From<SQLiteValue<'a>> for SQL<'a, SQLiteValue<'a>> {
315    fn from(value: SQLiteValue<'a>) -> Self {
316        SQL::param(value)
317    }
318}
319
320//------------------------------------------------------------------------------
321// From<T> implementations
322// Macro-based to reduce boilerplate
323//------------------------------------------------------------------------------
324
325/// Macro to implement From<integer> for SQLiteValue (converts to INTEGER)
326macro_rules! impl_from_int_for_sqlite_value {
327    ($($ty:ty),* $(,)?) => {
328        $(
329            impl<'a> From<$ty> for SQLiteValue<'a> {
330                #[inline]
331                fn from(value: $ty) -> Self {
332                    SQLiteValue::Integer(value as i64)
333                }
334            }
335
336            impl<'a> From<&$ty> for SQLiteValue<'a> {
337                #[inline]
338                fn from(value: &$ty) -> Self {
339                    SQLiteValue::Integer(*value as i64)
340                }
341            }
342        )*
343    };
344}
345
346/// Macro to implement From<float> for SQLiteValue (converts to REAL)
347macro_rules! impl_from_float_for_sqlite_value {
348    ($($ty:ty),* $(,)?) => {
349        $(
350            impl<'a> From<$ty> for SQLiteValue<'a> {
351                #[inline]
352                fn from(value: $ty) -> Self {
353                    SQLiteValue::Real(value as f64)
354                }
355            }
356
357            impl<'a> From<&$ty> for SQLiteValue<'a> {
358                #[inline]
359                fn from(value: &$ty) -> Self {
360                    SQLiteValue::Real(*value as f64)
361                }
362            }
363        )*
364    };
365}
366
367// Integer types -> SQLiteValue::Integer
368impl_from_int_for_sqlite_value!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, bool);
369
370// Float types -> SQLiteValue::Real
371impl_from_float_for_sqlite_value!(f32, f64);
372
373// --- String Types ---
374
375impl<'a> From<&'a str> for SQLiteValue<'a> {
376    fn from(value: &'a str) -> Self {
377        SQLiteValue::Text(Cow::Borrowed(value))
378    }
379}
380
381impl<'a> From<String> for SQLiteValue<'a> {
382    fn from(value: String) -> Self {
383        SQLiteValue::Text(Cow::Owned(value))
384    }
385}
386
387impl<'a> From<&'a String> for SQLiteValue<'a> {
388    fn from(value: &'a String) -> Self {
389        SQLiteValue::Text(Cow::Borrowed(value))
390    }
391}
392
393// --- Binary Data ---
394
395impl<'a> From<&'a [u8]> for SQLiteValue<'a> {
396    fn from(value: &'a [u8]) -> Self {
397        SQLiteValue::Blob(Cow::Borrowed(value))
398    }
399}
400
401impl<'a> From<Vec<u8>> for SQLiteValue<'a> {
402    fn from(value: Vec<u8>) -> Self {
403        SQLiteValue::Blob(Cow::Owned(value))
404    }
405}
406
407// --- UUID ---
408
409#[cfg(feature = "uuid")]
410impl<'a> From<Uuid> for SQLiteValue<'a> {
411    fn from(value: Uuid) -> Self {
412        SQLiteValue::Blob(Cow::Owned(value.as_bytes().to_vec()))
413    }
414}
415
416#[cfg(feature = "uuid")]
417impl<'a> From<&'a Uuid> for SQLiteValue<'a> {
418    fn from(value: &'a Uuid) -> Self {
419        SQLiteValue::Blob(Cow::Borrowed(value.as_bytes()))
420    }
421}
422
423// --- JSON ---
424// Note: JSON types should be handled through serialization in the schema macros
425// These implementations provide fallback support but JSON fields should primarily
426// be serialized to TEXT or BLOB through the field generation logic
427
428// --- Option Types ---
429impl<'a, T> From<Option<T>> for SQLiteValue<'a>
430where
431    T: TryInto<SQLiteValue<'a>>,
432{
433    fn from(value: Option<T>) -> Self {
434        match value {
435            Some(value) => value.try_into().unwrap_or(SQLiteValue::Null),
436            None => SQLiteValue::Null,
437        }
438    }
439}
440
441// --- Cow integration for SQL struct ---
442impl<'a> From<SQLiteValue<'a>> for Cow<'a, SQLiteValue<'a>> {
443    fn from(value: SQLiteValue<'a>) -> Self {
444        Cow::Owned(value)
445    }
446}
447
448impl<'a> From<&'a SQLiteValue<'a>> for Cow<'a, SQLiteValue<'a>> {
449    fn from(value: &'a SQLiteValue<'a>) -> Self {
450        Cow::Borrowed(value)
451    }
452}
453
454//------------------------------------------------------------------------------
455// TryFrom<SQLiteValue> implementations
456// Uses the FromSQLiteValue trait via convert() for unified conversion logic
457//------------------------------------------------------------------------------
458
459/// Macro to implement TryFrom<SQLiteValue> for types implementing FromSQLiteValue
460macro_rules! impl_try_from_sqlite_value {
461    ($($ty:ty),* $(,)?) => {
462        $(
463            impl<'a> TryFrom<SQLiteValue<'a>> for $ty {
464                type Error = DrizzleError;
465
466                #[inline]
467                fn try_from(value: SQLiteValue<'a>) -> Result<Self, Self::Error> {
468                    value.convert()
469                }
470            }
471        )*
472    };
473}
474
475impl_try_from_sqlite_value!(
476    i8,
477    i16,
478    i32,
479    i64,
480    isize,
481    u8,
482    u16,
483    u32,
484    u64,
485    usize,
486    f32,
487    f64,
488    bool,
489    String,
490    Vec<u8>,
491);
492
493#[cfg(feature = "uuid")]
494impl_try_from_sqlite_value!(Uuid);
495
496//------------------------------------------------------------------------------
497// TryFrom<&SQLiteValue> implementations for borrowing without consuming
498// Uses the FromSQLiteValue trait via convert_ref() for unified conversion logic
499//------------------------------------------------------------------------------
500
501/// Macro to implement TryFrom<&SQLiteValue> for types implementing FromSQLiteValue
502macro_rules! impl_try_from_sqlite_value_ref {
503    ($($ty:ty),* $(,)?) => {
504        $(
505            impl<'a> TryFrom<&SQLiteValue<'a>> for $ty {
506                type Error = DrizzleError;
507
508                #[inline]
509                fn try_from(value: &SQLiteValue<'a>) -> Result<Self, Self::Error> {
510                    value.convert_ref()
511                }
512            }
513        )*
514    };
515}
516
517impl_try_from_sqlite_value_ref!(
518    i8,
519    i16,
520    i32,
521    i64,
522    isize,
523    u8,
524    u16,
525    u32,
526    u64,
527    usize,
528    f32,
529    f64,
530    bool,
531    String,
532    Vec<u8>,
533);
534
535#[cfg(feature = "uuid")]
536impl_try_from_sqlite_value_ref!(Uuid);
537
538// --- Borrowed reference types (cannot use FromSQLiteValue) ---
539
540impl<'a> TryFrom<&'a SQLiteValue<'a>> for &'a str {
541    type Error = DrizzleError;
542
543    fn try_from(value: &'a SQLiteValue<'a>) -> Result<Self, Self::Error> {
544        match value {
545            SQLiteValue::Text(cow) => Ok(cow.as_ref()),
546            _ => Err(DrizzleError::ConversionError(
547                format!("Cannot convert {:?} to &str", value).into(),
548            )),
549        }
550    }
551}
552
553impl<'a> TryFrom<&'a SQLiteValue<'a>> for &'a [u8] {
554    type Error = DrizzleError;
555
556    fn try_from(value: &'a SQLiteValue<'a>) -> Result<Self, Self::Error> {
557        match value {
558            SQLiteValue::Blob(cow) => Ok(cow.as_ref()),
559            _ => Err(DrizzleError::ConversionError(
560                format!("Cannot convert {:?} to &[u8]", value).into(),
561            )),
562        }
563    }
564}