1use std::fmt::Write;
2
3use crate::conditional::{BuildCondition, Condition};
4use crate::join_table::{JoinTable, JoinTableImpl};
5use crate::limit_clause::LimitClause;
6use crate::ordering::{OrderByEntry, Ordering};
7use crate::select_column::{SelectColumn, SelectColumnImpl};
8use crate::{DBImpl, Value};
9
10pub trait Select<'until_build, 'post_query> {
14 fn limit_clause(self, limit: LimitClause) -> Self;
18
19 fn distinct(self) -> Self;
23
24 fn where_clause(self, where_clause: &'until_build Condition<'post_query>) -> Self;
28
29 fn build(self) -> (String, Vec<Value<'post_query>>);
33}
34
35#[derive(Debug)]
39pub struct SelectData<'until_build, 'post_query> {
40 pub(crate) resulting_columns: &'until_build [SelectColumnImpl<'until_build>],
41 pub(crate) limit: Option<u64>,
42 pub(crate) offset: Option<u64>,
43 pub(crate) from_clause: &'until_build str,
44 pub(crate) where_clause: Option<&'until_build Condition<'post_query>>,
45 pub(crate) distinct: bool,
46 pub(crate) lookup: Vec<Value<'post_query>>,
47 pub(crate) join_tables: &'until_build [JoinTableImpl<'until_build, 'post_query>],
48 pub(crate) order_by_clause: &'until_build [OrderByEntry<'until_build>],
49}
50
51#[derive(Debug)]
57pub enum SelectImpl<'until_build, 'post_query> {
58 #[cfg(feature = "sqlite")]
62 SQLite(SelectData<'until_build, 'post_query>),
63 #[cfg(feature = "mysql")]
67 MySQL(SelectData<'until_build, 'post_query>),
68 #[cfg(feature = "postgres")]
72 Postgres(SelectData<'until_build, 'post_query>),
73}
74
75impl<'until_build, 'post_build> Select<'until_build, 'post_build>
76 for SelectImpl<'until_build, 'post_build>
77{
78 fn limit_clause(mut self, limit: LimitClause) -> Self {
79 match self {
80 #[cfg(feature = "sqlite")]
81 SelectImpl::SQLite(ref mut d) => {
82 d.limit = Some(limit.limit);
83 d.offset = limit.offset;
84 }
85 #[cfg(feature = "mysql")]
86 SelectImpl::MySQL(ref mut d) => {
87 d.limit = Some(limit.limit);
88 d.offset = limit.offset;
89 }
90 #[cfg(feature = "postgres")]
91 SelectImpl::Postgres(ref mut d) => {
92 d.limit = Some(limit.limit);
93 d.offset = limit.offset;
94 }
95 };
96 self
97 }
98
99 fn distinct(mut self) -> Self {
100 match self {
101 #[cfg(feature = "sqlite")]
102 SelectImpl::SQLite(ref mut d) => d.distinct = true,
103 #[cfg(feature = "mysql")]
104 SelectImpl::MySQL(ref mut d) => d.distinct = true,
105 #[cfg(feature = "postgres")]
106 SelectImpl::Postgres(ref mut d) => d.distinct = true,
107 };
108 self
109 }
110
111 fn where_clause(mut self, where_clause: &'until_build Condition<'post_build>) -> Self {
112 match self {
113 #[cfg(feature = "sqlite")]
114 SelectImpl::SQLite(ref mut d) => d.where_clause = Some(where_clause),
115 #[cfg(feature = "mysql")]
116 SelectImpl::MySQL(ref mut d) => d.where_clause = Some(where_clause),
117 #[cfg(feature = "postgres")]
118 SelectImpl::Postgres(ref mut d) => d.where_clause = Some(where_clause),
119 };
120 self
121 }
122
123 fn build(self) -> (String, Vec<Value<'post_build>>) {
124 match self {
125 #[cfg(feature = "sqlite")]
126 SelectImpl::SQLite(mut d) => {
127 let mut s = format!("SELECT{} ", if d.distinct { " DISTINCT" } else { "" });
128
129 let column_len = d.resulting_columns.len();
130 for (idx, column) in d.resulting_columns.iter().enumerate() {
131 column.build(&mut s);
132
133 if idx != column_len - 1 {
134 write!(s, ", ").unwrap();
135 }
136 }
137
138 write!(s, " FROM \"{}\"", d.from_clause).unwrap();
139
140 for x in d.join_tables {
141 write!(s, " ").unwrap();
142 x.build(&mut s, &mut d.lookup);
143 }
144
145 if let Some(c) = d.where_clause {
146 write!(s, " WHERE {}", c.build(DBImpl::SQLite, &mut d.lookup)).unwrap()
147 };
148
149 if !d.order_by_clause.is_empty() {
150 write!(s, " ORDER BY ").unwrap();
151
152 let order_by_len = d.order_by_clause.len();
153 for (idx, entry) in d.order_by_clause.iter().enumerate() {
154 if let Some(table_name) = entry.table_name {
155 write!(s, "{table_name}.").unwrap();
156 };
157 write!(
158 s,
159 "{}{}",
160 entry.column_name,
161 match entry.ordering {
162 Ordering::Asc => "",
163 Ordering::Desc => " DESC",
164 }
165 )
166 .unwrap();
167
168 if idx != order_by_len - 1 {
169 write!(s, ", ").unwrap();
170 }
171 }
172 };
173
174 if let Some(limit) = d.limit {
175 write!(s, " LIMIT {limit}").unwrap();
176 if let Some(offset) = d.offset {
177 write!(s, " OFFSET {offset}").unwrap();
178 }
179 };
180
181 write!(s, ";").unwrap();
182
183 (s, d.lookup)
184 }
185 #[cfg(feature = "mysql")]
186 SelectImpl::MySQL(mut d) => {
187 let mut s = format!("SELECT{} ", if d.distinct { " DISTINCT" } else { "" });
188
189 let column_len = d.resulting_columns.len();
190 for (idx, column) in d.resulting_columns.iter().enumerate() {
191 column.build(&mut s);
192
193 if idx != column_len - 1 {
194 write!(s, ", ").unwrap();
195 }
196 }
197
198 write!(s, " FROM {}", d.from_clause).unwrap();
199
200 for x in d.join_tables {
201 write!(s, " ").unwrap();
202 x.build(&mut s, &mut d.lookup);
203 }
204
205 if let Some(c) = d.where_clause {
206 write!(s, " WHERE {}", c.build(DBImpl::MySQL, &mut d.lookup)).unwrap()
207 };
208
209 if !d.order_by_clause.is_empty() {
210 write!(s, " ORDER BY ").unwrap();
211
212 let order_by_len = d.order_by_clause.len();
213 for (idx, entry) in d.order_by_clause.iter().enumerate() {
214 if let Some(table_name) = entry.table_name {
215 write!(s, "{table_name}.").unwrap();
216 };
217 write!(
218 s,
219 "{}{}",
220 entry.column_name,
221 match entry.ordering {
222 Ordering::Asc => "",
223 Ordering::Desc => " DESC",
224 }
225 )
226 .unwrap();
227
228 if idx != order_by_len - 1 {
229 write!(s, ", ").unwrap();
230 }
231 }
232 };
233
234 if let Some(limit) = d.limit {
235 write!(s, " LIMIT {limit}").unwrap();
236 if let Some(offset) = d.offset {
237 write!(s, " OFFSET {offset}").unwrap();
238 }
239 };
240
241 write!(s, ";").unwrap();
242
243 (s, d.lookup)
244 }
245 #[cfg(feature = "postgres")]
246 SelectImpl::Postgres(mut d) => {
247 let mut s = format!("SELECT{} ", if d.distinct { " DISTINCT" } else { "" });
248
249 let column_len = d.resulting_columns.len();
250 for (idx, column) in d.resulting_columns.iter().enumerate() {
251 column.build(&mut s);
252
253 if idx != column_len - 1 {
254 write!(s, ", ").unwrap();
255 }
256 }
257
258 write!(s, " FROM \"{}\"", d.from_clause).unwrap();
259
260 for x in d.join_tables {
261 write!(s, " ").unwrap();
262 x.build(&mut s, &mut d.lookup);
263 }
264
265 if let Some(c) = d.where_clause {
266 write!(s, " WHERE {}", c.build(DBImpl::Postgres, &mut d.lookup)).unwrap()
267 };
268
269 if !d.order_by_clause.is_empty() {
270 write!(s, " ORDER BY ").unwrap();
271
272 let order_by_len = d.order_by_clause.len();
273 for (idx, entry) in d.order_by_clause.iter().enumerate() {
274 if let Some(table_name) = entry.table_name {
275 write!(s, "\"{table_name}\".").unwrap();
276 };
277 write!(
278 s,
279 "\"{}\"{}",
280 entry.column_name,
281 match entry.ordering {
282 Ordering::Asc => "",
283 Ordering::Desc => " DESC",
284 }
285 )
286 .unwrap();
287
288 if idx != order_by_len - 1 {
289 write!(s, ", ").unwrap();
290 }
291 }
292 };
293
294 if let Some(limit) = d.limit {
295 write!(s, " LIMIT {limit}").unwrap();
296 if let Some(offset) = d.offset {
297 write!(s, " OFFSET {offset}").unwrap();
298 }
299 };
300
301 write!(s, ";").unwrap();
302
303 (s, d.lookup)
304 }
305 }
306 }
307}