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
use std::fmt;
use crate::{Eloquent, error::EloquentError, Direction};

use super::formattable::Formattable;

pub struct OrderClauses {
    pub clauses: Vec<OrderClause>,
}

pub struct OrderClause {
    pub column: String,
    pub direction: Direction,
}

impl Eloquent {
    pub fn order_by(&mut self, column_name: String, direction: Direction) -> &mut Eloquent {
        self.order_clauses.clauses.push(OrderClause {
            column: column_name,
            direction,
        });

        self
    }
}

impl fmt::Display for Direction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Direction::Asc => write!(f, "ASC"),
            Direction::Desc => write!(f, "DESC"),
        }
    }
}

impl Formattable for OrderClauses {
    fn to_query_format(&self) -> Result<String, EloquentError> {
        if self.clauses.is_empty() {
            return Ok("".to_string());
        }

        let mut query: String = " ORDER BY ".to_owned();

        let mut order_clauses = self.clauses.iter().peekable();

        while let Some(clause) = order_clauses.next() {
            let comma_or_empty;

            if order_clauses.peek().is_some() {
                comma_or_empty = ", ";
            } else {
                comma_or_empty = "";
            }

            let item = format!("{} {}{}",
                clause.column,
                clause.direction,
                comma_or_empty,
            );

            query.push_str(&item);
        }

        Ok(query)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_can_order_by_a_single_column_asc() {
        let query = Eloquent::query()
            .table("users".to_string())
            .order_by("id".to_string(), Direction::Asc)
            .to_sql()
            .unwrap();

        assert_eq!(query, "SELECT * FROM users ORDER BY id ASC;");
    }

    #[test]
    fn it_can_order_by_a_single_column_desc() {
        let query = Eloquent::query()
            .table("users".to_string())
            .order_by("id".to_string(), Direction::Desc)
            .to_sql()
            .unwrap();

        assert_eq!(query, "SELECT * FROM users ORDER BY id DESC;");
    }

    #[test]
    fn it_can_order_by_multiple_columns() {
        let query = Eloquent::query()
            .table("flights".to_string())
            .order_by("destination".to_string(), Direction::Asc)
            .order_by("terminal_id".to_string(), Direction::Desc)
            .to_sql()
            .unwrap();

        assert_eq!(query, "SELECT * FROM flights ORDER BY destination ASC, terminal_id DESC;");
    }
}