1use crate::sql_arg::SqlArg;
4
5#[derive(Debug)]
9pub struct Sql(pub String, pub Vec<SqlArg>);
10
11impl Sql {
12 pub fn to_unsafe_string(&self) -> String {
18 fn parse_and_replace(position: &str, args: &[SqlArg], unsafe_string: &mut String) {
19 let pos: Result<usize, _> = position.parse();
20 match pos {
21 Ok(pos) => {
22 let arg: Option<&SqlArg> = args.get(pos - 1); match arg {
24 Some(v) => unsafe_string.push_str(&v.to_sql_string()),
25 None => {
26 unsafe_string.push('$');
27 unsafe_string.push_str(&position);
28 }
29 }
30 }
31 _ => {
32 unsafe_string.push('$');
33 unsafe_string.push_str(&position);
34 }
35 }
36 }
37
38 let mut quoted = false;
39 let mut params = self.1.iter();
44 let mut position_parsing = false;
45 let mut position = String::with_capacity(8);
46 let mut unsafe_string: String = String::new();
47
48 for c in self.0.chars() {
49 match c {
50 '\'' => {
51 quoted = !quoted;
52 unsafe_string.push('\'');
53 }
54 '?' if !quoted => {
55 match params.next() {
56 Some(p) => unsafe_string.push_str(&p.to_sql_string()),
57 None => unsafe_string.push('?'),
58 };
59 }
60 '$' if !quoted => {
61 position_parsing = true;
62 }
63 ' ' if position_parsing => {
64 parse_and_replace(&position, &self.1, &mut unsafe_string);
65 unsafe_string.push(' ');
66 position.clear();
67 position_parsing = false;
68 }
69 _ if position_parsing => position.push(c),
70 _ => unsafe_string.push(c),
71 }
72 }
73
74 if position_parsing {
76 parse_and_replace(&position, &self.1, &mut unsafe_string);
77 }
78
79 unsafe_string
80 }
81 pub fn append(&mut self, sql: &Sql) {
83 self.0.push_str(&sql.0);
84 self.1.extend_from_slice(&sql.1);
85 }
86 pub fn push_literal(&mut self, sql_lit: &str) {
88 self.0.push_str(&sql_lit);
89 }
90 pub fn pop_literals(&mut self, count: u8) {
92 for _ in 0..count {
93 self.0.pop();
94 }
95 }
96 pub fn new() -> Self {
98 Sql(String::new(), Vec::new())
99 }
100 pub fn is_empty(&self) -> bool {
102 self.0.is_empty()
103 }
104}
105
106impl Default for Sql {
107 fn default() -> Self {
108 Self::new()
109 }
110}
111
112#[cfg(test)]
113mod test {
114 use super::{Sql, SqlArg};
115
116 #[test]
117 fn to_unsafe_string() {
118 assert_eq!(
119 Sql("SELECT ?".to_string(), vec![SqlArg::U64(1)]).to_unsafe_string(),
120 "SELECT 1"
121 );
122 assert_eq!(
123 Sql("SELECT ? FROM".to_string(), vec![SqlArg::U64(1)]).to_unsafe_string(),
124 "SELECT 1 FROM"
125 );
126 assert_eq!(
127 Sql("SELECT $1 FROM".to_string(), vec![SqlArg::U64(1)]).to_unsafe_string(),
128 "SELECT 1 FROM"
129 );
130 assert_eq!(
131 Sql("SELECT $1".to_string(), vec![SqlArg::U64(1)]).to_unsafe_string(),
132 "SELECT 1"
133 );
134 assert_eq!(
135 Sql("SELECT $1".to_string(), vec![]).to_unsafe_string(),
136 "SELECT $1"
137 );
138 assert_eq!(
139 Sql("SELECT $a".to_string(), vec![]).to_unsafe_string(),
140 "SELECT $a"
141 );
142 assert_eq!(
143 Sql("SELECT '?'".to_string(), vec![SqlArg::U64(1)]).to_unsafe_string(),
144 "SELECT '?'"
145 );
146 assert_eq!(
147 Sql("SELECT '''?'".to_string(), vec![SqlArg::U64(1)]).to_unsafe_string(),
148 "SELECT '''?'"
149 );
150 }
151
152 #[test]
153 fn build() {
154 assert_eq!(Sql::default().to_unsafe_string(), "");
155 assert_eq!(Sql::default().is_empty(), true);
156 assert_eq!(Sql::new().is_empty(), true);
157
158 let mut s = Sql::new();
159 s.push_literal("SELECT 1 FROM");
160 assert_eq!(s.to_unsafe_string(), "SELECT 1 FROM");
161 s.pop_literals(5);
162 assert_eq!(s.to_unsafe_string(), "SELECT 1");
163
164 let mut s1 = Sql("SELECT ?".to_string(), vec![SqlArg::U64(1)]);
165 let s2 = Sql(", ?".to_string(), vec![SqlArg::U64(2)]);
166 s1.append(&s2);
167 assert_eq!(s1.to_unsafe_string(), "SELECT 1, 2");
168 }
169}