Skip to main content

burn_dataset/dataset/sqlite/
de.rs

1//! Deserialization of a database row into a user type.
2//!
3//! Turso has no serde integration, so this reimplements the mapping `serde_rusqlite` used to
4//! provide: a row is handed to serde as a map from column name to column value. That is what lets
5//! a target struct name a subset of the table's columns, in any order.
6
7use serde::de::value::{MapDeserializer, SeqDeserializer};
8use serde::de::{DeserializeOwned, Deserializer, IntoDeserializer, Visitor};
9use serde::forward_to_deserialize_any;
10use turso::{Row, Value};
11
12/// Error raised while deserializing a row into the target type.
13#[derive(thiserror::Error, Debug)]
14pub enum RowError {
15    /// A column could not be read out of the row.
16    #[error("column `{column}`: {source}")]
17    Column {
18        /// Name of the offending column.
19        column: String,
20        /// The underlying database error.
21        source: turso::Error,
22    },
23
24    /// Serde could not build the target type from the row.
25    #[error("{0}")]
26    Message(String),
27}
28
29impl serde::de::Error for RowError {
30    fn custom<T: core::fmt::Display>(msg: T) -> Self {
31        RowError::Message(msg.to_string())
32    }
33}
34
35/// Deserializes a row into `I`, matching the fields of `I` against `columns` by name.
36///
37/// `columns` must line up positionally with the row's columns, which is exactly what
38/// [`turso::Statement::column_names`] reports for the statement that produced the row.
39pub fn from_row_with_columns<I: DeserializeOwned>(
40    row: &Row,
41    columns: &[String],
42) -> Result<I, RowError> {
43    let mut entries = Vec::with_capacity(columns.len());
44    for (index, column) in columns.iter().enumerate() {
45        let value = row.get_value(index).map_err(|source| RowError::Column {
46            column: column.clone(),
47            source,
48        })?;
49        entries.push((column.as_str(), ValueDeserializer(value)));
50    }
51
52    I::deserialize(RowDeserializer { entries })
53}
54
55/// Deserializes a complete row, either by column name or position depending on the target type.
56struct RowDeserializer<'a> {
57    entries: Vec<(&'a str, ValueDeserializer)>,
58}
59
60impl RowDeserializer<'_> {
61    fn into_first_value(self) -> Result<ValueDeserializer, RowError> {
62        self.entries
63            .into_iter()
64            .next()
65            .map(|(_, value)| value)
66            .ok_or_else(|| RowError::Message("cannot deserialize an empty row".to_string()))
67    }
68}
69
70impl<'de> Deserializer<'de> for RowDeserializer<'_> {
71    type Error = RowError;
72
73    fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, RowError> {
74        self.into_first_value()?.deserialize_any(visitor)
75    }
76
77    fn deserialize_bool<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, RowError> {
78        self.into_first_value()?.deserialize_bool(visitor)
79    }
80
81    fn deserialize_f32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, RowError> {
82        self.into_first_value()?.deserialize_f32(visitor)
83    }
84
85    fn deserialize_f64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, RowError> {
86        self.into_first_value()?.deserialize_f64(visitor)
87    }
88
89    fn deserialize_byte_buf<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, RowError> {
90        self.into_first_value()?.deserialize_byte_buf(visitor)
91    }
92
93    fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, RowError> {
94        self.into_first_value()?.deserialize_option(visitor)
95    }
96
97    fn deserialize_unit<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, RowError> {
98        self.into_first_value()?.deserialize_unit(visitor)
99    }
100
101    fn deserialize_unit_struct<V: Visitor<'de>>(
102        self,
103        name: &'static str,
104        visitor: V,
105    ) -> Result<V::Value, RowError> {
106        self.into_first_value()?
107            .deserialize_unit_struct(name, visitor)
108    }
109
110    fn deserialize_newtype_struct<V: Visitor<'de>>(
111        self,
112        _name: &'static str,
113        visitor: V,
114    ) -> Result<V::Value, RowError> {
115        visitor.visit_newtype_struct(self.into_first_value()?)
116    }
117
118    fn deserialize_tuple<V: Visitor<'de>>(
119        self,
120        _len: usize,
121        visitor: V,
122    ) -> Result<V::Value, RowError> {
123        let values = self.entries.into_iter().map(|(_, value)| value);
124        visitor.visit_seq(SeqDeserializer::new(values))
125    }
126
127    fn deserialize_map<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, RowError> {
128        visitor.visit_map(MapDeserializer::new(self.entries.into_iter()))
129    }
130
131    fn deserialize_struct<V: Visitor<'de>>(
132        self,
133        _name: &'static str,
134        _fields: &'static [&'static str],
135        visitor: V,
136    ) -> Result<V::Value, RowError> {
137        self.deserialize_map(visitor)
138    }
139
140    fn deserialize_enum<V: Visitor<'de>>(
141        self,
142        name: &'static str,
143        variants: &'static [&'static str],
144        visitor: V,
145    ) -> Result<V::Value, RowError> {
146        self.into_first_value()?
147            .deserialize_enum(name, variants, visitor)
148    }
149
150    forward_to_deserialize_any! {
151        i8 i16 i32 i64 u8 u16 u32 u64 char str string bytes
152        seq tuple_struct identifier ignored_any
153    }
154}
155
156/// Deserializes a single column value.
157struct ValueDeserializer(Value);
158
159impl<'de> IntoDeserializer<'de, RowError> for ValueDeserializer {
160    type Deserializer = Self;
161
162    fn into_deserializer(self) -> Self {
163        self
164    }
165}
166
167impl<'de> Deserializer<'de> for ValueDeserializer {
168    type Error = RowError;
169
170    fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, RowError> {
171        match self.0 {
172            Value::Null => visitor.visit_none(),
173            Value::Integer(value) => visitor.visit_i64(value),
174            Value::Real(value) => visitor.visit_f64(value),
175            Value::Text(value) => visitor.visit_string(value),
176            // A `Vec<u8>` field derives as a sequence rather than as bytes, so a blob has to be
177            // offered element by element for the common `column_bytes: Vec<u8>` case to work.
178            // Fields tagged `#[serde(with = "serde_bytes")]` take the cheaper path below instead.
179            Value::Blob(value) => visitor.visit_seq(value.into_deserializer()),
180        }
181    }
182
183    /// SQLite has no boolean type; booleans arrive as integers.
184    fn deserialize_bool<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, RowError> {
185        match self.0 {
186            Value::Integer(value) => visitor.visit_bool(value != 0),
187            Value::Real(value) => visitor.visit_bool(value != 0.0),
188            _ => self.deserialize_any(visitor),
189        }
190    }
191
192    /// A NULL read into a bare float becomes NaN, as it did under `serde_rusqlite`. Deserializing
193    /// it into an `Option<f32>` instead yields `None`.
194    fn deserialize_f32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, RowError> {
195        match self.0 {
196            Value::Null => visitor.visit_f32(f32::NAN),
197            _ => self.deserialize_any(visitor),
198        }
199    }
200
201    /// See [`Self::deserialize_f32`].
202    fn deserialize_f64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, RowError> {
203        match self.0 {
204            Value::Null => visitor.visit_f64(f64::NAN),
205            _ => self.deserialize_any(visitor),
206        }
207    }
208
209    /// Hands a blob over as bytes, moving it instead of walking it element by element.
210    fn deserialize_byte_buf<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, RowError> {
211        match self.0 {
212            Value::Blob(value) => visitor.visit_byte_buf(value),
213            _ => self.deserialize_any(visitor),
214        }
215    }
216
217    fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, RowError> {
218        match self.0 {
219            Value::Null => visitor.visit_none(),
220            _ => visitor.visit_some(self),
221        }
222    }
223
224    fn deserialize_unit<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, RowError> {
225        match self.0 {
226            Value::Null => visitor.visit_unit(),
227            _ => self.deserialize_any(visitor),
228        }
229    }
230
231    fn deserialize_unit_struct<V: Visitor<'de>>(
232        self,
233        name: &'static str,
234        visitor: V,
235    ) -> Result<V::Value, RowError> {
236        match self.0 {
237            Value::Text(value) if value == name => visitor.visit_unit(),
238            _ => self.deserialize_any(visitor),
239        }
240    }
241
242    fn deserialize_newtype_struct<V: Visitor<'de>>(
243        self,
244        _name: &'static str,
245        visitor: V,
246    ) -> Result<V::Value, RowError> {
247        visitor.visit_newtype_struct(self)
248    }
249
250    fn deserialize_enum<V: Visitor<'de>>(
251        self,
252        _name: &'static str,
253        _variants: &'static [&'static str],
254        visitor: V,
255    ) -> Result<V::Value, RowError> {
256        match self.0 {
257            Value::Text(value) => visitor.visit_enum(value.into_deserializer()),
258            _ => self.deserialize_any(visitor),
259        }
260    }
261
262    forward_to_deserialize_any! {
263        i8 i16 i32 i64 u8 u16 u32 u64 char str string bytes
264        seq tuple tuple_struct map struct identifier ignored_any
265    }
266}