1use crate::{
2 ColumnTrait, EntityTrait, IdenStatic, Iterable, QueryTrait, Select, SelectTwo, SelectTwoMany,
3 SelectTwoRequired,
4};
5use core::marker::PhantomData;
6use sea_query::{Iden, IntoIden, Order, SelectExpr, SelectStatement, SimpleExpr};
7use std::borrow::Cow;
8
9macro_rules! select_def {
10 ( $ident: ident, $str: expr ) => {
11 #[derive(Debug, Clone, Copy)]
13 pub struct $ident;
14
15 impl Iden for $ident {
16 fn quoted(&self) -> Cow<'static, str> {
17 Cow::Borrowed(IdenStatic::as_str(self))
18 }
19
20 fn unquoted(&self) -> &str {
21 IdenStatic::as_str(self)
22 }
23 }
24
25 impl IdenStatic for $ident {
26 fn as_str(&self) -> &'static str {
27 $str
28 }
29 }
30 };
31}
32
33select_def!(SelectA, "A_");
34select_def!(SelectB, "B_");
35select_def!(SelectC, "C_");
36select_def!(SelectD, "D_");
37select_def!(SelectE, "E_");
38select_def!(SelectF, "F_");
39
40impl<E> Select<E>
41where
42 E: EntityTrait,
43{
44 pub(crate) fn apply_alias(mut self, pre: &str) -> Self {
45 self.query().exprs_mut_for_each(|sel| {
46 match &sel.alias {
47 Some(alias) => {
48 let alias = format!("{}{}", pre, alias.to_string().as_str());
49 sel.alias = Some(alias.into_iden());
50 }
51 None => {
52 let col = match &sel.expr {
53 SimpleExpr::Column(col_ref) => match col_ref.column() {
54 Some(col) => col,
55 None => {
56 panic!("cannot apply alias for Column with asterisk");
57 }
58 },
59 SimpleExpr::AsEnum(_, simple_expr) => match simple_expr.as_ref() {
60 SimpleExpr::Column(col_ref) => match col_ref.column() {
61 Some(col) => col,
62 None => {
63 panic!("cannot apply alias for AsEnum with asterisk")
64 }
65 },
66 _ => {
67 panic!("cannot apply alias for AsEnum with expr other than Column")
68 }
69 },
70 _ => panic!("cannot apply alias for expr other than Column or AsEnum"),
71 };
72 let alias = format!("{}{}", pre, col.to_string().as_str());
73 sel.alias = Some(alias.into_iden());
74 }
75 };
76 });
77 self
78 }
79
80 pub fn select_also<F>(mut self, _: F) -> SelectTwo<E, F>
82 where
83 F: EntityTrait,
84 {
85 self = self.apply_alias(SelectA.as_str());
86 SelectTwo::new(self.into_query())
87 }
88
89 #[doc(hidden)]
91 pub fn select_also_fake<F>(mut self, _: F) -> SelectTwo<E, F>
92 where
93 F: EntityTrait,
94 {
95 self = self.apply_alias(SelectA.as_str());
96 SelectTwo::new_without_prepare(self.into_query())
97 }
98
99 pub fn select_with<F>(mut self, _: F) -> SelectTwoMany<E, F>
101 where
102 F: EntityTrait,
103 {
104 self = self.apply_alias(SelectA.as_str());
105 SelectTwoMany::new(self.into_query())
106 }
107
108 pub fn select_two_required<F>(mut self, _: F) -> SelectTwoRequired<E, F>
110 where
111 F: EntityTrait,
112 {
113 self = self.apply_alias(SelectA.as_str());
114 SelectTwoRequired::new(self.into_query())
115 }
116}
117
118impl<E, F> SelectTwo<E, F>
119where
120 E: EntityTrait,
121 F: EntityTrait,
122{
123 pub(crate) fn new(query: SelectStatement) -> Self {
124 Self::new_without_prepare(query).prepare_select()
125 }
126
127 pub(crate) fn new_without_prepare(query: SelectStatement) -> Self {
128 Self {
129 query,
130 entity: PhantomData,
131 }
132 }
133
134 fn prepare_select(mut self) -> Self {
135 prepare_select_col::<F, _, _>(&mut self, SelectB);
136 self
137 }
138}
139
140impl<E, F> SelectTwoMany<E, F>
141where
142 E: EntityTrait,
143 F: EntityTrait,
144{
145 pub(crate) fn new(query: SelectStatement) -> Self {
146 Self::new_without_prepare(query)
147 .prepare_select()
148 .prepare_order_by()
149 }
150
151 pub(crate) fn new_without_prepare(query: SelectStatement) -> Self {
152 Self {
153 query,
154 entity: PhantomData,
155 }
156 }
157
158 fn prepare_select(mut self) -> Self {
159 prepare_select_col::<F, _, _>(&mut self, SelectB);
160 self
161 }
162
163 fn prepare_order_by(mut self) -> Self {
164 for col in <E::PrimaryKey as Iterable>::iter() {
165 self.query.order_by((E::default(), col), Order::Asc);
166 }
167 self
168 }
169}
170
171impl<E, F> SelectTwoRequired<E, F>
172where
173 E: EntityTrait,
174 F: EntityTrait,
175{
176 pub(crate) fn new(query: SelectStatement) -> Self {
177 Self::new_without_prepare(query).prepare_select()
178 }
179
180 pub(crate) fn new_without_prepare(query: SelectStatement) -> Self {
181 Self {
182 query,
183 entity: PhantomData,
184 }
185 }
186
187 fn prepare_select(mut self) -> Self {
188 prepare_select_col::<F, Self, _>(&mut self, SelectB);
189 self
190 }
191}
192
193pub(crate) fn prepare_select_col<F, S, A>(selector: &mut S, alias: A)
194where
195 F: EntityTrait,
196 S: QueryTrait<QueryStatement = SelectStatement>,
197 A: IdenStatic,
198{
199 for col in <F::Column as Iterable>::iter() {
200 let alias = format!("{}{}", alias.as_str(), col.as_str());
201 selector.query().expr(SelectExpr {
202 expr: col.select_as(col.into_expr()),
203 alias: Some(alias.into_iden()),
204 window: None,
205 });
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 use crate::tests_cfg::{cake, fruit};
212 use crate::{ColumnTrait, DbBackend, EntityTrait, QueryFilter, QuerySelect, QueryTrait};
213
214 #[test]
215 fn alias_1() {
216 assert_eq!(
217 cake::Entity::find()
218 .column_as(cake::Column::Id, "B")
219 .apply_alias("A_")
220 .build(DbBackend::MySql)
221 .to_string(),
222 "SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`, `cake`.`id` AS `A_B` FROM `cake`",
223 );
224 }
225
226 #[test]
227 fn select_also_1() {
228 assert_eq!(
229 cake::Entity::find()
230 .left_join(fruit::Entity)
231 .select_also(fruit::Entity)
232 .build(DbBackend::MySql)
233 .to_string(),
234 [
235 "SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,",
236 "`fruit`.`id` AS `B_id`, `fruit`.`name` AS `B_name`, `fruit`.`cake_id` AS `B_cake_id`",
237 "FROM `cake` LEFT JOIN `fruit` ON `cake`.`id` = `fruit`.`cake_id`",
238 ].join(" ")
239 );
240 }
241
242 #[test]
243 fn select_with_1() {
244 assert_eq!(
245 cake::Entity::find()
246 .left_join(fruit::Entity)
247 .select_with(fruit::Entity)
248 .build(DbBackend::MySql)
249 .to_string(),
250 [
251 "SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,",
252 "`fruit`.`id` AS `B_id`, `fruit`.`name` AS `B_name`, `fruit`.`cake_id` AS `B_cake_id`",
253 "FROM `cake` LEFT JOIN `fruit` ON `cake`.`id` = `fruit`.`cake_id`",
254 "ORDER BY `cake`.`id` ASC",
255 ].join(" ")
256 );
257 }
258
259 #[test]
260 fn select_also_2() {
261 assert_eq!(
262 cake::Entity::find()
263 .left_join(fruit::Entity)
264 .select_also(fruit::Entity)
265 .filter(cake::Column::Id.eq(1))
266 .filter(fruit::Column::Id.eq(2))
267 .build(DbBackend::MySql)
268 .to_string(),
269 [
270 "SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,",
271 "`fruit`.`id` AS `B_id`, `fruit`.`name` AS `B_name`, `fruit`.`cake_id` AS `B_cake_id`",
272 "FROM `cake` LEFT JOIN `fruit` ON `cake`.`id` = `fruit`.`cake_id`",
273 "WHERE `cake`.`id` = 1 AND `fruit`.`id` = 2",
274 ].join(" ")
275 );
276 }
277
278 #[test]
279 fn select_with_2() {
280 assert_eq!(
281 cake::Entity::find()
282 .left_join(fruit::Entity)
283 .select_with(fruit::Entity)
284 .filter(cake::Column::Id.eq(1))
285 .filter(fruit::Column::Id.eq(2))
286 .build(DbBackend::MySql)
287 .to_string(),
288 [
289 "SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,",
290 "`fruit`.`id` AS `B_id`, `fruit`.`name` AS `B_name`, `fruit`.`cake_id` AS `B_cake_id`",
291 "FROM `cake` LEFT JOIN `fruit` ON `cake`.`id` = `fruit`.`cake_id`",
292 "WHERE `cake`.`id` = 1 AND `fruit`.`id` = 2",
293 "ORDER BY `cake`.`id` ASC",
294 ].join(" ")
295 );
296 }
297}