1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
use crate::ToSql; use std::marker::PhantomData; #[derive(Debug, Clone, Copy)] pub struct Bind { pub n: u8, } #[derive(Debug)] pub struct Binder { counter: u8, } impl Default for Binder { fn default() -> Self { Self { counter: 1 } } } impl Binder { pub fn bind(&mut self) -> Bind { let n = self.counter; self.counter += 1; Bind { n } } } pub trait Binding { type Bindings; fn bindings(binder: &mut Binder) -> Self::Bindings; fn write_types(sql: &mut String); fn write_values(&self, sql: &mut String); fn prepare<F, S>(name: &str, f: F) -> Prepare<Self, S> where Self: Sized, F: FnOnce(Self::Bindings) -> S, S: ToSql, { let bindings = Self::bindings(&mut Binder::default()); Prepare { name, binding: PhantomData, stmt: f(bindings), } } } pub struct Prepare<'a, B, S> { name: &'a str, binding: PhantomData<B>, stmt: S, } impl<B: Binding, S: ToSql> Prepare<'_, B, S> { pub fn execute(&self, binding: B) -> Execute<B> { Execute { name: self.name, binding, } } } impl<B: Binding, S: ToSql> ToSql for Prepare<'_, B, S> { fn write_sql(&self, sql: &mut String) { sql.push_str("PREPARE "); sql.push_str(self.name); sql.push('('); B::write_types(sql); sql.push(')'); sql.push_str(" AS "); self.stmt.write_sql(sql); } } impl<B, S: Copy> Clone for Prepare<'_, B, S> { fn clone(&self) -> Self { *self } } impl<B, S: Copy> Copy for Prepare<'_, B, S> {} #[derive(Debug, Clone, Copy)] pub struct Execute<'a, B> { name: &'a str, binding: B, } impl<B: Binding> ToSql for Execute<'_, B> { fn write_sql(&self, sql: &mut String) { sql.push_str("EXECUTE "); sql.push_str(self.name); sql.push('('); self.binding.write_values(sql); sql.push(')'); } }