drizzle_sqlite/values/
owned.rs

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