1use crate::*;
4use std::borrow::Cow;
5
6#[cfg(feature = "backend-mysql")]
7#[cfg_attr(docsrs, doc(cfg(feature = "backend-mysql")))]
8mod mysql;
9#[cfg(feature = "backend-postgres")]
10#[cfg_attr(docsrs, doc(cfg(feature = "backend-postgres")))]
11mod postgres;
12#[cfg(feature = "backend-sqlite")]
13#[cfg_attr(docsrs, doc(cfg(feature = "backend-sqlite")))]
14mod sqlite;
15
16#[cfg(feature = "backend-mysql")]
17pub use mysql::*;
18#[cfg(feature = "backend-postgres")]
19pub use postgres::*;
20#[cfg(feature = "backend-sqlite")]
21pub use sqlite::*;
22
23mod foreign_key_builder;
24mod index_builder;
25mod query_builder;
26mod table_builder;
27mod table_ref_builder;
28
29pub use self::foreign_key_builder::*;
30pub use self::index_builder::*;
31pub use self::query_builder::*;
32pub use self::table_builder::*;
33pub use self::table_ref_builder::*;
34
35pub trait GenericBuilder: QueryBuilder + SchemaBuilder {}
36
37pub trait SchemaBuilder: TableBuilder + IndexBuilder + ForeignKeyBuilder {}
38
39pub trait QuotedBuilder {
40 fn quote(&self) -> Quote;
42
43 fn prepare_iden(&self, iden: &DynIden, sql: &mut dyn SqlWriter) {
45 let q = self.quote();
46 let qq = q.1 as char;
47
48 sql.write_char(q.left()).unwrap();
49 match &iden.0 {
50 Cow::Borrowed(s) => sql.write_str(s).unwrap(),
51 Cow::Owned(s) => {
52 for char in s.chars() {
53 if char == qq {
54 sql.write_char(char).unwrap()
55 }
56 sql.write_char(char).unwrap()
57 }
58 }
59 };
60 sql.write_char(q.right()).unwrap();
61 }
62}
63
64pub trait EscapeBuilder {
65 fn need_escape(&self, s: &str) -> bool {
67 s.chars().any(|c| {
68 matches!(
69 c,
70 '\r' | '\n' | '\x1a' | '\x09' | '\x08' | '\0' | '\'' | '"' | '\\'
71 )
72 })
73 }
74
75 fn escape_string(&self, string: &str) -> String {
77 let mut escaped = String::with_capacity(string.len() + 8);
78 self.write_escaped(&mut escaped, string);
79 escaped
80 }
81
82 fn write_escaped(&self, buffer: &mut dyn Write, string: &str) {
83 for c in string.chars() {
84 match c {
85 '\\' => buffer.write_str("\\\\"),
86 '"' => buffer.write_str("\\\""),
87 '\'' => buffer.write_str("\\'"),
88 '\0' => buffer.write_str("\\0"),
89 '\x08' => buffer.write_str("\\b"),
90 '\x09' => buffer.write_str("\\t"),
91 '\x1a' => buffer.write_str("\\z"),
92 '\n' => buffer.write_str("\\n"),
93 '\r' => buffer.write_str("\\r"),
94 _ => buffer.write_char(c),
95 }
96 .unwrap()
97 }
98 }
99
100 fn unescape_string(&self, string: &str) -> String {
102 let mut escape = false;
103 let mut output = String::new();
104 for c in string.chars() {
105 if !escape && c == '\\' {
106 escape = true;
107 } else if escape {
108 output
109 .write_char(match c {
110 '0' => '\0',
111 'b' => '\x08',
112 't' => '\x09',
113 'z' => '\x1a',
114 'n' => '\n',
115 'r' => '\r',
116 c => c,
117 })
118 .unwrap();
119 escape = false;
120 } else {
121 output.write_char(c).unwrap();
122 }
123 }
124 output
125 }
126}
127
128pub trait PrecedenceDecider {
129 fn inner_expr_well_known_greater_precedence(&self, inner: &Expr, outer_oper: &Oper) -> bool;
133}
134
135pub trait OperLeftAssocDecider {
136 fn well_known_left_associative(&self, op: &BinOper) -> bool;
140}
141
142#[derive(Debug, PartialEq)]
143pub enum Oper {
144 UnOper(UnOper),
145 BinOper(BinOper),
146}
147
148impl From<UnOper> for Oper {
149 fn from(value: UnOper) -> Self {
150 Oper::UnOper(value)
151 }
152}
153
154impl From<BinOper> for Oper {
155 fn from(value: BinOper) -> Self {
156 Oper::BinOper(value)
157 }
158}
159
160impl Oper {
161 pub(crate) fn is_logical(&self) -> bool {
162 matches!(
163 self,
164 Oper::UnOper(UnOper::Not) | Oper::BinOper(BinOper::And) | Oper::BinOper(BinOper::Or)
165 )
166 }
167
168 pub(crate) fn is_between(&self) -> bool {
169 matches!(
170 self,
171 Oper::BinOper(BinOper::Between) | Oper::BinOper(BinOper::NotBetween)
172 )
173 }
174
175 pub(crate) fn is_like(&self) -> bool {
176 matches!(
177 self,
178 Oper::BinOper(BinOper::Like) | Oper::BinOper(BinOper::NotLike)
179 )
180 }
181
182 pub(crate) fn is_in(&self) -> bool {
183 matches!(
184 self,
185 Oper::BinOper(BinOper::In) | Oper::BinOper(BinOper::NotIn)
186 )
187 }
188
189 pub(crate) fn is_is(&self) -> bool {
190 matches!(
191 self,
192 Oper::BinOper(BinOper::Is) | Oper::BinOper(BinOper::IsNot)
193 )
194 }
195
196 pub(crate) fn is_shift(&self) -> bool {
197 matches!(
198 self,
199 Oper::BinOper(BinOper::LShift) | Oper::BinOper(BinOper::RShift)
200 )
201 }
202
203 pub(crate) fn is_arithmetic(&self) -> bool {
204 match self {
205 Oper::BinOper(b) => {
206 matches!(
207 b,
208 BinOper::Mul | BinOper::Div | BinOper::Mod | BinOper::Add | BinOper::Sub
209 )
210 }
211 _ => false,
212 }
213 }
214
215 pub(crate) fn is_comparison(&self) -> bool {
216 match self {
217 Oper::BinOper(b) => {
218 matches!(
219 b,
220 BinOper::SmallerThan
221 | BinOper::SmallerThanOrEqual
222 | BinOper::Equal
223 | BinOper::GreaterThanOrEqual
224 | BinOper::GreaterThan
225 | BinOper::NotEqual
226 )
227 }
228 _ => false,
229 }
230 }
231}