1use async_graphql::Enum;
2use chrono::{DateTime, Utc};
3use uuid::Uuid;
4
5use crate::{
6 cursor::{Cursor, Iterable},
7 driver::{Driver, PushPrql},
8 take::Taken,
9};
10
11pub trait Sorting: PushPrql {
14 fn order(&self) -> Order;
15 fn flip(&self) -> impl Sorting;
16 fn push_to_driver_with_order(&self, driver: &mut Driver);
17}
18
19impl<T> Sorting for &T
20where
21 T: Sorting,
22{
23 fn order(&self) -> Order {
24 (*self).order()
25 }
26
27 fn flip(&self) -> impl Sorting {
28 (*self).flip()
29 }
30
31 fn push_to_driver_with_order(&self, driver: &mut Driver) {
32 (*self).push_to_driver_with_order(driver)
33 }
34}
35
36pub trait SortedBy {
37 fn sorting(&self) -> impl Sorting;
38}
39
40impl<T> SortedBy for &T
41where
42 T: SortedBy,
43{
44 fn sorting(&self) -> impl Sorting {
45 (*self).sorting()
46 }
47}
48
49#[derive(Clone, Copy, Debug, Enum, Eq, PartialEq)]
50pub enum Order {
51 Asc,
52 Desc,
53}
54
55impl Order {
56 pub fn flip(&self) -> Self {
57 match self {
58 Self::Asc => Self::Desc,
59 Self::Desc => Self::Asc,
60 }
61 }
62
63 pub fn is_asc(&self) -> bool {
64 matches!(self, Self::Asc)
65 }
66
67 pub fn is_desc(&self) -> bool {
68 matches!(self, Self::Desc)
69 }
70}
71
72impl PushPrql for Order {
73 fn push_to_driver(&self, driver: &mut Driver) {
74 if let Self::Desc = self {
75 driver.push('-');
76 }
77 }
78}
79
80pub struct Sort<By> {
81 pub order: Order,
82 pub by: By,
83}
84
85impl<By> Sorting for Sort<By>
86where
87 By: PushPrql,
88{
89 fn order(&self) -> Order {
90 self.order
91 }
92
93 fn flip(&self) -> impl Sorting {
94 Sort {
95 order: self.order.flip(),
96 by: &self.by,
97 }
98 }
99
100 fn push_to_driver_with_order(&self, driver: &mut Driver) {
101 self.order.push_to_driver(driver);
102 self.by.push_to_driver(driver);
103 }
104}
105
106impl<By> PushPrql for Sort<By>
107where
108 By: PushPrql,
109{
110 fn push_to_driver(&self, driver: &mut Driver) {
111 self.by.push_to_driver(driver);
112 }
113}
114
115pub struct Sorted<Query, Sort> {
116 pub query: Query,
117 pub sort: Sort,
118}
119
120impl<Query, Sort> Sorted<Query, Sort> {
121 pub fn take(&self, n: usize) -> Taken<&Self> {
122 Taken { query: self, n }
123 }
124}
125
126impl<Query, Sort> SortedBy for Sorted<Query, Sort>
127where
128 Sort: Sorting,
129{
130 fn sorting(&self) -> impl Sorting {
131 &self.sort
132 }
133}
134
135impl<Query, Sort> PushPrql for Sorted<Query, Sort>
136where
137 Query: PushPrql,
138 Sort: Sorting,
139{
140 fn push_to_driver(&self, driver: &mut Driver) {
141 self.query.push_to_driver(driver);
142 driver.push("\nsort { ");
143 self.sort.push_to_driver_with_order(driver);
144 driver.push(" }");
145 }
146}
147
148pub trait SortBy<By> {
149 fn sort_by(by: By) -> Sort<By>;
150}
151
152impl<By> SortBy<By> for i32
153where
154 By: PushPrql,
155{
156 fn sort_by(by: By) -> Sort<By> {
157 Sort {
158 order: Order::Asc,
159 by,
160 }
161 }
162}
163
164impl<By> SortBy<By> for u64
165where
166 By: PushPrql,
167{
168 fn sort_by(by: By) -> Sort<By> {
169 Sort {
170 order: Order::Asc,
171 by,
172 }
173 }
174}
175
176impl<By> SortBy<By> for String
177where
178 By: PushPrql,
179{
180 fn sort_by(by: By) -> Sort<By> {
181 Sort {
182 order: Order::Asc,
183 by,
184 }
185 }
186}
187
188macro_rules! impl_sortable {
189 ($t:ty, $i:ident, $c:expr) => {
190 impl Sortable for $t {
191 type Sort = $i;
192 }
193
194 impl Sortable for Option<$t> {
195 type Sort = $i;
196 }
197
198 #[derive(Clone, Copy, Debug, Enum, Eq, PartialEq)]
199 #[graphql(rename_items = "snake_case")]
200 pub enum $i {
201 Asc,
202 Desc,
203 }
204
205 impl Iterable for $i {
206 fn cursor(&self) -> Cursor {
207 $c
208 }
209 }
210
211 impl $i {
212 pub fn order(&self) -> Order {
213 match self {
214 Self::Asc => Order::Desc,
215 Self::Desc => Order::Asc,
216 }
217 }
218
219 pub fn flip_as_self(&self) -> Self {
220 match self {
221 Self::Asc => Self::Desc,
222 Self::Desc => Self::Asc,
223 }
224 }
225
226 pub fn push_to_driver_with_lhs(&self, lhs: &dyn PushPrql, driver: &mut Driver) {
227 lhs.push_to_driver(driver);
228 }
229
230 pub fn push_to_driver_with_order_with_lhs(
231 &self,
232 lhs: &dyn PushPrql,
233 driver: &mut Driver,
234 ) {
235 match self {
236 Self::Asc => {
237 lhs.push_to_driver(driver);
238 }
239 Self::Desc => {
240 driver.push('-');
241 lhs.push_to_driver(driver);
242 }
243 }
244 }
245 }
246 };
247}
248
249pub trait Sortable {
250 type Sort;
251}
252
253impl_sortable!(i32, I32Sort, Cursor::I32);
254impl_sortable!(i64, I64Sort, Cursor::I64);
255impl_sortable!(u32, U32Sort, Cursor::I32);
256impl_sortable!(u64, U64Sort, Cursor::I64);
257impl_sortable!(String, StringSort, Cursor::String);
258impl_sortable!(Uuid, UuidSort, Cursor::Uuid);
259impl_sortable!(DateTime<Utc>, DateTimeSort, Cursor::DateTime);
260
261#[cfg(test)]
262mod test {
263 use crate::{
264 column::{col, json},
265 cond::gt,
266 from::from,
267 table::table,
268 };
269
270 use super::*;
271
272 #[test]
273 fn test_sort() {
274 let mut driver = Driver::new();
275 {
276 from(table("users"))
277 .sort(col("age").asc())
278 .push_to_driver(&mut driver);
279 }
280 assert_eq!(driver.sql(), "SELECT * FROM users ORDER BY age");
281 }
282
283 #[test]
284 fn test_sort_desc() {
285 let mut driver = Driver::new();
286 {
287 from(table("users"))
288 .sort(col("age").desc())
289 .push_to_driver(&mut driver);
290 }
291 dbg!(driver.prql());
292 assert_eq!(driver.sql(), "SELECT * FROM users ORDER BY age DESC");
293 }
294
295 #[test]
296 fn test_filter_sort() {
297 let mut driver = Driver::new();
298 {
299 from(table("users"))
300 .filter(gt(col("age"), 18))
301 .sort(col("age").asc())
302 .push_to_driver(&mut driver);
303 }
304 assert_eq!(
305 driver.sql(),
306 "SELECT * FROM users WHERE age > $1 ORDER BY age"
307 );
308 }
309
310 #[test]
311 fn test_take_sort() {
312 let mut driver = Driver::new();
313 {
314 from(table("users"))
315 .take(10)
316 .sort(col("age").asc())
317 .push_to_driver(&mut driver);
318 }
319 assert_eq!(
320 driver.sql(),
321 "WITH table_0 AS (SELECT * FROM users LIMIT 10) SELECT * FROM table_0 ORDER BY age"
322 );
323 }
324
325 #[test]
326 fn test_sort_json() {
327 let mut driver = Driver::new();
328 {
329 from(table("users"))
330 .sort(json(col("info")).get("age").asc())
331 .push_to_driver(&mut driver);
332 }
333 assert_eq!(driver.sql(), "WITH table_0 AS (SELECT *, info->'age' AS _expr_0 FROM users) SELECT * FROM table_0 ORDER BY _expr_0");
334
335 let mut driver = Driver::new();
336 {
337 from(table("users"))
338 .sort(json(col("info")).get("age").desc())
339 .push_to_driver(&mut driver);
340 }
341 assert_eq!(driver.sql(), "WITH table_0 AS (SELECT *, info->'age' AS _expr_0 FROM users) SELECT * FROM table_0 ORDER BY _expr_0 DESC");
342 }
343}