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