diff --git a/src/grammar/clause/order_by.rs b/src/grammar/clause/order_by.rs index 4b9d4dd..94df0dd 100644 --- a/src/grammar/clause/order_by.rs +++ b/src/grammar/clause/order_by.rs @@ -1,54 +1,68 @@ -//! The `ORDER BY` clause. - -use Result; -use grammar::definition::Column; -use grammar::{Buffer, Clause, Expression}; - -/// An `ORDER BY` clause. -#[derive(Debug, Default)] -pub struct OrderBy(Vec>); - -/// An order. +use crate::grammar::definition::Column; +use crate::grammar::{Buffer, Clause, Expression}; +use crate::Result; + +/// Represents an `ORDER BY` clause in an SQL statement. +/// +/// This struct holds a list of expressions, each of which will be compiled +/// to SQL and joined by commas in the final clause. +#[derive(Debug, Default, Clone)] +pub struct OrderBy(Vec>); + +/// Specifies the direction of ordering in an `ORDER BY` clause. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Order { - /// The ascending order. + /// Ascending order (ASC). Ascending, - /// The descending order. + /// Descending order (DESC). Descending, } -/// An object that can be ordered by. -pub trait Orderable where Self: Sized { - /// The type produced after setting an order. +/// A trait for types that can be ordered in an `ORDER BY` clause. +/// +/// Allows specifying the order direction (ascending or descending) +/// for columns, strings, or other custom expressions. +pub trait Orderable: Sized { + /// The type produced when setting an order. type Output; - /// Set the order. - fn order(self, Option) -> Self::Output; + /// Set the order explicitly. + fn order(self, order: Option) -> Self::Output; - /// Set the ascending order. + /// Set ascending order. fn ascend(self) -> Self::Output { self.order(Some(Order::Ascending)) } - /// Set the descending order. + /// Set descending order. fn descend(self) -> Self::Output { self.order(Some(Order::Descending)) } } impl OrderBy { - #[doc(hidden)] - pub fn append(mut self, expression: T) -> Self where T: Expression + 'static { + /// Create a new, empty `OrderBy` clause. + pub fn new() -> Self { + Self(Vec::new()) + } + + /// Append an expression to the `OrderBy` clause. + /// This uses a builder pattern for convenient chaining. + pub fn append(&mut self, expression: T) -> &mut Self + where + T: Expression + 'static, + { self.0.push(Box::new(expression)); self } } impl Clause for OrderBy { + /// Compile the `OrderBy` clause into an SQL string. fn compile(&self) -> Result { let mut buffer = Buffer::new(); for expression in &self.0 { - buffer.push(try!(expression.compile())); + buffer.push(expression.compile()?); } Ok(format!("ORDER BY {}", buffer.join(", "))) } @@ -57,40 +71,45 @@ impl Clause for OrderBy { impl Orderable for Column { type Output = (Column, Option); - #[inline] fn order(self, order: Option) -> Self::Output { (self, order) } } -impl<'l> Orderable for &'l str { +// Implement Orderable for any type that can be converted into a String. +impl> Orderable for T { type Output = (String, Option); - #[inline] fn order(self, order: Option) -> Self::Output { - (self.to_string(), order) + (self.into(), order) } } impl Expression for (T, Option) { fn compile(&self) -> Result { - let main = try!(self.0.compile()); + let main = self.0.compile()?; Ok(match self.1 { Some(Order::Ascending) => format!("{} ASC", main), Some(Order::Descending) => format!("{} DESC", main), - _ => main, + None => main, }) } } #[cfg(test)] mod tests { - use grammar::Clause; - use prelude::*; - - macro_rules! new( - ($first:expr) => (super::OrderBy::default().append($first)); - ); + use super::*; + use crate::grammar::Clause; + use crate::prelude::*; + + // Macro for initializing an OrderBy with a first element, using the new builder pattern. + macro_rules! new { + ($first:expr) => {{ + let mut ob = OrderBy::default(); + ob.append($first); + ob + }}; + } #[test] fn from_column() { @@ -118,8 +137,10 @@ mod tests { #[test] fn append() { - let clause = new!("foo").append(column("bar").ascend()) - .append("baz".to_string().descend()); + let mut clause = new!("foo"); + clause + .append(column("bar").ascend()) + .append("baz".descend()); assert_eq!(clause.compile().unwrap(), "ORDER BY foo, `bar` ASC, baz DESC"); }