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
use std::borrow::Cow;
use crate::query::escape_wisdom;
use crate::schema::dialect::SQLDialect;
use crate::schema::value::encode::{SQLEscape, ToSQLString};

pub mod r#where;

pub struct SQLSelectStatement<'a> {
    pub(crate) columns: Option<&'a Vec<&'a str>>,
    pub(crate) from: &'a str,
    pub(crate) r#where: Option<String>,
    pub(crate) left_join: Option<String>,
    pub(crate) inner_join: Option<String>,
    pub(crate) order_by: Option<String>,
    pub(crate) limit: Option<(u64, u64)>,
}

impl<'a> SQLSelectStatement<'a> {

    pub fn left_join(&mut self, left_join: String) -> &mut Self {
        self.left_join = Some(left_join);
        self
    }

    pub fn inner_join(&mut self, inner_join: String) -> &mut Self {
        self.inner_join = Some(inner_join);
        self
    }

    pub fn r#where(&mut self, r#where: String) -> &mut Self {
        if r#where.as_str() == "" || r#where.as_str() == "()" {
            self.r#where = None;
        } else {
            self.r#where = Some(r#where);
        }
        self
    }

    pub fn order_by(&mut self, order_by: String) -> &mut Self {
        self.order_by = Some(order_by);
        self
    }

    pub fn limit(&mut self, limit: u64, skip: u64) -> &mut Self {
        self.limit = Some((limit, skip));
        self
    }
}

impl<'a> ToSQLString for SQLSelectStatement<'a> {
    fn to_string(&self, dialect: SQLDialect) -> String {
        let columns = if self.columns.is_none() { "*".to_owned() } else { self.columns.unwrap().iter().map(|c| {
            escape_wisdom(c, dialect)
        }).collect::<Vec<_>>().join(", ") };
        let left_join = if let Some(left_join) = &self.left_join {
            " LEFT JOIN ".to_owned() + left_join
        } else {
            "".to_owned()
        };
        let inner_join = if let Some(inner_join) = &self.inner_join {
            " INNER JOIN ".to_owned() + &if inner_join.is_escaped() {
                Cow::Borrowed(inner_join.as_str())
            } else {
                Cow::Owned(inner_join.escape(dialect))
            }
        } else {
            "".to_owned()
        };
        let r#where = if let Some(r#where) = &self.r#where {
            if !r#where.is_empty() {
                " WHERE ".to_owned() + r#where
            } else {
                "".to_owned()
            }
        } else {
            "".to_owned()
        };
        let order_by = if let Some(order_by) = &self.order_by {
            " ORDER BY ".to_owned() + order_by
        } else {
            "".to_owned()
        };
        let limit = if let Some(limit) = &self.limit {
            if dialect == SQLDialect::PostgreSQL {
                format!(" LIMIT {} OFFSET {}", limit.0, limit.1)
            } else {
                format!(" LIMIT {},{}", limit.1, limit.0)
            }
        } else {
            "".to_owned()
        };
        let escape = dialect.escape();
        let from_escaped = if self.from.starts_with("'") || self.from.starts_with("\"") || self.from.starts_with("`") {
            Cow::Borrowed(self.from)
        } else {
            Cow::Owned(format!("{}{}{}", escape, self.from, escape))
        };
        format!("SELECT {columns} from {}{}{}{}{}{}", from_escaped, left_join, inner_join, r#where, order_by, limit)
    }
}