sea_query/extension/mysql/select.rs
1use super::{IndexHint, IndexHintScope, IndexHintType};
2use crate::{IntoIden, IntoTableRef, SelectStatement};
3
4macro_rules! get_or_insert_index {
5 ($self:ident, $table:expr, $index:expr, $ty:expr, $scope:expr) => {
6 let key = $table.into();
7 match $self.index_hints.get_mut(&key) {
8 Some(value) => value.push(IndexHint {
9 index: $index,
10 r#type: $ty,
11 scope: $scope,
12 }),
13 None => {
14 $self.index_hints.insert(
15 key,
16 vec![IndexHint {
17 index: $index,
18 r#type: $ty,
19 scope: $scope,
20 }],
21 );
22 }
23 };
24 };
25}
26
27pub trait MySqlSelectStatementExt {
28 fn use_index<I>(&mut self, index: I, scope: IndexHintScope) -> &mut Self
29 where
30 I: IntoIden;
31
32 fn use_index_on<T, I>(&mut self, table: T, index: I, scope: IndexHintScope) -> &mut Self
33 where
34 T: IntoTableRef,
35 I: IntoIden;
36
37 fn force_index<I>(&mut self, index: I, scope: IndexHintScope) -> &mut Self
38 where
39 I: IntoIden;
40
41 fn force_index_on<T, I>(&mut self, table: T, index: I, scope: IndexHintScope) -> &mut Self
42 where
43 T: IntoTableRef,
44 I: IntoIden;
45
46 fn ignore_index<I>(&mut self, index: I, scope: IndexHintScope) -> &mut Self
47 where
48 I: IntoIden;
49
50 fn ignore_index_on<T, I>(&mut self, table: T, index: I, scope: IndexHintScope) -> &mut Self
51 where
52 T: IntoTableRef,
53 I: IntoIden;
54}
55
56const PANIC_MSG: &str =
57 "No table in from clause, you should specify the table before using index hint";
58
59impl MySqlSelectStatementExt for SelectStatement {
60 /// USE INDEX hint on the last table in the from clause for MySQL
61 ///
62 /// Give the optimizer information about how to choose indexes during query processing.
63 /// See [MySQL reference manual for Index Hints](https://dev.mysql.com/doc/refman/8.0/en/index-hints.html)
64 ///
65 /// # Examples
66 ///
67 /// ```
68 /// use sea_query::{extension::mysql::*, tests_cfg::*, *};
69 ///
70 /// let query = Query::select()
71 /// .from(Char::Table)
72 /// .use_index(IndexName::new("IDX_123456"), IndexHintScope::All)
73 /// .column(Char::SizeW)
74 /// .to_owned();
75 ///
76 /// assert_eq!(
77 /// query.to_string(MysqlQueryBuilder),
78 /// r#"SELECT `size_w` FROM `character` USE INDEX (`IDX_123456`)"#
79 /// );
80 /// ```
81 fn use_index<I>(&mut self, index: I, scope: IndexHintScope) -> &mut Self
82 where
83 I: IntoIden,
84 {
85 let table_ref = self.from.last().expect(PANIC_MSG);
86
87 get_or_insert_index!(
88 self,
89 table_ref,
90 index.into_iden(),
91 IndexHintType::Use,
92 scope
93 );
94
95 self
96 }
97
98 /// USE INDEX hint on the specified in the from clause for MySQL
99 ///
100 /// # Examples
101 ///
102 /// ```
103 /// use sea_query::{extension::mysql::*, tests_cfg::*, *};
104 ///
105 /// let query = Query::select()
106 /// .from(Font::Table)
107 /// .from(Char::Table)
108 /// .use_index_on(Char::Table, IndexName::new("IDX_123456"), IndexHintScope::All)
109 /// .use_index_on(Font::Table, IndexName::new("IDX_654321"), IndexHintScope::All)
110 /// .column(Char::SizeW)
111 /// .to_owned();
112 ///
113 /// assert_eq!(
114 /// query.to_string(MysqlQueryBuilder),
115 /// r#"SELECT `size_w` FROM `font` USE INDEX (`IDX_654321`), `character` USE INDEX (`IDX_123456`)"#
116 /// );
117 /// ```
118 fn use_index_on<T, I>(&mut self, table: T, index: I, scope: IndexHintScope) -> &mut Self
119 where
120 T: IntoTableRef,
121 I: IntoIden,
122 {
123 get_or_insert_index!(
124 self,
125 table.into_table_ref(),
126 index.into_iden(),
127 IndexHintType::Use,
128 scope
129 );
130
131 self
132 }
133
134 /// FORCE INDEX hint on the last table in from clause for MySQL
135 ///
136 /// Give the optimizer information about how to choose indexes during query processing.
137 /// See [MySQL reference manual for Index Hints](https://dev.mysql.com/doc/refman/8.0/en/index-hints.html)
138 ///
139 /// # Examples
140 ///
141 /// ```
142 /// use sea_query::{extension::mysql::*, tests_cfg::*, *};
143 ///
144 /// let query = Query::select()
145 /// .from(Char::Table)
146 /// .force_index(IndexName::new("IDX_123456"), IndexHintScope::All)
147 /// .column(Char::SizeW)
148 /// .to_owned();
149 ///
150 /// assert_eq!(
151 /// query.to_string(MysqlQueryBuilder),
152 /// r#"SELECT `size_w` FROM `character` FORCE INDEX (`IDX_123456`)"#
153 /// );
154 /// ```
155 fn force_index<I>(&mut self, index: I, scope: IndexHintScope) -> &mut Self
156 where
157 I: IntoIden,
158 {
159 let table_ref = self.from.last().expect(PANIC_MSG);
160
161 get_or_insert_index!(
162 self,
163 table_ref,
164 index.into_iden(),
165 IndexHintType::Force,
166 scope
167 );
168
169 self
170 }
171
172 /// FORCE INDEX hint on the specified in the from clause for MySQL
173 ///
174 /// # Examples
175 ///
176 /// ```
177 /// use sea_query::{extension::mysql::*, tests_cfg::*, *};
178 ///
179 /// let query = Query::select()
180 /// .from(Font::Table)
181 /// .from(Char::Table)
182 /// .force_index_on(Char::Table, IndexName::new("IDX_123456"), IndexHintScope::All)
183 /// .force_index_on(Font::Table, IndexName::new("IDX_654321"), IndexHintScope::All)
184 /// .column(Char::SizeW)
185 /// .to_owned();
186 ///
187 /// assert_eq!(
188 /// query.to_string(MysqlQueryBuilder),
189 /// r#"SELECT `size_w` FROM `font` FORCE INDEX (`IDX_654321`), `character` FORCE INDEX (`IDX_123456`)"#
190 /// );
191 /// ```
192 fn force_index_on<T, I>(&mut self, table: T, index: I, scope: IndexHintScope) -> &mut Self
193 where
194 T: IntoTableRef,
195 I: IntoIden,
196 {
197 get_or_insert_index!(
198 self,
199 table.into_table_ref(),
200 index.into_iden(),
201 IndexHintType::Force,
202 scope
203 );
204
205 self
206 }
207
208 /// Ignore index hint on the last table in the from clause for MySQL
209 ///
210 /// Give the optimizer information about how to choose indexes during query processing.
211 /// See [MySQL reference manual for Index Hints](https://dev.mysql.com/doc/refman/8.0/en/index-hints.html)
212 ///
213 /// # Examples
214 ///
215 /// ```
216 /// use sea_query::{extension::mysql::*, tests_cfg::*, *};
217 ///
218 /// let query = Query::select()
219 /// .from(Char::Table)
220 /// .ignore_index(IndexName::new("IDX_123456"), IndexHintScope::All)
221 /// .column(Char::SizeW)
222 /// .to_owned();
223 ///
224 /// assert_eq!(
225 /// query.to_string(MysqlQueryBuilder),
226 /// r#"SELECT `size_w` FROM `character` IGNORE INDEX (`IDX_123456`)"#
227 /// )
228 /// ```
229 fn ignore_index<I>(&mut self, index: I, scope: IndexHintScope) -> &mut Self
230 where
231 I: IntoIden,
232 {
233 let table_ref = self.from.last().expect(PANIC_MSG);
234
235 get_or_insert_index!(
236 self,
237 table_ref,
238 index.into_iden(),
239 IndexHintType::Ignore,
240 scope
241 );
242
243 self
244 }
245
246 /// IGNORE INDEX hint on the specified in the from clause for MySQL
247 ///
248 /// # Examples
249 ///
250 /// ```
251 /// use sea_query::{extension::mysql::*, tests_cfg::*, *};
252 ///
253 /// let query = Query::select()
254 /// .from(Font::Table)
255 /// .from(Char::Table)
256 /// .ignore_index_on(Char::Table, IndexName::new("IDX_123456"), IndexHintScope::All)
257 /// .ignore_index_on(Font::Table, IndexName::new("IDX_654321"), IndexHintScope::All)
258 /// .column(Char::SizeW)
259 /// .to_owned();
260 ///
261 /// assert_eq!(
262 /// query.to_string(MysqlQueryBuilder),
263 /// r#"SELECT `size_w` FROM `font` IGNORE INDEX (`IDX_654321`), `character` IGNORE INDEX (`IDX_123456`)"#
264 /// );
265 /// ```
266 fn ignore_index_on<T, I>(&mut self, table: T, index: I, scope: IndexHintScope) -> &mut Self
267 where
268 T: IntoTableRef,
269 I: IntoIden,
270 {
271 get_or_insert_index!(
272 self,
273 table.into_table_ref(),
274 index.into_iden(),
275 IndexHintType::Ignore,
276 scope
277 );
278
279 self
280 }
281}