bindable.rs

  1use std::{
  2    path::{Path, PathBuf},
  3    sync::Arc,
  4};
  5
  6use anyhow::{Context as _, Result};
  7use util::paths::PathExt;
  8
  9use crate::statement::{SqlType, Statement};
 10
 11/// Define the number of columns that a type occupies in a query/database
 12pub trait StaticColumnCount {
 13    fn column_count() -> usize {
 14        1
 15    }
 16}
 17
 18/// Bind values of different types to placeholders in a prepared SQL statement.
 19pub trait Bind {
 20    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32>;
 21}
 22
 23pub trait Column: Sized {
 24    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)>;
 25}
 26
 27impl StaticColumnCount for bool {}
 28impl Bind for bool {
 29    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
 30        statement
 31            .bind(&self.then_some(1).unwrap_or(0), start_index)
 32            .with_context(|| format!("Failed to bind bool at index {start_index}"))
 33    }
 34}
 35
 36impl Column for bool {
 37    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
 38        i32::column(statement, start_index)
 39            .map(|(i, next_index)| (i != 0, next_index))
 40            .with_context(|| format!("Failed to read bool at index {start_index}"))
 41    }
 42}
 43
 44impl StaticColumnCount for &[u8] {}
 45impl Bind for &[u8] {
 46    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
 47        statement
 48            .bind_blob(start_index, self)
 49            .with_context(|| format!("Failed to bind &[u8] at index {start_index}"))?;
 50        Ok(start_index + 1)
 51    }
 52}
 53
 54impl<const C: usize> StaticColumnCount for &[u8; C] {}
 55impl<const C: usize> Bind for &[u8; C] {
 56    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
 57        statement
 58            .bind_blob(start_index, self.as_slice())
 59            .with_context(|| format!("Failed to bind &[u8; C] at index {start_index}"))?;
 60        Ok(start_index + 1)
 61    }
 62}
 63
 64impl<const C: usize> Column for [u8; C] {
 65    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
 66        let bytes_slice = statement.column_blob(start_index)?;
 67        let array = bytes_slice.try_into()?;
 68        Ok((array, start_index + 1))
 69    }
 70}
 71
 72impl StaticColumnCount for Vec<u8> {}
 73impl Bind for Vec<u8> {
 74    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
 75        statement
 76            .bind_blob(start_index, self)
 77            .with_context(|| format!("Failed to bind Vec<u8> at index {start_index}"))?;
 78        Ok(start_index + 1)
 79    }
 80}
 81
 82impl Column for Vec<u8> {
 83    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
 84        let result = statement
 85            .column_blob(start_index)
 86            .with_context(|| format!("Failed to read Vec<u8> at index {start_index}"))?;
 87
 88        Ok((Vec::from(result), start_index + 1))
 89    }
 90}
 91
 92impl StaticColumnCount for f64 {}
 93impl Bind for f64 {
 94    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
 95        statement
 96            .bind_double(start_index, *self)
 97            .with_context(|| format!("Failed to bind f64 at index {start_index}"))?;
 98        Ok(start_index + 1)
 99    }
100}
101
102impl Column for f64 {
103    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
104        let result = statement
105            .column_double(start_index)
106            .with_context(|| format!("Failed to parse f64 at index {start_index}"))?;
107
108        Ok((result, start_index + 1))
109    }
110}
111
112impl StaticColumnCount for f32 {}
113impl Bind for f32 {
114    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
115        statement
116            .bind_double(start_index, *self as f64)
117            .with_context(|| format!("Failed to bind f64 at index {start_index}"))?;
118        Ok(start_index + 1)
119    }
120}
121
122impl Column for f32 {
123    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
124        let result = statement
125            .column_double(start_index)
126            .with_context(|| format!("Failed to parse f32 at index {start_index}"))?
127            as f32;
128
129        Ok((result, start_index + 1))
130    }
131}
132
133impl StaticColumnCount for i32 {}
134impl Bind for i32 {
135    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
136        statement
137            .bind_int(start_index, *self)
138            .with_context(|| format!("Failed to bind i32 at index {start_index}"))?;
139
140        Ok(start_index + 1)
141    }
142}
143
144impl Column for i32 {
145    fn column<'a>(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
146        let result = statement.column_int(start_index)?;
147        Ok((result, start_index + 1))
148    }
149}
150
151impl StaticColumnCount for i64 {}
152impl Bind for i64 {
153    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
154        statement
155            .bind_int64(start_index, *self)
156            .with_context(|| format!("Failed to bind i64 at index {start_index}"))?;
157        Ok(start_index + 1)
158    }
159}
160
161impl Column for i64 {
162    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
163        let result = statement.column_int64(start_index)?;
164        Ok((result, start_index + 1))
165    }
166}
167
168impl StaticColumnCount for u64 {}
169impl Bind for u64 {
170    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
171        statement
172            .bind_int64(start_index, (*self) as i64)
173            .with_context(|| format!("Failed to bind i64 at index {start_index}"))?;
174        Ok(start_index + 1)
175    }
176}
177
178impl Column for u64 {
179    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
180        let result = statement.column_int64(start_index)? as u64;
181        Ok((result, start_index + 1))
182    }
183}
184
185impl StaticColumnCount for u32 {}
186impl Bind for u32 {
187    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
188        (*self as i64)
189            .bind(statement, start_index)
190            .with_context(|| format!("Failed to bind usize at index {start_index}"))
191    }
192}
193
194impl Column for u32 {
195    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
196        let result = statement.column_int64(start_index)?;
197        Ok((result as u32, start_index + 1))
198    }
199}
200
201impl StaticColumnCount for u16 {}
202impl Bind for u16 {
203    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
204        (*self as i64)
205            .bind(statement, start_index)
206            .with_context(|| format!("Failed to bind usize at index {start_index}"))
207    }
208}
209
210impl Column for u16 {
211    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
212        let result = statement.column_int64(start_index)?;
213        Ok((result as u16, start_index + 1))
214    }
215}
216
217impl StaticColumnCount for usize {}
218impl Bind for usize {
219    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
220        (*self as i64)
221            .bind(statement, start_index)
222            .with_context(|| format!("Failed to bind usize at index {start_index}"))
223    }
224}
225
226impl Column for usize {
227    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
228        let result = statement.column_int64(start_index)?;
229        Ok((result as usize, start_index + 1))
230    }
231}
232
233impl StaticColumnCount for &str {}
234impl Bind for &str {
235    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
236        statement.bind_text(start_index, self)?;
237        Ok(start_index + 1)
238    }
239}
240
241impl StaticColumnCount for Arc<str> {}
242impl Bind for Arc<str> {
243    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
244        statement.bind_text(start_index, self.as_ref())?;
245        Ok(start_index + 1)
246    }
247}
248
249impl StaticColumnCount for String {}
250impl Bind for String {
251    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
252        statement.bind_text(start_index, self)?;
253        Ok(start_index + 1)
254    }
255}
256
257impl Column for Arc<str> {
258    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
259        let result = statement.column_text(start_index)?;
260        Ok((Arc::from(result), start_index + 1))
261    }
262}
263
264impl Column for String {
265    fn column<'a>(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
266        let result = statement.column_text(start_index)?;
267        Ok((result.to_owned(), start_index + 1))
268    }
269}
270
271impl<T: StaticColumnCount> StaticColumnCount for Option<T> {
272    fn column_count() -> usize {
273        T::column_count()
274    }
275}
276impl<T: Bind + StaticColumnCount> Bind for Option<T> {
277    fn bind(&self, statement: &Statement, mut start_index: i32) -> Result<i32> {
278        if let Some(this) = self {
279            this.bind(statement, start_index)
280        } else {
281            for _ in 0..T::column_count() {
282                statement.bind_null(start_index)?;
283                start_index += 1;
284            }
285            Ok(start_index)
286        }
287    }
288}
289
290impl<T: Column + StaticColumnCount> Column for Option<T> {
291    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
292        if let SqlType::Null = statement.column_type(start_index)? {
293            Ok((None, start_index + T::column_count() as i32))
294        } else {
295            T::column(statement, start_index).map(|(result, next_index)| (Some(result), next_index))
296        }
297    }
298}
299
300impl<T: StaticColumnCount, const COUNT: usize> StaticColumnCount for [T; COUNT] {
301    fn column_count() -> usize {
302        T::column_count() * COUNT
303    }
304}
305impl<T: Bind, const COUNT: usize> Bind for [T; COUNT] {
306    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
307        let mut current_index = start_index;
308        for binding in self {
309            current_index = binding.bind(statement, current_index)?
310        }
311
312        Ok(current_index)
313    }
314}
315
316impl StaticColumnCount for &Path {}
317impl Bind for &Path {
318    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
319        self.as_os_str()
320            .as_encoded_bytes()
321            .bind(statement, start_index)
322    }
323}
324
325impl StaticColumnCount for Arc<Path> {}
326impl Bind for Arc<Path> {
327    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
328        self.as_ref().bind(statement, start_index)
329    }
330}
331impl Column for Arc<Path> {
332    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
333        let blob = statement.column_blob(start_index)?;
334
335        PathBuf::try_from_bytes(blob).map(|path| (Arc::from(path.as_path()), start_index + 1))
336    }
337}
338
339impl StaticColumnCount for PathBuf {}
340impl Bind for PathBuf {
341    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
342        (self.as_ref() as &Path).bind(statement, start_index)
343    }
344}
345
346impl Column for PathBuf {
347    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
348        let blob = statement.column_blob(start_index)?;
349
350        PathBuf::try_from_bytes(blob).map(|path| (path, start_index + 1))
351    }
352}
353
354impl StaticColumnCount for uuid::Uuid {
355    fn column_count() -> usize {
356        1
357    }
358}
359
360impl Bind for uuid::Uuid {
361    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
362        self.as_bytes().bind(statement, start_index)
363    }
364}
365
366impl Column for uuid::Uuid {
367    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
368        let (bytes, next_index) = Column::column(statement, start_index)?;
369        Ok((uuid::Uuid::from_bytes(bytes), next_index))
370    }
371}
372
373impl StaticColumnCount for () {
374    fn column_count() -> usize {
375        0
376    }
377}
378/// Unit impls do nothing. This simplifies query macros
379impl Bind for () {
380    fn bind(&self, _statement: &Statement, start_index: i32) -> Result<i32> {
381        Ok(start_index)
382    }
383}
384
385impl Column for () {
386    fn column(_statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
387        Ok(((), start_index))
388    }
389}
390
391macro_rules! impl_tuple_row_traits {
392    ( $($local:ident: $type:ident),+ ) => {
393        impl<$($type: StaticColumnCount),+> StaticColumnCount for ($($type,)+) {
394            fn column_count() -> usize {
395                let mut count = 0;
396                $(count += $type::column_count();)+
397                count
398            }
399        }
400
401        impl<$($type: Bind),+> Bind for ($($type,)+) {
402            fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
403                let mut next_index = start_index;
404                let ($($local,)+) = self;
405                $(next_index = $local.bind(statement, next_index)?;)+
406                Ok(next_index)
407            }
408        }
409
410        impl<$($type: Column),+> Column for ($($type,)+) {
411            fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
412                let mut next_index = start_index;
413                Ok((
414                    (
415                        $({
416                            let value;
417                            (value, next_index) = $type::column(statement, next_index)?;
418                            value
419                        },)+
420                    ),
421                    next_index,
422                ))
423            }
424        }
425    }
426}
427
428impl_tuple_row_traits!(t1: T1, t2: T2);
429impl_tuple_row_traits!(t1: T1, t2: T2, t3: T3);
430impl_tuple_row_traits!(t1: T1, t2: T2, t3: T3, t4: T4);
431impl_tuple_row_traits!(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5);
432impl_tuple_row_traits!(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6);
433impl_tuple_row_traits!(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7);
434impl_tuple_row_traits!(
435    t1: T1,
436    t2: T2,
437    t3: T3,
438    t4: T4,
439    t5: T5,
440    t6: T6,
441    t7: T7,
442    t8: T8
443);
444impl_tuple_row_traits!(
445    t1: T1,
446    t2: T2,
447    t3: T3,
448    t4: T4,
449    t5: T5,
450    t6: T6,
451    t7: T7,
452    t8: T8,
453    t9: T9
454);
455impl_tuple_row_traits!(
456    t1: T1,
457    t2: T2,
458    t3: T3,
459    t4: T4,
460    t5: T5,
461    t6: T6,
462    t7: T7,
463    t8: T8,
464    t9: T9,
465    t10: T10
466);