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