Skip to main content

reinhardt_query/types/
order.rs

1//! Order and ordering types for SQL queries.
2//!
3//! This module provides types for ORDER BY clauses:
4//!
5//! - [`Order`]: Ascending or descending order
6//! - [`NullOrdering`]: NULL ordering (NULLS FIRST/LAST)
7//! - [`OrderExpr`]: An expression with its ordering specification
8
9use super::iden::DynIden;
10
11/// Ordering direction for ORDER BY clauses.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
13pub enum Order {
14	/// Ascending order (ASC)
15	#[default]
16	Asc,
17	/// Descending order (DESC)
18	Desc,
19}
20
21impl Order {
22	/// Returns the SQL representation of this order.
23	#[must_use]
24	pub fn as_str(&self) -> &'static str {
25		match self {
26			Self::Asc => "ASC",
27			Self::Desc => "DESC",
28		}
29	}
30}
31
32/// NULL ordering specification.
33///
34/// Used to specify whether NULL values should appear first or last
35/// in the ordering.
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
37pub enum NullOrdering {
38	/// NULLS FIRST - NULL values appear before non-NULL values
39	First,
40	/// NULLS LAST - NULL values appear after non-NULL values
41	Last,
42}
43
44impl NullOrdering {
45	/// Returns the SQL representation of this null ordering.
46	#[must_use]
47	pub fn as_str(&self) -> &'static str {
48		match self {
49			Self::First => "NULLS FIRST",
50			Self::Last => "NULLS LAST",
51		}
52	}
53}
54
55/// An expression with its ordering specification.
56///
57/// This represents a single item in an ORDER BY clause.
58#[derive(Debug, Clone)]
59pub struct OrderExpr {
60	/// The expression to order by (column or expression)
61	pub expr: OrderExprKind,
62	/// The ordering direction
63	pub order: Order,
64	/// Optional NULL ordering
65	pub nulls: Option<NullOrdering>,
66}
67
68/// The kind of expression in an ORDER BY clause.
69#[derive(Debug, Clone)]
70pub enum OrderExprKind {
71	/// A column identifier
72	Column(DynIden),
73	/// A qualified column (table.column)
74	TableColumn(DynIden, DynIden),
75	/// An expression (requires expr module)
76	Expr(Box<crate::expr::SimpleExpr>),
77}
78
79impl OrderExpr {
80	/// Create a new order expression for a column with the default order (ASC).
81	pub fn new<I: super::iden::IntoIden>(column: I) -> Self {
82		Self {
83			expr: OrderExprKind::Column(column.into_iden()),
84			order: Order::Asc,
85			nulls: None,
86		}
87	}
88
89	/// Create a new order expression for a qualified column.
90	pub fn new_table_column<T: super::iden::IntoIden, C: super::iden::IntoIden>(
91		table: T,
92		column: C,
93	) -> Self {
94		Self {
95			expr: OrderExprKind::TableColumn(table.into_iden(), column.into_iden()),
96			order: Order::Asc,
97			nulls: None,
98		}
99	}
100
101	/// Set the ordering direction.
102	#[must_use]
103	pub fn order(mut self, order: Order) -> Self {
104		self.order = order;
105		self
106	}
107
108	/// Set NULL ordering.
109	#[must_use]
110	pub fn nulls(mut self, nulls: NullOrdering) -> Self {
111		self.nulls = Some(nulls);
112		self
113	}
114}
115
116#[cfg(test)]
117mod tests {
118	use super::*;
119	use rstest::rstest;
120
121	#[rstest]
122	fn test_order_as_str() {
123		assert_eq!(Order::Asc.as_str(), "ASC");
124		assert_eq!(Order::Desc.as_str(), "DESC");
125	}
126
127	#[rstest]
128	fn test_order_default() {
129		assert_eq!(Order::default(), Order::Asc);
130	}
131
132	#[rstest]
133	fn test_null_ordering_as_str() {
134		assert_eq!(NullOrdering::First.as_str(), "NULLS FIRST");
135		assert_eq!(NullOrdering::Last.as_str(), "NULLS LAST");
136	}
137
138	#[rstest]
139	fn test_order_expr_builder() {
140		let expr = OrderExpr::new("column_name")
141			.order(Order::Desc)
142			.nulls(NullOrdering::Last);
143
144		assert_eq!(expr.order, Order::Desc);
145		assert_eq!(expr.nulls, Some(NullOrdering::Last));
146	}
147}