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