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 u64 {}
168impl Bind for u64 {
169    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
170        statement
171            .bind_int64(start_index, (*self) as i64)
172            .with_context(|| format!("Failed to bind i64 at index {start_index}"))?;
173        Ok(start_index + 1)
174    }
175}
176
177impl Column for u64 {
178    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
179        let result = statement.column_int64(start_index)? as u64;
180        Ok((result, start_index + 1))
181    }
182}
183
184impl StaticColumnCount for u32 {}
185impl Bind for u32 {
186    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
187        (*self as i64)
188            .bind(statement, start_index)
189            .with_context(|| format!("Failed to bind usize at index {start_index}"))
190    }
191}
192
193impl Column for u32 {
194    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
195        let result = statement.column_int64(start_index)?;
196        Ok((result as u32, start_index + 1))
197    }
198}
199
200impl StaticColumnCount for usize {}
201impl Bind for usize {
202    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
203        (*self as i64)
204            .bind(statement, start_index)
205            .with_context(|| format!("Failed to bind usize at index {start_index}"))
206    }
207}
208
209impl Column for usize {
210    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
211        let result = statement.column_int64(start_index)?;
212        Ok((result as usize, start_index + 1))
213    }
214}
215
216impl StaticColumnCount for &str {}
217impl Bind for &str {
218    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
219        statement.bind_text(start_index, self)?;
220        Ok(start_index + 1)
221    }
222}
223
224impl StaticColumnCount for Arc<str> {}
225impl Bind for Arc<str> {
226    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
227        statement.bind_text(start_index, self.as_ref())?;
228        Ok(start_index + 1)
229    }
230}
231
232impl StaticColumnCount for String {}
233impl Bind for String {
234    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
235        statement.bind_text(start_index, self)?;
236        Ok(start_index + 1)
237    }
238}
239
240impl Column for Arc<str> {
241    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
242        let result = statement.column_text(start_index)?;
243        Ok((Arc::from(result), start_index + 1))
244    }
245}
246
247impl Column for String {
248    fn column<'a>(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
249        let result = statement.column_text(start_index)?;
250        Ok((result.to_owned(), start_index + 1))
251    }
252}
253
254impl<T: StaticColumnCount> StaticColumnCount for Option<T> {
255    fn column_count() -> usize {
256        T::column_count()
257    }
258}
259impl<T: Bind + StaticColumnCount> Bind for Option<T> {
260    fn bind(&self, statement: &Statement, mut start_index: i32) -> Result<i32> {
261        if let Some(this) = self {
262            this.bind(statement, start_index)
263        } else {
264            for _ in 0..T::column_count() {
265                statement.bind_null(start_index)?;
266                start_index += 1;
267            }
268            Ok(start_index)
269        }
270    }
271}
272
273impl<T: Column + StaticColumnCount> Column for Option<T> {
274    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
275        if let SqlType::Null = statement.column_type(start_index)? {
276            Ok((None, start_index + T::column_count() as i32))
277        } else {
278            T::column(statement, start_index).map(|(result, next_index)| (Some(result), next_index))
279        }
280    }
281}
282
283impl<T: StaticColumnCount, const COUNT: usize> StaticColumnCount for [T; COUNT] {
284    fn column_count() -> usize {
285        T::column_count() * COUNT
286    }
287}
288impl<T: Bind, const COUNT: usize> Bind for [T; COUNT] {
289    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
290        let mut current_index = start_index;
291        for binding in self {
292            current_index = binding.bind(statement, current_index)?
293        }
294
295        Ok(current_index)
296    }
297}
298
299impl StaticColumnCount for &Path {}
300impl Bind for &Path {
301    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
302        self.as_os_str().as_bytes().bind(statement, start_index)
303    }
304}
305
306impl StaticColumnCount for Arc<Path> {}
307impl Bind for Arc<Path> {
308    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
309        self.as_ref().bind(statement, start_index)
310    }
311}
312
313impl StaticColumnCount for PathBuf {}
314impl Bind for PathBuf {
315    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
316        (self.as_ref() as &Path).bind(statement, start_index)
317    }
318}
319
320impl Column for PathBuf {
321    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
322        let blob = statement.column_blob(start_index)?;
323
324        Ok((
325            PathBuf::from(OsStr::from_bytes(blob).to_owned()),
326            start_index + 1,
327        ))
328    }
329}
330
331impl StaticColumnCount for uuid::Uuid {
332    fn column_count() -> usize {
333        1
334    }
335}
336
337impl Bind for uuid::Uuid {
338    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
339        self.as_bytes().bind(statement, start_index)
340    }
341}
342
343impl Column for uuid::Uuid {
344    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
345        let (bytes, next_index) = Column::column(statement, start_index)?;
346        Ok((uuid::Uuid::from_bytes(bytes), next_index))
347    }
348}
349
350impl StaticColumnCount for () {
351    fn column_count() -> usize {
352        0
353    }
354}
355/// Unit impls do nothing. This simplifies query macros
356impl Bind for () {
357    fn bind(&self, _statement: &Statement, start_index: i32) -> Result<i32> {
358        Ok(start_index)
359    }
360}
361
362impl Column for () {
363    fn column(_statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
364        Ok(((), start_index))
365    }
366}
367
368macro_rules! impl_tuple_row_traits {
369    ( $($local:ident: $type:ident),+ ) => {
370        impl<$($type: StaticColumnCount),+> StaticColumnCount for ($($type,)+) {
371            fn column_count() -> usize {
372                let mut count = 0;
373                $(count += $type::column_count();)+
374                count
375            }
376        }
377
378        impl<$($type: Bind),+> Bind for ($($type,)+) {
379            fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
380                let mut next_index = start_index;
381                let ($($local,)+) = self;
382                $(next_index = $local.bind(statement, next_index)?;)+
383                Ok(next_index)
384            }
385        }
386
387        impl<$($type: Column),+> Column for ($($type,)+) {
388            fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
389                let mut next_index = start_index;
390                Ok((
391                    (
392                        $({
393                            let value;
394                            (value, next_index) = $type::column(statement, next_index)?;
395                            value
396                        },)+
397                    ),
398                    next_index,
399                ))
400            }
401        }
402    }
403}
404
405impl_tuple_row_traits!(t1: T1, t2: T2);
406impl_tuple_row_traits!(t1: T1, t2: T2, t3: T3);
407impl_tuple_row_traits!(t1: T1, t2: T2, t3: T3, t4: T4);
408impl_tuple_row_traits!(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5);
409impl_tuple_row_traits!(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6);
410impl_tuple_row_traits!(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7);
411impl_tuple_row_traits!(
412    t1: T1,
413    t2: T2,
414    t3: T3,
415    t4: T4,
416    t5: T5,
417    t6: T6,
418    t7: T7,
419    t8: T8
420);
421impl_tuple_row_traits!(
422    t1: T1,
423    t2: T2,
424    t3: T3,
425    t4: T4,
426    t5: T5,
427    t6: T6,
428    t7: T7,
429    t8: T8,
430    t9: T9
431);
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    t9: T9,
442    t10: T10
443);