1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use super::{
    join::{Join, JoinType},
    where_::{Combiner, Where},
};

pub struct Select<'a> {
    distinct: bool,
    from: &'a str,
    limit: u32,
    offset: u32,
    columns: &'a str,
    where_: Where,
    group: &'a str,
    order: &'a str,

    joins: Vec<Join>,
}

#[allow(dead_code)]
impl<'a> Select<'a> {
    pub fn new() -> Select<'a> {
        Select {
            distinct: false,
            from: "",
            limit: 0,
            offset: 0,
            columns: "",
            where_: Where::new(Combiner::And),
            group: "",
            order: "",
            joins: vec![],
        }
    }

    pub fn distinct(&mut self) -> &mut Select<'a> {
        self.distinct = true;
        self
    }

    pub fn from(&mut self, from: &'a str) -> &mut Select<'a> {
        self.from = from;
        self
    }

    pub fn columns(&mut self, columns: &'a str) -> &mut Select<'a> {
        self.columns = columns;
        self
    }

    pub fn where_(&mut self, where_: Where) -> &mut Select<'a> {
        self.where_ = where_;
        self
    }

    pub fn join(&mut self, table: &str, on: &str, join_type: JoinType) -> &mut Select<'a> {
        self.joins
            .push(Join::new(table.to_string(), on.to_string(), join_type));
        self
    }

    pub fn group(&mut self, group: &'a str) -> &mut Select<'a> {
        self.group = group;
        self
    }

    pub fn order(&mut self, order: &'a str) -> &mut Select<'a> {
        self.order = order;
        self
    }

    pub fn limit(&mut self, limit: u32) -> &mut Select<'a> {
        self.limit = limit;
        self
    }

    pub fn offset(&mut self, offset: u32) -> &mut Select<'a> {
        self.offset = offset;
        self
    }

    pub fn build(&self) -> String {
        let mut statement = "SELECT ".to_string();

        if self.distinct {
            statement.push_str("DISTINCT ");
        }

        if self.columns.len() > 0 {
            statement.push_str(&format!("{} ", self.columns.trim_end()));
        } else {
            statement.push_str("* ");
        }

        if self.from.len() > 0 {
            statement.push_str(&format!("FROM {} ", self.from));
        }

        if self.joins.len() > 0 {
            for join in &self.joins {
                statement.push_str(&join.build());
            }
        }

        statement.push_str(&self.where_.build());

        if self.group.len() > 0 {
            statement.push_str(" GROUP BY ");
            statement.push_str(&format!("{}", self.group.trim_end()));
        }

        if self.order.len() > 0 {
            statement.push_str(" ORDER BY ");
            statement.push_str(&format!("{}", self.order.trim_end()));
        }

        if self.limit > 0 {
            statement.push_str(&format!(" LIMIT {}", self.limit));
        }

        if self.offset > 0 && self.limit > 0 {
            statement.push_str(&format!(" OFFSET {}", self.offset));
        }

        statement = statement.trim().to_string() + ";";
        statement
    }
}