1use serde::{Deserialize, Serialize};
4use std::borrow::Cow;
5use std::fmt;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
9#[derive(Default)]
10pub enum SortOrder {
11 #[default]
13 Asc,
14 Desc,
16}
17
18impl SortOrder {
19 pub fn as_sql(&self) -> &'static str {
21 match self {
22 Self::Asc => "ASC",
23 Self::Desc => "DESC",
24 }
25 }
26}
27
28impl fmt::Display for SortOrder {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 write!(f, "{}", self.as_sql())
31 }
32}
33
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
37pub enum NullsOrder {
38 First,
40 Last,
42}
43
44impl NullsOrder {
45 pub fn as_sql(&self) -> &'static str {
47 match self {
48 Self::First => "NULLS FIRST",
49 Self::Last => "NULLS LAST",
50 }
51 }
52}
53
54#[derive(Debug, Clone, PartialEq, Eq)]
56pub struct OrderByField {
57 pub column: Cow<'static, str>,
59 pub order: SortOrder,
61 pub nulls: Option<NullsOrder>,
63}
64
65impl OrderByField {
66 pub fn new(column: impl Into<Cow<'static, str>>, order: SortOrder) -> Self {
68 Self {
69 column: column.into(),
70 order,
71 nulls: None,
72 }
73 }
74
75 #[inline]
77 pub const fn new_static(column: &'static str, order: SortOrder) -> Self {
78 Self {
79 column: Cow::Borrowed(column),
80 order,
81 nulls: None,
82 }
83 }
84
85 pub fn nulls(mut self, nulls: NullsOrder) -> Self {
87 self.nulls = Some(nulls);
88 self
89 }
90
91 pub fn asc(column: impl Into<Cow<'static, str>>) -> Self {
93 Self::new(column, SortOrder::Asc)
94 }
95
96 pub fn desc(column: impl Into<Cow<'static, str>>) -> Self {
98 Self::new(column, SortOrder::Desc)
99 }
100
101 #[inline]
103 pub const fn asc_static(column: &'static str) -> Self {
104 Self::new_static(column, SortOrder::Asc)
105 }
106
107 #[inline]
109 pub const fn desc_static(column: &'static str) -> Self {
110 Self::new_static(column, SortOrder::Desc)
111 }
112
113 pub fn to_sql(&self) -> String {
117 let cap = self.column.len() + 5 + if self.nulls.is_some() { 12 } else { 0 };
119 let mut sql = String::with_capacity(cap);
120 self.write_sql(&mut sql);
121 sql
122 }
123
124 #[inline]
138 pub fn write_sql(&self, buffer: &mut String) {
139 buffer.push_str(&self.column);
140 buffer.push(' ');
141 buffer.push_str(self.order.as_sql());
142 if let Some(nulls) = self.nulls {
143 buffer.push(' ');
144 buffer.push_str(nulls.as_sql());
145 }
146 }
147
148 #[inline]
150 pub fn estimated_len(&self) -> usize {
151 self.column.len() + 5 + if self.nulls.is_some() { 12 } else { 0 }
152 }
153}
154
155#[derive(Debug, Clone, PartialEq, Eq)]
157pub enum OrderBy {
158 Field(OrderByField),
160 Fields(Box<[OrderByField]>),
162}
163
164impl OrderBy {
165 pub fn none() -> Self {
167 Self::Fields(Box::new([]))
168 }
169
170 pub fn is_empty(&self) -> bool {
172 match self {
173 Self::Field(_) => false,
174 Self::Fields(fields) => fields.is_empty(),
175 }
176 }
177
178 pub fn then(self, field: OrderByField) -> Self {
180 match self {
181 Self::Field(existing) => Self::Fields(vec![existing, field].into_boxed_slice()),
182 Self::Fields(existing) => {
183 let mut fields: Vec<_> = existing.into_vec();
184 fields.push(field);
185 Self::Fields(fields.into_boxed_slice())
186 }
187 }
188 }
189
190 pub fn from_fields(fields: impl IntoIterator<Item = OrderByField>) -> Self {
192 let fields: Vec<_> = fields.into_iter().collect();
193 match fields.len() {
194 0 => Self::none(),
195 1 => Self::Field(fields.into_iter().next().unwrap()),
196 _ => Self::Fields(fields.into_boxed_slice()),
197 }
198 }
199
200 pub fn to_sql(&self) -> String {
204 match self {
205 Self::Field(field) => field.to_sql(),
206 Self::Fields(fields) if fields.is_empty() => String::new(),
207 Self::Fields(fields) => {
208 let cap: usize = fields.iter().map(|f| f.estimated_len() + 2).sum();
210 let mut sql = String::with_capacity(cap);
211 self.write_sql(&mut sql);
212 sql
213 }
214 }
215 }
216
217 #[inline]
234 pub fn write_sql(&self, buffer: &mut String) {
235 match self {
236 Self::Field(field) => field.write_sql(buffer),
237 Self::Fields(fields) => {
238 for (i, field) in fields.iter().enumerate() {
239 if i > 0 {
240 buffer.push_str(", ");
241 }
242 field.write_sql(buffer);
243 }
244 }
245 }
246 }
247
248 #[inline]
250 pub fn field_count(&self) -> usize {
251 match self {
252 Self::Field(_) => 1,
253 Self::Fields(fields) => fields.len(),
254 }
255 }
256}
257
258impl From<OrderByField> for OrderBy {
259 fn from(field: OrderByField) -> Self {
260 Self::Field(field)
261 }
262}
263
264impl From<Vec<OrderByField>> for OrderBy {
265 fn from(fields: Vec<OrderByField>) -> Self {
266 match fields.len() {
267 0 => Self::none(),
268 1 => Self::Field(fields.into_iter().next().unwrap()),
269 _ => Self::Fields(fields.into_boxed_slice()),
270 }
271 }
272}
273
274#[derive(Debug)]
276pub struct OrderByBuilder {
277 fields: Vec<OrderByField>,
278}
279
280impl OrderByBuilder {
281 #[inline]
283 pub fn with_capacity(capacity: usize) -> Self {
284 Self {
285 fields: Vec::with_capacity(capacity),
286 }
287 }
288
289 #[inline]
291 pub fn push(mut self, field: OrderByField) -> Self {
292 self.fields.push(field);
293 self
294 }
295
296 #[inline]
298 pub fn asc(self, column: impl Into<Cow<'static, str>>) -> Self {
299 self.push(OrderByField::asc(column))
300 }
301
302 #[inline]
304 pub fn desc(self, column: impl Into<Cow<'static, str>>) -> Self {
305 self.push(OrderByField::desc(column))
306 }
307
308 #[inline]
310 pub fn build(self) -> OrderBy {
311 OrderBy::from(self.fields)
312 }
313}
314
315pub mod order_patterns {
317 use super::*;
318
319 pub const CREATED_AT_DESC: OrderByField = OrderByField::desc_static("created_at");
321
322 pub const CREATED_AT_ASC: OrderByField = OrderByField::asc_static("created_at");
324
325 pub const UPDATED_AT_DESC: OrderByField = OrderByField::desc_static("updated_at");
327
328 pub const UPDATED_AT_ASC: OrderByField = OrderByField::asc_static("updated_at");
330
331 pub const ID_ASC: OrderByField = OrderByField::asc_static("id");
333
334 pub const ID_DESC: OrderByField = OrderByField::desc_static("id");
336
337 pub const NAME_ASC: OrderByField = OrderByField::asc_static("name");
339
340 pub const NAME_DESC: OrderByField = OrderByField::desc_static("name");
342
343 pub const PRICE_ASC: OrderByField = OrderByField::asc_static("price");
345
346 pub const PRICE_DESC: OrderByField = OrderByField::desc_static("price");
348}
349
350#[derive(Debug, Clone, PartialEq, Eq)]
352#[derive(Default)]
353pub enum Select {
354 #[default]
356 All,
357 Fields(Vec<String>),
359 Field(String),
361}
362
363impl Select {
364 pub fn all() -> Self {
366 Self::All
367 }
368
369 pub fn fields(fields: impl IntoIterator<Item = impl Into<String>>) -> Self {
371 Self::Fields(fields.into_iter().map(Into::into).collect())
372 }
373
374 pub fn field(field: impl Into<String>) -> Self {
376 Self::Field(field.into())
377 }
378
379 pub fn is_all(&self) -> bool {
381 matches!(self, Self::All)
382 }
383
384 pub fn field_names(&self) -> Vec<&str> {
386 match self {
387 Self::All => vec!["*"],
388 Self::Fields(fields) => fields.iter().map(String::as_str).collect(),
389 Self::Field(field) => vec![field.as_str()],
390 }
391 }
392
393 pub fn to_sql(&self) -> String {
395 match self {
396 Self::All => "*".to_string(),
397 Self::Fields(fields) => {
398 let cap: usize = fields.iter().map(|f| f.len() + 2).sum();
400 let mut sql = String::with_capacity(cap);
401 self.write_sql(&mut sql);
402 sql
403 }
404 Self::Field(field) => field.clone(),
405 }
406 }
407
408 #[inline]
410 pub fn write_sql(&self, buffer: &mut String) {
411 match self {
412 Self::All => buffer.push('*'),
413 Self::Fields(fields) => {
414 for (i, field) in fields.iter().enumerate() {
415 if i > 0 {
416 buffer.push_str(", ");
417 }
418 buffer.push_str(field);
419 }
420 }
421 Self::Field(field) => buffer.push_str(field),
422 }
423 }
424}
425
426
427#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
429#[derive(Default)]
430pub enum SetParam<T> {
431 Set(T),
433 #[default]
435 Unset,
436}
437
438impl<T> SetParam<T> {
439 pub fn is_set(&self) -> bool {
441 matches!(self, Self::Set(_))
442 }
443
444 pub fn get(&self) -> Option<&T> {
446 match self {
447 Self::Set(v) => Some(v),
448 Self::Unset => None,
449 }
450 }
451
452 pub fn take(self) -> Option<T> {
454 match self {
455 Self::Set(v) => Some(v),
456 Self::Unset => None,
457 }
458 }
459
460 pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> SetParam<U> {
462 match self {
463 Self::Set(v) => SetParam::Set(f(v)),
464 Self::Unset => SetParam::Unset,
465 }
466 }
467}
468
469
470impl<T> From<T> for SetParam<T> {
471 fn from(value: T) -> Self {
472 Self::Set(value)
473 }
474}
475
476impl<T> From<Option<T>> for SetParam<T> {
477 fn from(opt: Option<T>) -> Self {
478 match opt {
479 Some(v) => Self::Set(v),
480 None => Self::Unset,
481 }
482 }
483}
484
485#[cfg(test)]
486mod tests {
487 use super::*;
488
489 #[test]
490 fn test_sort_order() {
491 assert_eq!(SortOrder::Asc.as_sql(), "ASC");
492 assert_eq!(SortOrder::Desc.as_sql(), "DESC");
493 }
494
495 #[test]
496 fn test_order_by_field() {
497 let field = OrderByField::desc("created_at");
498 assert_eq!(field.to_sql(), "created_at DESC");
499
500 let field_with_nulls = OrderByField::asc("name").nulls(NullsOrder::Last);
501 assert_eq!(field_with_nulls.to_sql(), "name ASC NULLS LAST");
502 }
503
504 #[test]
505 fn test_order_by_field_static() {
506 let field = OrderByField::desc_static("created_at");
507 assert_eq!(field.to_sql(), "created_at DESC");
508
509 let field = OrderByField::asc_static("id");
510 assert_eq!(field.to_sql(), "id ASC");
511 }
512
513 #[test]
514 fn test_order_by_field_write_sql() {
515 let field = OrderByField::desc("created_at");
516 let mut buffer = String::with_capacity(32);
517 field.write_sql(&mut buffer);
518 assert_eq!(buffer, "created_at DESC");
519
520 let field = OrderByField::asc("name").nulls(NullsOrder::First);
521 let mut buffer = String::with_capacity(32);
522 field.write_sql(&mut buffer);
523 assert_eq!(buffer, "name ASC NULLS FIRST");
524 }
525
526 #[test]
527 fn test_order_by_multiple() {
528 let order =
529 OrderBy::Field(OrderByField::desc("created_at")).then(OrderByField::asc("name"));
530 assert_eq!(order.to_sql(), "created_at DESC, name ASC");
531 }
532
533 #[test]
534 fn test_order_by_from_fields() {
535 let order =
536 OrderBy::from_fields([OrderByField::desc("created_at"), OrderByField::asc("id")]);
537 assert_eq!(order.to_sql(), "created_at DESC, id ASC");
538 assert_eq!(order.field_count(), 2);
539 }
540
541 #[test]
542 fn test_order_by_write_sql() {
543 let order =
544 OrderBy::from_fields([OrderByField::desc("created_at"), OrderByField::asc("id")]);
545 let mut buffer = String::with_capacity(64);
546 buffer.push_str("ORDER BY ");
547 order.write_sql(&mut buffer);
548 assert_eq!(buffer, "ORDER BY created_at DESC, id ASC");
549 }
550
551 #[test]
552 fn test_order_by_builder() {
553 let order = OrderByBuilder::with_capacity(3)
554 .desc("created_at")
555 .asc("name")
556 .asc("id")
557 .build();
558 assert_eq!(order.to_sql(), "created_at DESC, name ASC, id ASC");
559 assert_eq!(order.field_count(), 3);
560 }
561
562 #[test]
563 fn test_order_patterns() {
564 assert_eq!(order_patterns::CREATED_AT_DESC.to_sql(), "created_at DESC");
565 assert_eq!(order_patterns::ID_ASC.to_sql(), "id ASC");
566 assert_eq!(order_patterns::NAME_ASC.to_sql(), "name ASC");
567 }
568
569 #[test]
570 fn test_select() {
571 assert_eq!(Select::all().to_sql(), "*");
572 assert_eq!(Select::field("id").to_sql(), "id");
573 assert_eq!(
574 Select::fields(["id", "name", "email"]).to_sql(),
575 "id, name, email"
576 );
577 }
578
579 #[test]
580 fn test_select_write_sql() {
581 let select = Select::fields(["id", "name", "email"]);
582 let mut buffer = String::with_capacity(32);
583 buffer.push_str("SELECT ");
584 select.write_sql(&mut buffer);
585 assert_eq!(buffer, "SELECT id, name, email");
586 }
587
588 #[test]
589 fn test_set_param() {
590 let set: SetParam<i32> = SetParam::Set(42);
591 assert!(set.is_set());
592 assert_eq!(set.get(), Some(&42));
593
594 let unset: SetParam<i32> = SetParam::Unset;
595 assert!(!unset.is_set());
596 assert_eq!(unset.get(), None);
597 }
598}