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
use crate::arg::SqlArg; pub trait Bind { fn bind(&self, arg: &dyn SqlArg) -> String; fn binds(&self, args: &[&dyn SqlArg]) -> String; } impl Bind for &str { fn bind(&self, arg: &dyn SqlArg) -> String { (*self).to_string().bind(arg) } fn binds(&self, args: &[&dyn SqlArg]) -> String { (*self).to_string().binds(args) } } impl Bind for String { fn bind(&self, arg: &dyn SqlArg) -> String { self.replacen('?', &arg.sql_arg(), 1) } fn binds(&self, args: &[&dyn SqlArg]) -> String { let mut offset = 0; let mut res = String::new(); let len = args.len(); for ch in self.chars() { if ch == '?' { res.push_str(&args[offset].sql_arg()); offset = (offset + 1) % len; } else { res.push(ch); } } res } } #[cfg(test)] mod tests { use super::*; use std::error::Error; #[test] fn test_bind() -> Result<(), Box<dyn Error>> { let foo = "f?o?o"; assert_eq!("'lol'foo?", &"?foo?".bind(&"lol")); assert_eq!("'lol'foo10", &"?foo?".bind(&"lol").bind(&10)); assert_eq!("'lol'foo?", &"?foo?".bind(&String::from("lol"))); assert_eq!("'lol'foo?", &String::from("?foo?").bind(&"lol")); assert_eq!("f'lol'o?o", &foo.bind(&"lol")); assert_eq!("fo'f?o?o'o", &"fo?o".bind(&foo)); assert_eq!("fo10o", &"fo?o".bind(&10_usize)); assert_eq!("fo10o", &"fo?o".bind(&10)); assert_eq!("fo10o", &"fo?o".bind(&10_isize)); Ok(()) } #[test] fn test_binds() -> Result<(), Box<dyn Error>> { assert_eq!("10f20o30o10", &"?f?o?o?".binds(&[&10, &20, &30])); assert_eq!( "'abc'f'def'o'ghi'o'abc'", &"?f?o?o?".binds(&[&"abc", &"def", &"ghi"]) ); assert_eq!( "10f20o30o10", &String::from("?f?o?o?").binds(&[&10, &20, &30]) ); assert_eq!( "10f'AAA'o10o'AAA'", &String::from("?f?o?o?").binds(&[&10, &"AAA"]) ); Ok(()) } }