rwf 0.2.1

Framework for building web applications in the Rust programming language
Documentation
//! Implements the `ORDER BY` SQL primitive.
use super::{Column, Escape, ToSql};

#[derive(Debug, Clone)]
pub enum OrderColumn {
    Asc(Column),
    Desc(Column),
    Raw(String),
}

impl ToSql for OrderColumn {
    fn to_sql(&self) -> String {
        use OrderColumn::*;

        match self {
            Asc(column) => format!("{} ASC", column.to_sql()),
            Desc(column) => format!("{} DESC", column.to_sql()),
            Raw(raw) => raw.clone(),
        }
    }
}

pub trait ToOrderBy {
    fn to_order_by(&self) -> OrderBy;
}

impl ToOrderBy for &str {
    fn to_order_by(&self) -> OrderBy {
        OrderBy {
            order_by: vec![OrderColumn::Raw(self.escape())],
        }
    }
}

impl ToOrderBy for [&str; 2] {
    fn to_order_by(&self) -> OrderBy {
        OrderBy {
            order_by: vec![OrderColumn::Raw(format!(
                "{} {}",
                Column::name(self[0]).to_sql(),
                self[1].to_ascii_uppercase().escape()
            ))],
        }
    }
}

impl ToOrderBy for (&str, &str) {
    fn to_order_by(&self) -> OrderBy {
        [self.0, self.1].to_order_by()
    }
}

impl ToOrderBy for (Column, &str) {
    fn to_order_by(&self) -> OrderBy {
        OrderBy {
            order_by: vec![OrderColumn::Raw(format!(
                "{} {}",
                self.0.to_sql(),
                self.1.to_ascii_uppercase().escape()
            ))],
        }
    }
}

#[derive(Debug, Default, Clone)]
pub struct OrderBy {
    pub order_by: Vec<OrderColumn>,
}

impl OrderBy {
    pub fn asc(column: Column) -> Self {
        Self {
            order_by: vec![OrderColumn::Asc(column)],
        }
    }

    pub fn desc(column: Column) -> Self {
        Self {
            order_by: vec![OrderColumn::Desc(column)],
        }
    }

    pub fn is_empty(&self) -> bool {
        self.order_by.is_empty()
    }
}

impl std::ops::Add for OrderBy {
    type Output = OrderBy;

    fn add(mut self, other: OrderBy) -> Self {
        self.order_by.extend(other.order_by);
        self
    }
}

impl ToSql for OrderBy {
    fn to_sql(&self) -> String {
        if self.order_by.is_empty() {
            "".to_string()
        } else {
            format!(
                " ORDER BY {}",
                self.order_by
                    .iter()
                    .map(|column| column.to_sql())
                    .collect::<Vec<_>>()
                    .join(", ")
            )
        }
    }
}

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

    #[test]
    fn test_order_by_raw() {
        let _order_by = "created_at ASC".to_order_by();
        let _order_by = ["created_at", "ASC"].to_order_by();
    }
}