use Result;
use grammar::definition::Column;
use grammar::{Buffer, Clause, Expression};
#[derive(Debug, Default)]
pub struct OrderBy(Vec<Box<Expression>>);
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Order {
Ascending,
Descending,
}
pub trait Orderable where Self: Sized {
type Output;
fn order(self, Option<Order>) -> Self::Output;
fn ascend(self) -> Self::Output {
self.order(Some(Order::Ascending))
}
fn descend(self) -> Self::Output {
self.order(Some(Order::Descending))
}
}
impl OrderBy {
#[doc(hidden)]
pub fn append<T>(mut self, expression: T) -> Self where T: Expression + 'static {
self.0.push(Box::new(expression));
self
}
}
impl Clause for OrderBy {
fn compile(&self) -> Result<String> {
let mut buffer = Buffer::new();
for expression in &self.0 {
buffer.push(try!(expression.compile()));
}
Ok(format!("ORDER BY {}", buffer.join(", ")))
}
}
impl Orderable for Column {
type Output = (Column, Option<Order>);
#[inline]
fn order(self, order: Option<Order>) -> Self::Output {
(self, order)
}
}
impl<'l> Orderable for &'l str {
type Output = (String, Option<Order>);
#[inline]
fn order(self, order: Option<Order>) -> Self::Output {
(self.to_string(), order)
}
}
impl<T: Expression> Expression for (T, Option<Order>) {
fn compile(&self) -> Result<String> {
let main = try!(self.0.compile());
Ok(match self.1 {
Some(Order::Ascending) => format!("{} ASC", main),
Some(Order::Descending) => format!("{} DESC", main),
_ => main,
})
}
}
#[cfg(test)]
mod tests {
use grammar::Clause;
use prelude::*;
macro_rules! new(
($first:expr) => (super::OrderBy::default().append($first));
);
#[test]
fn from_column() {
let clause = new!(column("foo"));
assert_eq!(clause.compile().unwrap(), "ORDER BY `foo`");
let clause = new!(column("foo").ascend());
assert_eq!(clause.compile().unwrap(), "ORDER BY `foo` ASC");
let clause = new!(column("foo").descend());
assert_eq!(clause.compile().unwrap(), "ORDER BY `foo` DESC");
}
#[test]
fn from_string() {
let clause = new!("foo");
assert_eq!(clause.compile().unwrap(), "ORDER BY foo");
let clause = new!("foo".ascend());
assert_eq!(clause.compile().unwrap(), "ORDER BY foo ASC");
let clause = new!("foo".descend());
assert_eq!(clause.compile().unwrap(), "ORDER BY foo DESC");
}
#[test]
fn append() {
let clause = new!("foo").append(column("bar").ascend())
.append("baz".to_string().descend());
assert_eq!(clause.compile().unwrap(), "ORDER BY foo, `bar` ASC, baz DESC");
}
}