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