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