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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
use std::path::Path;
use json::{JsonValue, object};
use crate::mode::Mode;

#[derive(Clone, Debug)]
pub enum Charset {
    Utf8mb4,
    Utf8,
}

impl Charset {
    pub fn from(str: &str) -> Charset {
        match str {
            "utf8" => Charset::Utf8,
            "utf8mb4" => Charset::Utf8mb4,
            _ => Charset::Utf8mb4
        }
    }
}


#[derive(Clone)]
pub struct Config {
    pub db_mode: Mode,
    pub keyauto: bool,
    pub hostname: String,
    pub hostport: String,
    pub database: String,
    pub username: String,
    pub userpass: String,
    pub charset: String,
    pub prefix: String,
    pub params: Vec<String>,
    pub debug: bool,
}

impl Config {
    pub fn get_dsn(self) -> String {
        match self.db_mode {
            Mode::Mysql => {
                format!("mysql://{}:{}@{}:{}/{}", self.username, self.userpass, self.hostname, self.hostport, self.database)
            }
            Mode::Sqlite => {
                let data = Path::new(self.hostname.as_str());
                let data = data.join(format!("{}.db", self.database));
                format!("{}", data.to_str().unwrap())
            }
            Mode::Mssql => {
                format!("sqlsrv://{}:{}@{}:{}/{}", self.username, self.userpass, self.hostname, self.hostport, self.database)
            }
        }
    }
}

#[derive(Clone)]
pub struct Params {
    pub mode: Mode,
    pub table: String,
    pub where_and: Vec<String>,
    pub where_or: Vec<String>,
    pub page: i32,
    pub limit: i32,
    pub fields: JsonValue,
    pub top: String,
    pub order: JsonValue,
    pub group: JsonValue,
    pub distinct: bool,
    pub json: JsonValue,
}

impl Params {
    pub fn default(mode: Mode) -> Self {
        Self {
            mode,
            table: "".to_string(),
            where_and: vec![],
            where_or: vec![],
            page: -1,
            limit: 10,
            fields: object! {},
            top: String::new(),
            order: object! {},
            group: object! {},
            distinct: false,
            json: object! {},
        }
    }
    pub fn where_sql(&mut self) -> String {
        let mut where_and_sql = String::new();
        let mut where_or_sql = String::new();

        for item in self.where_or.iter() {
            where_or_sql = format!("{} OR {}", where_or_sql, item);
        }
        for item in self.where_and.iter() {
            where_and_sql = format!("{} AND {}", where_and_sql, item);
        }
        if where_and_sql != "" {
            where_and_sql = where_and_sql.trim_start_matches(" AND ").parse().unwrap();
            where_and_sql = format!("WHERE {}", where_and_sql);
        }

        if where_or_sql != "" {
            where_or_sql = where_or_sql.trim_start_matches(" OR ").parse().unwrap();
            if where_and_sql == "" {
                return format!("WHERE {}", where_or_sql);
            } else {
                return format!("{} OR ({})", where_and_sql, where_or_sql);
            }
        }
        where_and_sql
    }
    pub fn page_limit_sql(&mut self) -> String {
        if self.page == -1 {
            return format!("");
        }
        match self.mode {
            Mode::Mysql => {
                return format!("LIMIT {} OFFSET {}", self.page, self.page * self.limit);
            }
            Mode::Sqlite => {
                return format!("LIMIT {} OFFSET {}", self.limit, self.page * self.limit - self.limit);
            }
            Mode::Mssql => {
                return format!("");
            }
        }
    }
    pub fn fields(&mut self) -> String {
        let mut fields = String::new();
        for (_, value) in self.fields.entries() {
            fields = format!("{},{}", fields, value);
        }
        if fields == "" {
            fields = "*".into();
        } else {
            fields = fields.trim_start_matches(",").into();
        }
        match self.mode {
            Mode::Mysql => {
                return format!("{}", fields);
            }
            Mode::Sqlite => {
                return format!("{}", fields);
            }
            Mode::Mssql => {
                return format!("{}", fields);
            }
        }
    }
    pub fn top(&mut self) -> String {
        match self.mode {
            Mode::Mysql | Mode::Sqlite => {
                return format!("");
            }
            Mode::Mssql => {
                return format!("{}", self.top);
            }
        }
    }
    pub fn order(&mut self) -> String {
        let mut sql = String::new();
        for (field, item) in self.order.entries() {
            sql = format!("{} {} {},", sql, field, item);
        }
        if sql != "" {
            sql = format!("ORDER BY {}", sql);
            sql = sql.trim_end_matches(",").parse().unwrap();
        }
        return sql;
    }
    pub fn group(&mut self) -> String {
        let mut sql = String::new();
        for (field, _) in self.group.entries() {
            sql = format!("{} {},", sql, field);
        }
        if sql != "" {
            sql = format!("GROUP BY {}", sql);
            sql = sql.trim_end_matches(",").parse().unwrap();
        }
        return sql;
    }
    pub fn distinct(&self) -> String {
        if self.distinct {
            return "DISTINCT".to_string();
        } else {
            return "".to_string();
        }
    }
    pub fn select_sql(&mut self) -> String {
        return format!("SELECT {} {} {} FROM {} {} {} {} {}", self.distinct(), self.top(), self.fields(), self.table.clone(), self.where_sql(), self.group(), self.order(), self.page_limit_sql());
    }
}