1use crate::column::ColumnMarker;
4use crate::error::{Error, Result};
5use crate::expr::Expr;
6
7#[derive(Debug, Clone, PartialEq)]
9pub enum SelectItem {
10 Column(ColumnMarker),
12 Computed {
14 expr: Expr,
16 alias: String,
18 },
19}
20
21impl SelectItem {
22 pub fn column(marker: ColumnMarker) -> Self {
24 SelectItem::Column(marker)
25 }
26
27 pub fn computed(expr: Expr, alias: impl Into<String>) -> Self {
29 SelectItem::Computed {
30 expr,
31 alias: alias.into(),
32 }
33 }
34}
35
36impl From<ColumnMarker> for SelectItem {
37 fn from(marker: ColumnMarker) -> Self {
38 SelectItem::Column(marker)
39 }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
44pub enum OrderDir {
45 Asc,
47 Desc,
49}
50
51#[derive(Debug, Clone, PartialEq, Eq)]
53pub struct OrderBy {
54 pub column: String,
56 pub direction: OrderDir,
58}
59
60impl OrderBy {
61 pub fn new(column: impl Into<String>, direction: OrderDir) -> Self {
63 OrderBy {
64 column: column.into(),
65 direction,
66 }
67 }
68
69 pub fn asc(column: impl Into<String>) -> Self {
71 OrderBy::new(column, OrderDir::Asc)
72 }
73
74 pub fn desc(column: impl Into<String>) -> Self {
76 OrderBy::new(column, OrderDir::Desc)
77 }
78}
79
80#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
82pub struct SelectCapacity {
83 pub items: usize,
85 pub joins: usize,
87 pub order_by_columns: usize,
89 pub order_by_exprs: usize,
91 pub group_by: usize,
93 pub distinct: usize,
95}
96
97#[derive(Debug, Clone, PartialEq)]
99pub enum OrderByItem {
100 Column(OrderBy),
102 Expr(Expr, OrderDir),
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq)]
108pub enum JoinType {
109 Inner,
111 Left,
113}
114
115#[derive(Debug, Clone, PartialEq)]
117pub struct JoinClause {
118 pub join_type: JoinType,
120 pub table: String,
122 pub on: Expr,
124 pub items: Vec<SelectItem>,
126}
127
128impl JoinClause {
129 pub fn new(
131 join_type: JoinType,
132 table: impl Into<String>,
133 on: Expr,
134 items: Vec<SelectItem>,
135 ) -> Self {
136 Self {
137 join_type,
138 table: table.into(),
139 on,
140 items,
141 }
142 }
143}
144
145#[derive(Debug, Clone, PartialEq)]
147pub struct Select {
148 pub table: String,
150 pub items: Vec<SelectItem>,
152 pub joins: Vec<JoinClause>,
154 pub filter: Option<Expr>,
156 pub order_by: Vec<OrderBy>,
158 pub take: Option<i32>,
164 pub skip: Option<u32>,
166 pub group_by: Vec<ColumnMarker>,
168 pub distinct: Vec<String>,
174 pub having: Option<Expr>,
176 pub order_by_items: Vec<OrderByItem>,
178 pub order_by_exprs: Vec<(Expr, OrderDir)>,
180}
181
182impl Select {
183 pub fn from_table(table: impl Into<String>) -> SelectBuilder {
185 SelectBuilder {
186 table: table.into(),
187 items: Vec::new(),
188 joins: Vec::new(),
189 filter: None,
190 order_by: Vec::new(),
191 take: None,
192 skip: None,
193 group_by: Vec::new(),
194 distinct: Vec::new(),
195 having: None,
196 order_by_items: Vec::new(),
197 order_by_exprs: Vec::new(),
198 }
199 }
200}
201
202#[derive(Debug, Clone)]
204pub struct SelectBuilder {
205 table: String,
206 items: Vec<SelectItem>,
207 joins: Vec<JoinClause>,
208 filter: Option<Expr>,
209 order_by: Vec<OrderBy>,
210 take: Option<i32>,
211 skip: Option<u32>,
212 group_by: Vec<ColumnMarker>,
213 distinct: Vec<String>,
214 having: Option<Expr>,
215 order_by_items: Vec<OrderByItem>,
216 order_by_exprs: Vec<(Expr, OrderDir)>,
217}
218
219impl SelectBuilder {
220 #[must_use]
222 pub fn with_capacity(mut self, capacity: SelectCapacity) -> Self {
223 self.items.reserve(capacity.items);
224 self.joins.reserve(capacity.joins);
225 self.order_by.reserve(capacity.order_by_columns);
226 self.group_by.reserve(capacity.group_by);
227 self.distinct.reserve(capacity.distinct);
228 self.order_by_items
229 .reserve(capacity.order_by_columns + capacity.order_by_exprs);
230 self.order_by_exprs.reserve(capacity.order_by_exprs);
231 self
232 }
233
234 #[must_use]
236 pub fn items(mut self, items: Vec<SelectItem>) -> Self {
237 self.items = items;
238 self
239 }
240
241 #[must_use]
243 pub fn item(mut self, item: SelectItem) -> Self {
244 self.items.push(item);
245 self
246 }
247
248 #[must_use]
250 pub fn computed(mut self, expr: Expr, alias: impl Into<String>) -> Self {
251 self.items.push(SelectItem::computed(expr, alias));
252 self
253 }
254
255 #[must_use]
257 pub fn filter(mut self, expr: Expr) -> Self {
258 self.filter = Some(expr);
259 self
260 }
261
262 #[must_use]
264 pub fn order_by(mut self, column: impl Into<String>, direction: OrderDir) -> Self {
265 let order = OrderBy::new(column, direction);
266 self.order_by.push(order.clone());
267 self.order_by_items.push(OrderByItem::Column(order));
268 self
269 }
270
271 #[must_use]
273 pub fn order_by_asc(mut self, column: impl Into<String>) -> Self {
274 let order = OrderBy::asc(column);
275 self.order_by.push(order.clone());
276 self.order_by_items.push(OrderByItem::Column(order));
277 self
278 }
279
280 #[must_use]
282 pub fn order_by_desc(mut self, column: impl Into<String>) -> Self {
283 let order = OrderBy::desc(column);
284 self.order_by.push(order.clone());
285 self.order_by_items.push(OrderByItem::Column(order));
286 self
287 }
288
289 #[must_use]
294 pub fn take(mut self, n: i32) -> Self {
295 self.take = Some(n);
296 self
297 }
298
299 #[must_use]
301 pub fn skip(mut self, n: u32) -> Self {
302 self.skip = Some(n);
303 self
304 }
305
306 #[must_use]
308 pub fn join(mut self, clause: JoinClause) -> Self {
309 self.joins.push(clause);
310 self
311 }
312
313 #[must_use]
315 pub fn inner_join(self, table: impl Into<String>, on: Expr, items: Vec<SelectItem>) -> Self {
316 self.join(JoinClause::new(JoinType::Inner, table, on, items))
317 }
318
319 #[must_use]
321 pub fn left_join(self, table: impl Into<String>, on: Expr, items: Vec<SelectItem>) -> Self {
322 self.join(JoinClause::new(JoinType::Left, table, on, items))
323 }
324
325 #[must_use]
327 pub fn group_by_column(mut self, column: ColumnMarker) -> Self {
328 self.group_by.push(column);
329 self
330 }
331
332 #[must_use]
334 pub fn group_by(mut self, columns: Vec<ColumnMarker>) -> Self {
335 self.group_by.extend(columns);
336 self
337 }
338
339 #[must_use]
341 pub fn having(mut self, expr: Expr) -> Self {
342 self.having = Some(expr);
343 self
344 }
345
346 #[must_use]
348 pub fn order_by_expr(mut self, expr: Expr, direction: OrderDir) -> Self {
349 self.order_by_exprs.push((expr.clone(), direction));
350 self.order_by_items.push(OrderByItem::Expr(expr, direction));
351 self
352 }
353
354 #[must_use]
360 pub fn distinct(mut self, columns: Vec<String>) -> Self {
361 self.distinct = columns;
362 self
363 }
364
365 pub fn build(self) -> Result<Select> {
367 if self.table.is_empty() {
368 return Err(Error::MissingField("table".to_string()));
369 }
370
371 Ok(Select {
372 table: self.table,
373 items: self.items,
374 joins: self.joins,
375 filter: self.filter,
376 order_by: self.order_by,
377 take: self.take,
378 skip: self.skip,
379 group_by: self.group_by,
380 distinct: self.distinct,
381 having: self.having,
382 order_by_items: self.order_by_items,
383 order_by_exprs: self.order_by_exprs,
384 })
385 }
386}
387
388#[cfg(test)]
389mod tests {
390 use super::*;
391 use crate::expr::Expr;
392
393 #[test]
394 fn test_order_by() {
395 let asc = OrderBy::asc("id");
396 assert_eq!(asc.column, "id");
397 assert_eq!(asc.direction, OrderDir::Asc);
398
399 let desc = OrderBy::desc("created_at");
400 assert_eq!(desc.column, "created_at");
401 assert_eq!(desc.direction, OrderDir::Desc);
402 }
403
404 #[test]
405 fn test_simple_select() {
406 let query = Select::from_table("users").build().unwrap();
407
408 assert_eq!(query.table, "users");
409 assert!(query.items.is_empty());
410 assert!(query.joins.is_empty());
411 assert!(query.filter.is_none());
412 assert!(query.order_by.is_empty());
413 assert!(query.take.is_none());
414 assert!(query.skip.is_none());
415 }
416
417 #[test]
418 fn test_select_with_columns() {
419 let query = Select::from_table("users")
420 .item(SelectItem::from(ColumnMarker::new("users", "id")))
421 .item(SelectItem::from(ColumnMarker::new("users", "email")))
422 .build()
423 .unwrap();
424
425 assert_eq!(query.items.len(), 2);
426 if let SelectItem::Column(col) = &query.items[0] {
427 assert_eq!(col.table, "users");
428 assert_eq!(col.name, "id");
429 }
430 if let SelectItem::Column(col) = &query.items[1] {
431 assert_eq!(col.table, "users");
432 assert_eq!(col.name, "email");
433 }
434 }
435
436 #[test]
437 fn test_select_with_filter() {
438 let filter = Expr::column("age").ge(Expr::param(18i64));
439 let query = Select::from_table("users")
440 .filter(filter.clone())
441 .build()
442 .unwrap();
443
444 assert_eq!(query.filter, Some(filter));
445 }
446
447 #[test]
448 fn test_select_with_order_by() {
449 let query = Select::from_table("users")
450 .order_by_desc("created_at")
451 .order_by_asc("email")
452 .build()
453 .unwrap();
454
455 assert_eq!(query.order_by.len(), 2);
456 assert_eq!(query.order_by[0].column, "created_at");
457 assert_eq!(query.order_by[0].direction, OrderDir::Desc);
458 assert_eq!(query.order_by[1].column, "email");
459 assert_eq!(query.order_by[1].direction, OrderDir::Asc);
460 }
461
462 #[test]
463 fn test_select_with_take_and_skip() {
464 let query = Select::from_table("users")
465 .take(10)
466 .skip(20)
467 .build()
468 .unwrap();
469
470 assert_eq!(query.take, Some(10));
471 assert_eq!(query.skip, Some(20));
472 }
473
474 #[test]
475 fn test_complex_select() {
476 let filter = Expr::column("age")
477 .ge(Expr::param(18i64))
478 .and(Expr::column("email").like(Expr::param("%@gmail.com")));
479
480 let query = Select::from_table("users")
481 .items(vec![
482 SelectItem::from(ColumnMarker::new("users", "id")),
483 SelectItem::from(ColumnMarker::new("users", "email")),
484 SelectItem::from(ColumnMarker::new("users", "age")),
485 ])
486 .filter(filter)
487 .order_by_desc("id")
488 .take(10)
489 .build()
490 .unwrap();
491
492 assert_eq!(query.table, "users");
493 assert_eq!(query.items.len(), 3);
494 assert!(query.filter.is_some());
495 assert_eq!(query.order_by.len(), 1);
496 assert_eq!(query.take, Some(10));
497 }
498
499 #[test]
500 fn test_select_with_inner_join() {
501 let on = Expr::column("users__id").eq(Expr::column("posts__user_id"));
502 let query = Select::from_table("users")
503 .item(SelectItem::from(ColumnMarker::new("users", "id")))
504 .inner_join(
505 "posts",
506 on.clone(),
507 vec![
508 SelectItem::from(ColumnMarker::new("posts", "id")),
509 SelectItem::from(ColumnMarker::new("posts", "title")),
510 ],
511 )
512 .build()
513 .unwrap();
514
515 assert_eq!(query.joins.len(), 1);
516 assert_eq!(query.joins[0].join_type, JoinType::Inner);
517 assert_eq!(query.joins[0].table, "posts");
518 assert_eq!(query.joins[0].on, on);
519 assert_eq!(query.joins[0].items.len(), 2);
520 }
521
522 #[test]
523 fn test_select_with_left_join() {
524 let on = Expr::column("users__id").eq(Expr::column("posts__user_id"));
525 let query = Select::from_table("users")
526 .item(SelectItem::from(ColumnMarker::new("users", "id")))
527 .left_join(
528 "posts",
529 on,
530 vec![SelectItem::from(ColumnMarker::new("posts", "title"))],
531 )
532 .build()
533 .unwrap();
534
535 assert_eq!(query.joins.len(), 1);
536 assert_eq!(query.joins[0].join_type, JoinType::Left);
537 assert_eq!(query.joins[0].table, "posts");
538 assert_eq!(query.joins[0].items.len(), 1);
539 }
540
541 #[test]
542 fn test_select_with_multiple_joins() {
543 let query = Select::from_table("users")
544 .inner_join(
545 "posts",
546 Expr::column("users__id").eq(Expr::column("posts__user_id")),
547 vec![SelectItem::from(ColumnMarker::new("posts", "title"))],
548 )
549 .left_join(
550 "comments",
551 Expr::column("posts__id").eq(Expr::column("comments__post_id")),
552 vec![SelectItem::from(ColumnMarker::new("comments", "body"))],
553 )
554 .build()
555 .unwrap();
556
557 assert_eq!(query.joins.len(), 2);
558 assert_eq!(query.joins[0].join_type, JoinType::Inner);
559 assert_eq!(query.joins[0].table, "posts");
560 assert_eq!(query.joins[1].join_type, JoinType::Left);
561 assert_eq!(query.joins[1].table, "comments");
562 }
563}