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