bindable.rs

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