1use crate::{IntoOperator, Operator, Result, Value};
4
5pub trait QueryBuilder {
7 fn to_sql(&self) -> Result<String>;
9
10 fn parameters(&self) -> &[Value];
12
13 fn clone_builder(&self) -> Self
15 where
16 Self: Sized;
17}
18
19pub trait IntoCondition {
21 fn into_condition(self) -> (String, Operator, Value);
22}
23
24impl<T> IntoCondition for (&str, T)
26where
27 T: Into<Value>,
28{
29 fn into_condition(self) -> (String, Operator, Value) {
30 (self.0.to_string(), Operator::EQ, self.1.into())
31 }
32}
33
34impl<T, O> IntoCondition for (&str, O, T)
36where
37 T: Into<Value>,
38 O: IntoOperator,
39{
40 fn into_condition(self) -> (String, Operator, Value) {
41 (self.0.to_string(), self.1.into_operator(), self.2.into())
42 }
43}
44
45#[derive(Debug, Clone, PartialEq)]
47pub struct WhereCondition {
48 pub column: String,
49 pub operator: Operator,
50 pub value: Value,
51 pub connector: WhereConnector,
52}
53
54#[derive(Debug, Clone, PartialEq)]
56pub enum WhereConnector {
57 And,
58 Or,
59}
60
61#[derive(Debug, Clone, PartialEq)]
63pub enum AggregateFunction {
64 Count,
65 CountDistinct,
66 Sum,
67 Avg,
68 Min,
69 Max,
70}
71
72impl std::fmt::Display for AggregateFunction {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 match self {
75 AggregateFunction::Count => write!(f, "COUNT"),
76 AggregateFunction::CountDistinct => write!(f, "COUNT(DISTINCT"),
77 AggregateFunction::Sum => write!(f, "SUM"),
78 AggregateFunction::Avg => write!(f, "AVG"),
79 AggregateFunction::Min => write!(f, "MIN"),
80 AggregateFunction::Max => write!(f, "MAX"),
81 }
82 }
83}
84
85#[derive(Debug, Clone)]
87pub enum ColumnSelector {
88 Column(String),
89 Aggregate {
90 function: AggregateFunction,
91 column: String,
92 alias: Option<String>,
93 },
94 CountAll {
95 alias: Option<String>,
96 },
97 }
99
100impl ColumnSelector {
101 pub fn count() -> Self {
103 Self::CountAll { alias: None }
104 }
105
106 pub fn count_as(alias: &str) -> Self {
108 Self::CountAll {
109 alias: Some(alias.to_string()),
110 }
111 }
112
113 pub fn count_column(column: &str) -> Self {
115 Self::Aggregate {
116 function: AggregateFunction::Count,
117 column: column.to_string(),
118 alias: None,
119 }
120 }
121
122 pub fn count_distinct(column: &str) -> Self {
124 Self::Aggregate {
125 function: AggregateFunction::CountDistinct,
126 column: column.to_string(),
127 alias: None,
128 }
129 }
130
131 pub fn sum(column: &str) -> Self {
133 Self::Aggregate {
134 function: AggregateFunction::Sum,
135 column: column.to_string(),
136 alias: None,
137 }
138 }
139
140 pub fn avg(column: &str) -> Self {
142 Self::Aggregate {
143 function: AggregateFunction::Avg,
144 column: column.to_string(),
145 alias: None,
146 }
147 }
148
149 pub fn min(column: &str) -> Self {
151 Self::Aggregate {
152 function: AggregateFunction::Min,
153 column: column.to_string(),
154 alias: None,
155 }
156 }
157
158 pub fn max(column: &str) -> Self {
160 Self::Aggregate {
161 function: AggregateFunction::Max,
162 column: column.to_string(),
163 alias: None,
164 }
165 }
166
167 pub fn as_alias(mut self, alias: &str) -> Self {
169 match self {
170 Self::Column(_) => {
171 self
174 }
175 Self::Aggregate {
176 alias: ref mut alias_field,
177 ..
178 } => {
179 *alias_field = Some(alias.to_string());
180 self
181 }
182 Self::CountAll {
183 alias: ref mut alias_field,
184 } => {
185 *alias_field = Some(alias.to_string());
186 self
187 } }
189 }
190
191 }
193
194pub trait IntoColumns {
196 fn into_columns(self) -> Vec<String>;
197}
198
199impl IntoColumns for &str {
200 fn into_columns(self) -> Vec<String> {
201 vec![self.to_string()]
202 }
203}
204
205impl IntoColumns for String {
206 fn into_columns(self) -> Vec<String> {
207 vec![self]
208 }
209}
210
211impl IntoColumns for Vec<String> {
212 fn into_columns(self) -> Vec<String> {
213 self
214 }
215}
216
217impl IntoColumns for Vec<&str> {
218 fn into_columns(self) -> Vec<String> {
219 self.into_iter().map(|s| s.to_string()).collect()
220 }
221}
222
223impl IntoColumns for (&str, &str) {
225 fn into_columns(self) -> Vec<String> {
226 vec![self.0.to_string(), self.1.to_string()]
227 }
228}
229
230impl IntoColumns for (&str, &str, &str) {
231 fn into_columns(self) -> Vec<String> {
232 vec![self.0.to_string(), self.1.to_string(), self.2.to_string()]
233 }
234}
235
236impl IntoColumns for (&str, &str, &str, &str) {
237 fn into_columns(self) -> Vec<String> {
238 vec![
239 self.0.to_string(),
240 self.1.to_string(),
241 self.2.to_string(),
242 self.3.to_string(),
243 ]
244 }
245}
246
247impl IntoColumns for (&str, &str, &str, &str, &str) {
248 fn into_columns(self) -> Vec<String> {
249 vec![
250 self.0.to_string(),
251 self.1.to_string(),
252 self.2.to_string(),
253 self.3.to_string(),
254 self.4.to_string(),
255 ]
256 }
257}
258
259#[derive(Debug, Clone, PartialEq)]
261pub enum JoinType {
262 Inner,
263 Left,
264 Right,
265 Full,
266 Cross,
267}
268
269impl std::fmt::Display for JoinType {
270 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
271 match self {
272 JoinType::Inner => write!(f, "INNER"),
273 JoinType::Left => write!(f, "LEFT"),
274 JoinType::Right => write!(f, "RIGHT"),
275 JoinType::Full => write!(f, "FULL OUTER"),
276 JoinType::Cross => write!(f, "CROSS"),
277 }
278 }
279}
280
281#[derive(Debug, Clone, PartialEq)]
283pub enum JoinConnector {
284 And,
285 Or,
286}
287
288#[derive(Debug, Clone, PartialEq)]
290pub struct JoinCondition {
291 pub left_column: String,
292 pub operator: Operator,
293 pub right_column: String,
294 pub connector: JoinConnector,
295}
296
297#[derive(Debug, Clone, PartialEq)]
299pub struct JoinClause {
300 pub join_type: JoinType,
301 pub table: String,
302 pub on_conditions: Vec<JoinCondition>,
303}
304
305#[derive(Debug, Clone, PartialEq)]
307pub enum SortDirection {
308 Asc,
309 Desc,
310}
311
312impl std::fmt::Display for SortDirection {
313 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
314 match self {
315 SortDirection::Asc => write!(f, "ASC"),
316 SortDirection::Desc => write!(f, "DESC"),
317 }
318 }
319}
320
321#[derive(Debug, Clone, PartialEq)]
323pub struct OrderByClause {
324 pub column: String,
325 pub direction: SortDirection,
326}
327
328#[derive(Debug, Clone, PartialEq)]
330pub struct GroupByClause {
331 pub columns: Vec<String>,
332}
333
334#[derive(Debug, Clone, PartialEq)]
336pub struct HavingCondition {
337 pub column_or_function: String,
338 pub operator: Operator,
339 pub value: Value,
340 pub connector: WhereConnector,
341}
342
343pub trait IntoColumnSelectors {
345 fn into_column_selectors(self) -> Vec<crate::ColumnSelector>;
346}
347
348impl IntoColumnSelectors for &str {
349 fn into_column_selectors(self) -> Vec<crate::ColumnSelector> {
350 vec![crate::ColumnSelector::Column(self.to_string())]
351 }
352}
353
354impl IntoColumnSelectors for String {
355 fn into_column_selectors(self) -> Vec<crate::ColumnSelector> {
356 vec![crate::ColumnSelector::Column(self)]
357 }
358}
359
360impl IntoColumnSelectors for Vec<String> {
361 fn into_column_selectors(self) -> Vec<crate::ColumnSelector> {
362 self.into_iter()
363 .map(|s| crate::ColumnSelector::Column(s))
364 .collect()
365 }
366}
367
368impl IntoColumnSelectors for Vec<&str> {
369 fn into_column_selectors(self) -> Vec<crate::ColumnSelector> {
370 self.into_iter()
371 .map(|s| crate::ColumnSelector::Column(s.to_string()))
372 .collect()
373 }
374}
375
376impl IntoColumnSelectors for crate::ColumnSelector {
377 fn into_column_selectors(self) -> Vec<crate::ColumnSelector> {
378 vec![self]
379 }
380}
381
382impl IntoColumnSelectors for Vec<crate::ColumnSelector> {
383 fn into_column_selectors(self) -> Vec<crate::ColumnSelector> {
384 self
385 }
386}
387
388impl IntoColumnSelectors for (&str, &str) {
390 fn into_column_selectors(self) -> Vec<crate::ColumnSelector> {
391 vec![
392 crate::ColumnSelector::Column(self.0.to_string()),
393 crate::ColumnSelector::Column(self.1.to_string()),
394 ]
395 }
396}
397
398impl IntoColumnSelectors for (&str, &str, &str) {
399 fn into_column_selectors(self) -> Vec<crate::ColumnSelector> {
400 vec![
401 crate::ColumnSelector::Column(self.0.to_string()),
402 crate::ColumnSelector::Column(self.1.to_string()),
403 crate::ColumnSelector::Column(self.2.to_string()),
404 ]
405 }
406}
407
408impl IntoColumnSelectors for (&str, &str, &str, &str) {
409 fn into_column_selectors(self) -> Vec<crate::ColumnSelector> {
410 vec![
411 crate::ColumnSelector::Column(self.0.to_string()),
412 crate::ColumnSelector::Column(self.1.to_string()),
413 crate::ColumnSelector::Column(self.2.to_string()),
414 crate::ColumnSelector::Column(self.3.to_string()),
415 ]
416 }
417}
418
419impl IntoColumnSelectors for (&str, &str, &str, &str, &str) {
420 fn into_column_selectors(self) -> Vec<crate::ColumnSelector> {
421 vec![
422 crate::ColumnSelector::Column(self.0.to_string()),
423 crate::ColumnSelector::Column(self.1.to_string()),
424 crate::ColumnSelector::Column(self.2.to_string()),
425 crate::ColumnSelector::Column(self.3.to_string()),
426 crate::ColumnSelector::Column(self.4.to_string()),
427 ]
428 }
429}
430
431impl IntoColumnSelectors for (&str, crate::ColumnSelector) {
433 fn into_column_selectors(self) -> Vec<crate::ColumnSelector> {
434 vec![crate::ColumnSelector::Column(self.0.to_string()), self.1]
435 }
436}
437
438impl IntoColumnSelectors for (&str, crate::ColumnSelector, crate::ColumnSelector) {
439 fn into_column_selectors(self) -> Vec<crate::ColumnSelector> {
440 vec![
441 crate::ColumnSelector::Column(self.0.to_string()),
442 self.1,
443 self.2,
444 ]
445 }
446}
447
448impl IntoColumnSelectors for (crate::ColumnSelector, &str, crate::ColumnSelector) {
449 fn into_column_selectors(self) -> Vec<crate::ColumnSelector> {
450 vec![
451 self.0,
452 crate::ColumnSelector::Column(self.1.to_string()),
453 self.2,
454 ]
455 }
456}
457
458#[cfg(test)]
463mod tests {
464 use super::*;
465 use crate::operator::op;
466
467 #[test]
468 fn test_string_operator_conversion() {
469 let condition = ("age", ">", 18);
471 let (column, operator, value) = condition.into_condition();
472 assert_eq!(column, "age");
473 assert_eq!(operator, op::GT);
474 assert_eq!(value, 18.into());
475 }
476
477 #[test]
478 fn test_condition_trait_implementations() {
479 let condition = ("name", "John");
481 let (column, operator, value) = condition.into_condition();
482 assert_eq!(column, "name");
483 assert_eq!(operator, op::EQ);
484 assert_eq!(value, "John".into());
485
486 let condition = ("age", op::GT, 18);
488 let (column, operator, value) = condition.into_condition();
489 assert_eq!(column, "age");
490 assert_eq!(operator, op::GT);
491 assert_eq!(value, 18.into());
492 }
493
494 #[test]
495 fn test_into_columns_implementations() {
496 let cols = "name".into_columns();
498 assert_eq!(cols, vec!["name"]);
499
500 let cols = ("name", "age").into_columns();
502 assert_eq!(cols, vec!["name", "age"]);
503
504 let cols = vec!["name", "age"].into_columns();
506 assert_eq!(cols, vec!["name", "age"]);
507 }
508}