rdb_pagination_core/sql/
order_by.rs

1use crate::{ColumnName, OrderType, TableName};
2
3#[derive(Debug, Clone)]
4pub enum NullStrategy {
5    Default,
6    First,
7    Last,
8}
9
10/// Struct for generating the `ORDER BY` clause.
11#[derive(Debug, Clone)]
12pub struct SqlOrderByComponent {
13    pub table_name:    TableName,
14    pub column_name:   ColumnName,
15    pub order_type:    OrderType,
16    pub null_strategy: NullStrategy,
17}
18
19#[cfg(any(feature = "mysql", feature = "sqlite"))]
20impl SqlOrderByComponent {
21    fn to_sql_order_by_clause_component<'a>(&self, s: &'a mut String) -> &'a str {
22        use std::{fmt::Write, str::from_utf8_unchecked};
23
24        let len = s.len();
25
26        match self.null_strategy {
27            NullStrategy::Default => (),
28            NullStrategy::First => {
29                s.write_fmt(format_args!(
30                    "`{table_name}`.`{column_name}` IS NOT NULL, ",
31                    table_name = self.table_name,
32                    column_name = self.column_name,
33                ))
34                .unwrap();
35            },
36            NullStrategy::Last => {
37                s.write_fmt(format_args!(
38                    "`{table_name}`.`{column_name}` IS NULL, ",
39                    table_name = self.table_name,
40                    column_name = self.column_name,
41                ))
42                .unwrap();
43            },
44        }
45
46        s.write_fmt(format_args!(
47            "`{table_name}`.`{column_name}` {order_type}",
48            table_name = self.table_name,
49            column_name = self.column_name,
50            order_type = self.order_type.as_str(),
51        ))
52        .unwrap();
53
54        unsafe { from_utf8_unchecked(&s.as_bytes()[len..]) }
55    }
56
57    fn format_sql_order_by_components<'a>(
58        order_by_components: &[SqlOrderByComponent],
59        s: &'a mut String,
60    ) -> &'a str {
61        use std::str::from_utf8_unchecked;
62
63        if order_by_components.is_empty() {
64            return "";
65        }
66
67        let len = s.len();
68
69        s.push_str("ORDER BY ");
70
71        for order_by_unit in order_by_components {
72            order_by_unit.to_sql_order_by_clause_component(s);
73            s.push_str(", ");
74        }
75
76        unsafe {
77            let len = s.len();
78
79            s.as_mut_vec().truncate(len - 2);
80        }
81
82        unsafe { from_utf8_unchecked(&s.as_bytes()[len..]) }
83    }
84}
85
86#[cfg(feature = "mysql")]
87impl SqlOrderByComponent {
88    /// Generate an `ORDER BY` component for MySQL.
89    ///
90    /// ```sql
91    /// `<table_name>`.`<column_name>` <order_type>
92    /// ```
93    #[inline]
94    pub fn to_mysql_order_by_clause_component<'a>(&self, s: &'a mut String) -> &'a str {
95        self.to_sql_order_by_clause_component(s)
96    }
97
98    /// Generate an `ORDER BY` clause for MySQL.
99    ///
100    /// If there is at least one component, the result string will starts with `ORDER BY`, and concatenate a series of `SqlOrderByComponent`s with `,`.
101    ///
102    /// ```sql
103    /// ORDER BY <SqlOrderByComponent[0]>, <SqlOrderByComponent[1]>
104    /// ```
105    #[inline]
106    pub fn format_mysql_order_by_components<'a>(
107        order_by_components: &[SqlOrderByComponent],
108        s: &'a mut String,
109    ) -> &'a str {
110        Self::format_sql_order_by_components(order_by_components, s)
111    }
112}
113
114#[cfg(feature = "sqlite")]
115impl SqlOrderByComponent {
116    /// Generate an `ORDER BY` component for SQLite.
117    ///
118    /// ```sql
119    /// `<table_name>`.`<column_name>` <order_type>
120    /// ```
121    #[inline]
122    pub fn to_sqlite_order_by_clause_component<'a>(&self, s: &'a mut String) -> &'a str {
123        self.to_sql_order_by_clause_component(s)
124    }
125
126    /// Generate an `ORDER BY` clause for SQLite.
127    ///
128    /// If there is at least one component, the result string will starts with `ORDER BY`, and concatenate a series of `SqlOrderByComponent`s with `,`.
129    ///
130    /// ```sql
131    /// ORDER BY <SqlOrderByComponent[0]>, <SqlOrderByComponent[1]>
132    /// ```
133    #[inline]
134    pub fn format_sqlite_order_by_components<'a>(
135        order_by_components: &[SqlOrderByComponent],
136        s: &'a mut String,
137    ) -> &'a str {
138        Self::format_sql_order_by_components(order_by_components, s)
139    }
140}
141
142#[cfg(any(feature = "mssql", feature = "mssql2008"))]
143impl SqlOrderByComponent {
144    fn to_sql_order_by_clause_component_ms<'a>(&self, s: &'a mut String) -> &'a str {
145        use std::{fmt::Write, str::from_utf8_unchecked};
146
147        let len = s.len();
148
149        match self.null_strategy {
150            NullStrategy::Default => (),
151            NullStrategy::First => {
152                s.write_fmt(format_args!(
153                    "CASE WHEN [{table_name}].[{column_name}] IS NULL THEN 0 ELSE 1 END, ",
154                    table_name = self.table_name,
155                    column_name = self.column_name,
156                ))
157                .unwrap();
158            },
159            NullStrategy::Last => {
160                s.write_fmt(format_args!(
161                    "CASE WHEN [{table_name}].[{column_name}] IS NULL THEN 1 ELSE 0 END, ",
162                    table_name = self.table_name,
163                    column_name = self.column_name,
164                ))
165                .unwrap();
166            },
167        }
168
169        s.write_fmt(format_args!(
170            "[{table_name}].[{column_name}] {order_type}",
171            table_name = self.table_name,
172            column_name = self.column_name,
173            order_type = self.order_type.as_str(),
174        ))
175        .unwrap();
176
177        unsafe { from_utf8_unchecked(&s.as_bytes()[len..]) }
178    }
179
180    fn format_sql_order_by_components_ms<'a>(
181        order_by_components: &[SqlOrderByComponent],
182        s: &'a mut String,
183    ) -> &'a str {
184        use std::str::from_utf8_unchecked;
185
186        if order_by_components.is_empty() {
187            return "";
188        }
189
190        let len = s.len();
191
192        s.push_str("ORDER BY ");
193
194        for order_by_unit in order_by_components {
195            order_by_unit.to_sql_order_by_clause_component_ms(s);
196            s.push_str(", ");
197        }
198
199        unsafe {
200            let len = s.len();
201
202            s.as_mut_vec().truncate(len - 2);
203        }
204
205        unsafe { from_utf8_unchecked(&s.as_bytes()[len..]) }
206    }
207}
208
209#[cfg(any(feature = "mssql", feature = "mssql2008"))]
210impl SqlOrderByComponent {
211    /// Generate an `ORDER BY` component for Microsoft SQL Server.
212    ///
213    /// ```sql
214    /// [<table_name>].[<column_name>] <order_type>
215    /// ```
216    #[inline]
217    pub fn to_mssql_order_by_clause_component<'a>(&self, s: &'a mut String) -> &'a str {
218        self.to_sql_order_by_clause_component_ms(s)
219    }
220
221    /// Generate an `ORDER BY` clause for Microsoft SQL Server.
222    ///
223    /// If there is at least one component, the result string will starts with `ORDER BY`, and concatenate a series of `SqlOrderByComponent`s with `,`.
224    ///
225    /// ```sql
226    /// ORDER BY <SqlOrderByComponent[0]>, <SqlOrderByComponent[1]>
227    /// ```
228    #[inline]
229    pub fn format_mssql_order_by_components<'a>(
230        order_by_components: &[SqlOrderByComponent],
231        s: &'a mut String,
232    ) -> &'a str {
233        Self::format_sql_order_by_components_ms(order_by_components, s)
234    }
235}