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