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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
use filter::Filter;
use join::Join;
use join::Modifier;
use join::JoinType;
pub enum Direction{
ASC,
DESC,
}
pub enum SqlType{
//DML
Select,
Insert,
Update,
Delete,
Truncate,
//DDL
Create,
Drop,
Alter,
}
pub struct ColumnName{
column:String,
table:String,
////optional schema, if ever there are same tables resideing in different schema/namespace
schema:Option<String>,
rename:Option<String>
}
impl ColumnName{
fn rename(&self)->String{
return format!("{}_{}", self.table, self.column)
}
}
pub struct Query{
///sql type determine which type of query to form, some fields are not applicable to other types of query
pub sql_type:SqlType,
///whether to use *
pub select_all:bool,
/// whether to select the records distinct
pub distinct:bool,
/// enumerate all the columns of the table involved in the query
pub enumerate_columns:bool,
///or whether to select columns
pub enumerated_columns:Vec<ColumnName>,
/// list of renamed columns whenever there is a conflict
/// Vec(table, column, new_column_name)
pub renamed_columns:Vec<(String, String, String)>,
/// specify to use distinct ON set of columns
pub distinct_on_columns:Vec<String>,
/// filter records, ~ where statement of the query
pub filters:Vec<Filter>,
/// joining multiple tables
pub joins:Vec<Join>,
/// ordering of the records via the columns specified
pub order_by:Vec<(String, Direction)>,
/// list of involved tables
pub involved_tables:Vec<String>,
/// grouping columns to create an aggregate
pub grouped_columns: Vec<String>,
/// exclude the mention of the columns in the SQL query, useful when ignoring changes in update/insert records
pub excluded_columns:Vec<ColumnName>,
/// paging of records
pub page:Option<usize>,
/// size of a page
pub items_per_page:Option<usize>,
/// where the focus of values of column selection
/// this is the table to insert to, update to delete, create, drop
/// whe used in select, this is the
pub from_table:Option<String>,
}
impl Query{
//the default query is select
pub fn new()->Self{
Query{
sql_type:SqlType::Select,
select_all:false,
distinct:false,
enumerate_columns:true,
enumerated_columns:Vec::new(),
renamed_columns:Vec::new(),
distinct_on_columns:Vec::new(),
filters:Vec::new(),
joins:Vec::new(),
order_by:Vec::new(),
involved_tables:Vec::new(),
grouped_columns:Vec::new(),
excluded_columns:Vec::new(),
page:None,
items_per_page:None,
from_table:None,
}
}
pub fn select()->Self{
let mut q = Query::new();
q.sql_type = SqlType::Select;
q
}
pub fn insert()->Self{
let mut q = Query::new();
q.sql_type = SqlType::Insert;
q
}
pub fn update()->Self{
let mut q = Query::new();
q.sql_type = SqlType::Update;
q
}
pub fn delete()->Self{
let mut q = Query::new();
q.sql_type = SqlType::Delete;
q
}
pub fn create()->Self{
let mut q = Query::new();
q.sql_type = SqlType::Create;
q
}
//add DISTINCT ie: SELECT DISTINCT
pub fn set_distinct(&mut self){
self.distinct = true;
}
//enumerate all the columns involved in the query
pub fn enumerate(&mut self){
self.select_all = false;
self.enumerate_columns = true;
}
/// all enumerated columns shall be called from this
/// any conflict of columns from some other table will be automatically renamed
/// columns that are not conflicts from some other table,
/// but is the other conflicting column is not explicityly enumerated will not be renamed
///
pub fn enumerate_column(&mut self, table:&String, column:&String){
let c = ColumnName{
column:column.clone(),
table:table.clone(),
schema:None,
rename:None
};
self.enumerated_columns.push(c);
}
/// exclude columns when inserting/updating data
/// [FIXME] ?? remove from the enumerated_columns
/// can this be called before the mentioned of the enumerated column?
/// else these needs to be stored and have a final list of columns
/// that is mentioned in the query
pub fn exclude_column(&mut self, table:&String, column:&String){
let c = ColumnName{
column:column.clone(),
table:table.clone(),
schema:None,
rename:None,
};
self.excluded_columns.push(c);
}
pub fn distinct_on_columns(&mut self, columns:&Vec<String>){
let columns = columns.clone();
for c in columns{
self.distinct_on_columns.push(c);
}
}
pub fn set_page(&mut self, page:usize){
self.page = Some(page);
}
pub fn set_items_per_page(&mut self, items:usize){
self.items_per_page = Some(items);
}
pub fn from_table(&mut self, table:&String){
self.from_table = Some(table.clone());
self.involved_tables.push(table.clone());
}
/// join a table on this query
///
// # Examples
//
// ```
// let mut q = Query::new();
// let join = Join{
// modifier:Some(Modifier::LEFT),
// join_type:Type::OUTER,
// table:table,
// column1:vec![column1],
// column2:vec![column2]
// };
//
// q.join(join);
//
// ```
pub fn join(&mut self, join:Join){
self.involved_tables.push(join.table.clone());
self.joins.push(join);
}
/// join a table on this query
///
// # Examples
//
// ```
// let mut q = Query::new();
// q.select_from_table("users");
// q.left_join("roles", "role_id", "role_id");
//
// ```
pub fn left_join(&mut self, table:String, column1:String, column2:String){
let join = Join{
modifier:Some(Modifier::LEFT),
join_type:JoinType::OUTER,
table:table,
column1:vec![column1],
column2:vec![column2]
};
self.join(join);
}
pub fn right_join(&mut self, table:String, column1:String, column2:String){
let join = Join{
modifier:Some(Modifier::RIGHT),
join_type:JoinType::OUTER,
table:table,
column1:vec![column1],
column2:vec![column2]
};
self.join(join);
}
pub fn full_join(&mut self, table:String, column1:String, column2:String){
let join = Join{
modifier:Some(Modifier::FULL),
join_type:JoinType::OUTER,
table:table,
column1:vec![column1],
column2:vec![column2]
};
self.join(join);
}
pub fn inner_join(&mut self, table:String, column1:String, column2:String){
let join = Join{
modifier:None,
join_type:JoinType::INNER,
table:table,
column1:vec![column1],
column2:vec![column2]
};
self.join(join);
}
///ascending orderby of this column
pub fn asc(&mut self, column:String){
self.order_by.push((column, Direction::ASC));
}
///ascending orderby of this column
pub fn desc(&mut self, column:String){
self.order_by.push((column, Direction::DESC));
}
pub fn rename(&mut self, table:String, column:String, new_column_name:String){
self.renamed_columns.push((table, column, new_column_name));
}
}