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