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);