1#[cfg(feature = "pagination")]
2use super::pages::Page;
3use crate::{
4 Error, Table, ToSqlite,
5 builder::{
6 joins::{TableJoin, TableJoinOptions, TableJoins},
7 models::{QueryCondition, QueryOrder, QueryType, WhereCondition},
8 values::{Value, Values},
9 },
10 queries::Query,
11};
12
13#[derive(Debug, Clone, Default)]
65pub struct QueryBuilder {
66 pub(crate) table: Table,
67 pub(crate) query_type: QueryType,
68 pub(crate) aliases: bool,
70
71 pub(crate) columns: Vec<String>,
72
73 pub(crate) count: bool,
75 pub(crate) limit: Option<usize>,
77 pub(crate) offset: Option<usize>,
79
80 pub(crate) where_clause: Vec<String>,
82 pub(crate) where_condition_last: bool,
84 pub(crate) order_by: Vec<(String, QueryOrder)>,
86
87 pub(crate) joins: TableJoins,
88
89 pub(crate) values: Values,
91
92 pub(crate) error: Option<Error>,
93}
94
95impl QueryBuilder {
96 pub fn new() -> Self {
98 QueryBuilder::default()
99 }
100 pub fn select() -> QueryBuilder {
102 QueryBuilder {
103 query_type: QueryType::Select,
104 ..Default::default()
105 }
106 }
107 pub fn create() -> QueryBuilder {
109 QueryBuilder {
110 query_type: QueryType::Create,
111 ..Default::default()
112 }
113 }
114
115 pub fn all() -> QueryBuilder {
117 QueryBuilder {
118 query_type: QueryType::Select,
119 ..Default::default()
120 }
121 }
122
123 pub fn insert() -> QueryBuilder {
125 QueryBuilder {
126 query_type: QueryType::Insert,
127 ..Default::default()
128 }
129 }
130
131 pub fn update() -> QueryBuilder {
133 QueryBuilder {
134 query_type: QueryType::Update,
135 ..Default::default()
136 }
137 }
138
139 pub fn delete() -> QueryBuilder {
141 QueryBuilder {
142 query_type: QueryType::Delete,
143 ..Default::default()
144 }
145 }
146
147 pub fn table(mut self, table: Table) -> Self {
149 self.table = table.clone();
150 self
151 }
152
153 pub fn columns(mut self, columns: Vec<&str>) -> Self {
155 self.columns = columns.iter().map(|c| c.to_string()).collect();
156 self
157 }
158
159 pub fn add_value(mut self, column: &str, value: impl Into<Value>) -> Self {
161 self.values.push(column.to_string(), value.into());
162 self
163 }
164
165 pub fn and(mut self) -> Self {
167 self.where_clause.push(WhereCondition::And.to_sqlite());
168 self.where_condition_last = true;
169 self
170 }
171
172 pub fn or(mut self) -> Self {
174 self.where_clause.push(WhereCondition::Or.to_sqlite());
175 self.where_condition_last = true;
176 self
177 }
178
179 fn add_where(&mut self, column: &str, condition: QueryCondition, value: Value) {
181 let mut column_name: &str = column;
182
183 let table: &Table = if let Some((ftable, fcolumn)) = column.split_once('.') {
185 match self.joins.get(ftable) {
186 Some(TableJoin::InnerJoin(TableJoinOptions { child, .. })) => {
187 column_name = fcolumn;
188 child
189 }
190 _ => {
191 self.error = Some(Error::QueryBuilderError(
192 format!("Table `{}` does not exist", ftable),
193 String::from("where_eq"),
194 ));
195 &self.table
196 }
197 }
198 } else {
199 &self.table
200 };
201
202 if table.is_valid_column(column_name) {
203 if !self.where_clause.is_empty() && !self.where_condition_last {
205 self.where_clause
207 .push(WhereCondition::default().to_sqlite());
208 }
209
210 self.where_clause
211 .push(format!("{} {} ?", column, condition.to_sqlite()));
212 self.values.push(column.to_string(), value);
213 self.where_condition_last = false;
214 } else {
215 self.error = Some(Error::QueryBuilderError(
216 format!(
217 "Column `{}` does not exist in table `{}`",
218 column_name, table.name
219 ),
220 String::from("where_eq"),
221 ));
222 }
223 }
224
225 pub fn where_eq(mut self, column: &str, value: impl Into<Value>) -> Self {
227 QueryBuilder::add_where(&mut self, column, QueryCondition::Eq, value.into());
228 self
229 }
230
231 pub fn where_ne(mut self, column: &str, value: impl Into<Value>) -> Self {
233 QueryBuilder::add_where(&mut self, column, QueryCondition::Ne, value.into());
234 self
235 }
236
237 pub fn where_like(mut self, column: &str, value: impl Into<Value>) -> Self {
239 QueryBuilder::add_where(&mut self, column, QueryCondition::Like, value.into());
240 self
241 }
242
243 pub fn where_gt(mut self, column: &str, value: impl Into<Value>) -> Self {
245 QueryBuilder::add_where(&mut self, column, QueryCondition::Gt, value.into());
246 self
247 }
248
249 pub fn where_lt(mut self, column: &str, value: impl Into<Value>) -> Self {
251 QueryBuilder::add_where(&mut self, column, QueryCondition::Lt, value.into());
252 self
253 }
254
255 pub fn where_gte(mut self, column: &str, value: impl Into<Value>) -> Self {
257 QueryBuilder::add_where(&mut self, column, QueryCondition::Gte, value.into());
258 self
259 }
260
261 pub fn where_lte(mut self, column: &str, value: impl Into<Value>) -> Self {
263 QueryBuilder::add_where(&mut self, column, QueryCondition::Lte, value.into());
264 self
265 }
266
267 pub fn filter(mut self, fields: Vec<(&str, impl Into<Value>)>) -> Self {
269 for (field, value) in fields {
270 if field.starts_with("=") {
271 let field = &field[1..];
272 self = self.where_eq(field, value.into());
273 } else if field.starts_with("~") {
274 let field = &field[1..];
275 self = self.where_like(field, value.into());
276 } else if field.starts_with("!") {
277 let field = &field[1..];
278 self = self.where_ne(field, value.into());
279 } else {
280 self = self.where_eq(field, value.into()).or();
282 }
283 }
284 self
285 }
286
287 pub fn order_by(mut self, column: &str, order: QueryOrder) -> Self {
289 if self.table.is_valid_column(column) {
290 self.order_by.push((column.to_string(), order));
291 } else {
292 self.error = Some(Error::QueryBuilderError(
293 format!(
294 "Column `{}` does not exist in table `{}`",
295 column, self.table.name
296 ),
297 String::from("order_by"),
298 ));
299 }
300 self
301 }
302
303 pub fn join(mut self, table: Table) -> Self {
307 let key = self.table.get_primary_key();
308 if table.is_valid_column(key.as_str()) || self.table.is_valid_column(key.as_str()) {
309 self.joins
311 .push(TableJoin::new(self.table.clone(), table.clone()));
312 } else {
313 self.error = Some(Error::QueryBuilderError(
314 format!("Column `{}` does not exist in table `{}`", key, table.name),
315 String::from("join"),
316 ));
317 }
318 self
319 }
320
321 pub fn count(mut self) -> Self {
323 self.count = true;
324 self
325 }
326
327 pub fn limit(mut self, limit: usize) -> Self {
329 if limit != 0 {
330 self.limit = Some(limit);
331 } else {
332 self.error = Some(Error::QueryBuilderError(
333 String::from("Limit cannot be 0"),
334 String::from("limit"),
335 ));
336 }
337 self
338 }
339
340 pub fn offset(mut self, offset: usize) -> Self {
342 self.offset = Some(offset);
343 self
344 }
345
346 #[cfg(feature = "pagination")]
348 pub fn page(mut self, page: &Page) -> Self {
349 self.offset = Some(page.offset() as usize);
350 self.limit = Some(page.limit as usize);
351 self
352 }
353
354 pub fn build(&mut self) -> Result<Query, crate::Error> {
356 if let Some(ref error) = self.error {
357 return Err(error.clone());
358 }
359
360 let mut pop_where_condition = false;
362 if let Some(last) = self.where_clause.last() {
363 if last == &WhereCondition::Or.to_sqlite() || last == &WhereCondition::And.to_sqlite() {
364 pop_where_condition = true;
365 }
366 }
367 if pop_where_condition {
369 self.where_clause.pop();
370 }
371
372 match self.query_type {
373 QueryType::Create => {
374 let query = self.table.on_create(self)?;
375 Ok(Query::new(
376 self.query_type.clone(),
377 query.clone(),
378 Values::new(),
379 Values::new(),
380 self.columns.clone(),
381 self.table.clone(),
382 ))
383 }
384 QueryType::Select => {
385 let query = self.table.on_select(self)?;
386 Ok(Query::new(
387 self.query_type.clone(),
388 query.clone(),
389 self.values.clone(),
390 Values::new(),
391 self.columns.clone(),
392 self.table.clone(),
393 ))
394 }
395 QueryType::Insert => {
396 let (query, parameters) = self.table.on_insert(self)?;
397 Ok(Query::new(
398 self.query_type.clone(),
399 query.clone(),
400 self.values.clone(),
401 parameters,
402 self.columns.clone(),
403 self.table.clone(),
404 ))
405 }
406 QueryType::Update => {
407 let (query, parameters) = self.table.on_update(self)?;
408 Ok(Query::new(
409 self.query_type.clone(),
410 query.clone(),
411 self.values.clone(),
412 parameters,
413 self.columns.clone(),
414 self.table.clone(),
415 ))
416 }
417 QueryType::Delete => {
418 let (query, parameters) = self.table.on_delete(self)?;
419 Ok(Query::new(
420 self.query_type.clone(),
421 query.clone(),
422 self.values.clone(),
423 parameters,
424 self.columns.clone(),
425 self.table.clone(),
426 ))
427 }
428 QueryType::Batch => Err(Error::QueryBuilderError(
429 String::from("Batch queries are not supported"),
430 String::from("build"),
431 )),
432 }
433 }
434}
435
436#[cfg(test)]
437mod tests {
438 use crate::{
439 Column, ColumnType, ColumnTypeOptions, QueryBuilder, Table, builder::values::Value,
440 };
441
442 fn simple_table() -> Table {
443 Table {
444 name: "users".to_string(),
445 database: None,
446 columns: crate::Columns::from(vec![
447 Column::new(
448 "id".to_string(),
449 ColumnType::Identifier(ColumnTypeOptions::primary_key()),
450 ),
451 Column::new(
452 "username".to_string(),
453 ColumnType::Text(ColumnTypeOptions::default()),
454 ),
455 Column::new(
456 "email".to_string(),
457 ColumnType::Text(ColumnTypeOptions::null()),
458 ),
459 ]),
460 }
461 }
462
463 #[test]
464 fn test_simple_select() {
465 let table = simple_table();
466
467 let query = QueryBuilder::select()
468 .table(table)
469 .build()
470 .expect("Failed to build query");
471
472 assert_eq!(query.query, "SELECT id, username, email FROM users;");
473 }
474
475 #[test]
476 fn test_where() {
477 let table = simple_table();
478 let query = QueryBuilder::select()
479 .table(table)
480 .where_eq("username", "geekmasher")
481 .or()
482 .where_like("email", "%geekmasher%")
483 .build()
484 .expect("Failed to build query");
485
486 assert_eq!(
487 query.query,
488 "SELECT id, username, email FROM users WHERE username = ? OR email LIKE ?;"
489 );
490 let first = query.values.get(&String::from("username")).unwrap();
491 assert_eq!(first, &Value::Text(String::from("geekmasher")));
492 let second = query.values.get(&String::from("email")).unwrap();
493 assert_eq!(second, &Value::Text(String::from("%geekmasher%")));
494 }
495}