1use crate::{
2 find_linked_recursive, join_tbl_on_condition, unpack_table_ref, ColumnTrait, EntityTrait,
3 IdenStatic, Iterable, Linked, QuerySelect, Related, Select, SelectA, SelectB, SelectThree,
4 SelectTwo, SelectTwoMany,
5};
6pub use sea_query::JoinType;
7use sea_query::{Alias, Condition, Expr, IntoIden, SeaRc, SelectExpr};
8
9impl<E> Select<E>
10where
11 E: EntityTrait,
12{
13 pub fn left_join<R>(self, _: R) -> Self
15 where
16 R: EntityTrait,
17 E: Related<R>,
18 {
19 self.join_join(JoinType::LeftJoin, E::to(), E::via())
20 }
21
22 pub fn right_join<R>(self, _: R) -> Self
24 where
25 R: EntityTrait,
26 E: Related<R>,
27 {
28 self.join_join(JoinType::RightJoin, E::to(), E::via())
29 }
30
31 pub fn inner_join<R>(self, _: R) -> Self
33 where
34 R: EntityTrait,
35 E: Related<R>,
36 {
37 self.join_join(JoinType::InnerJoin, E::to(), E::via())
38 }
39
40 pub fn reverse_join<R>(self, _: R) -> Self
42 where
43 R: EntityTrait + Related<E>,
44 {
45 self.join_rev(JoinType::InnerJoin, R::to())
46 }
47
48 pub fn find_also_related<R>(self, r: R) -> SelectTwo<E, R>
50 where
51 R: EntityTrait,
52 E: Related<R>,
53 {
54 self.left_join(r).select_also(r)
55 }
56
57 pub fn find_with_related<R>(self, r: R) -> SelectTwoMany<E, R>
59 where
60 R: EntityTrait,
61 E: Related<R>,
62 {
63 self.left_join(r).select_with(r)
64 }
65
66 pub fn find_also_linked<L, T>(self, l: L) -> SelectTwo<E, T>
68 where
69 L: Linked<FromEntity = E, ToEntity = T>,
70 T: EntityTrait,
71 {
72 let mut slf = self;
73 for (i, mut rel) in l.link().into_iter().enumerate() {
74 let to_tbl = Alias::new(format!("r{i}")).into_iden();
75 let from_tbl = if i > 0 {
76 Alias::new(format!("r{}", i - 1)).into_iden()
77 } else {
78 unpack_table_ref(&rel.from_tbl)
79 };
80 let table_ref = rel.to_tbl;
81
82 let mut condition = Condition::all().add(join_tbl_on_condition(
83 SeaRc::clone(&from_tbl),
84 SeaRc::clone(&to_tbl),
85 rel.from_col,
86 rel.to_col,
87 ));
88 if let Some(f) = rel.on_condition.take() {
89 condition = condition.add(f(SeaRc::clone(&from_tbl), SeaRc::clone(&to_tbl)));
90 }
91
92 slf.query()
93 .join_as(JoinType::LeftJoin, table_ref, to_tbl, condition);
94 }
95 slf = slf.apply_alias(SelectA.as_str());
96 let mut select_two = SelectTwo::new_without_prepare(slf.query);
97 for col in <T::Column as Iterable>::iter() {
98 let alias = format!("{}{}", SelectB.as_str(), col.as_str());
99 let expr = Expr::col((
100 Alias::new(format!("r{}", l.link().len() - 1)).into_iden(),
101 col.into_iden(),
102 ));
103 select_two.query().expr(SelectExpr {
104 expr: col.select_as(expr),
105 alias: Some(SeaRc::new(Alias::new(alias))),
106 window: None,
107 });
108 }
109 select_two
110 }
111
112 pub fn find_with_linked<L, T>(self, l: L) -> SelectTwoMany<E, T>
114 where
115 L: Linked<FromEntity = E, ToEntity = T>,
116 T: EntityTrait,
117 {
118 let mut slf = self;
119 for (i, mut rel) in l.link().into_iter().enumerate() {
120 let to_tbl = Alias::new(format!("r{i}")).into_iden();
121 let from_tbl = if i > 0 {
122 Alias::new(format!("r{}", i - 1)).into_iden()
123 } else {
124 unpack_table_ref(&rel.from_tbl)
125 };
126 let table_ref = rel.to_tbl;
127
128 let mut condition = Condition::all().add(join_tbl_on_condition(
129 SeaRc::clone(&from_tbl),
130 SeaRc::clone(&to_tbl),
131 rel.from_col,
132 rel.to_col,
133 ));
134 if let Some(f) = rel.on_condition.take() {
135 condition = condition.add(f(SeaRc::clone(&from_tbl), SeaRc::clone(&to_tbl)));
136 }
137
138 slf.query()
139 .join_as(JoinType::LeftJoin, table_ref, to_tbl, condition);
140 }
141 slf = slf.apply_alias(SelectA.as_str());
142 let mut select_two_many = SelectTwoMany::new_without_prepare(slf.query);
143 for col in <T::Column as Iterable>::iter() {
144 let alias = format!("{}{}", SelectB.as_str(), col.as_str());
145 let expr = Expr::col((
146 Alias::new(format!("r{}", l.link().len() - 1)).into_iden(),
147 col.into_iden(),
148 ));
149 select_two_many.query().expr(SelectExpr {
150 expr: col.select_as(expr),
151 alias: Some(SeaRc::new(Alias::new(alias))),
152 window: None,
153 });
154 }
155 select_two_many
156 }
157
158 #[doc(hidden)]
159 pub fn find_with_linked_recursive<L>(self, l: L) -> Select<E>
161 where
162 L: Linked<FromEntity = E, ToEntity = E>,
163 {
164 find_linked_recursive(self, l.link())
165 }
166}
167
168impl<E, F> SelectTwo<E, F>
169where
170 E: EntityTrait,
171 F: EntityTrait,
172{
173 pub fn find_also_related<R>(self, r: R) -> SelectThree<E, F, R>
175 where
176 R: EntityTrait,
177 E: Related<R>,
178 {
179 self.join_join(JoinType::LeftJoin, E::to(), E::via())
180 .select_also(r)
181 }
182
183 pub fn and_also_related<R>(self, r: R) -> SelectThree<E, F, R>
185 where
186 R: EntityTrait,
187 F: Related<R>,
188 {
189 self.join_join(JoinType::LeftJoin, F::to(), F::via())
190 .select_also(r)
191 }
192}
193
194#[cfg(test)]
195mod tests {
196 use crate::tests_cfg::{cake, cake_filling, cake_filling_price, entity_linked, filling, fruit};
197 use crate::{
198 ColumnTrait, DbBackend, EntityTrait, ModelTrait, QueryFilter, QuerySelect, QueryTrait,
199 RelationTrait,
200 };
201 use pretty_assertions::assert_eq;
202 use sea_query::{Alias, ConditionType, Expr, IntoCondition, JoinType};
203
204 #[test]
205 fn join_1() {
206 assert_eq!(
207 cake::Entity::find()
208 .left_join(fruit::Entity)
209 .build(DbBackend::MySql)
210 .to_string(),
211 [
212 "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
213 "LEFT JOIN `fruit` ON `cake`.`id` = `fruit`.`cake_id`",
214 ]
215 .join(" ")
216 );
217 }
218
219 #[test]
220 fn join_2() {
221 assert_eq!(
222 cake::Entity::find()
223 .inner_join(fruit::Entity)
224 .filter(fruit::Column::Name.contains("cherry"))
225 .build(DbBackend::MySql)
226 .to_string(),
227 [
228 "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
229 "INNER JOIN `fruit` ON `cake`.`id` = `fruit`.`cake_id`",
230 "WHERE `fruit`.`name` LIKE \'%cherry%\'"
231 ]
232 .join(" ")
233 );
234 }
235
236 #[test]
237 fn join_3() {
238 assert_eq!(
239 fruit::Entity::find()
240 .reverse_join(cake::Entity)
241 .build(DbBackend::MySql)
242 .to_string(),
243 [
244 "SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit`",
245 "INNER JOIN `cake` ON `cake`.`id` = `fruit`.`cake_id`",
246 ]
247 .join(" ")
248 );
249 }
250
251 #[test]
252 fn join_4() {
253 use crate::{Related, Select};
254
255 let find_fruit: Select<fruit::Entity> = cake::Entity::find_related();
256 assert_eq!(
257 find_fruit
258 .filter(cake::Column::Id.eq(11))
259 .build(DbBackend::MySql)
260 .to_string(),
261 [
262 "SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit`",
263 "INNER JOIN `cake` ON `cake`.`id` = `fruit`.`cake_id`",
264 "WHERE `cake`.`id` = 11",
265 ]
266 .join(" ")
267 );
268 }
269
270 #[test]
271 fn join_5() {
272 let cake_model = cake::Model {
273 id: 12,
274 name: "".to_owned(),
275 };
276
277 assert_eq!(
278 cake_model
279 .find_related(fruit::Entity)
280 .build(DbBackend::MySql)
281 .to_string(),
282 [
283 "SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit`",
284 "INNER JOIN `cake` ON `cake`.`id` = `fruit`.`cake_id`",
285 "WHERE `cake`.`id` = 12",
286 ]
287 .join(" ")
288 );
289 }
290
291 #[test]
292 fn join_6() {
293 assert_eq!(
294 cake::Entity::find()
295 .left_join(filling::Entity)
296 .build(DbBackend::MySql)
297 .to_string(),
298 [
299 "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
300 "LEFT JOIN `cake_filling` ON `cake`.`id` = `cake_filling`.`cake_id`",
301 "LEFT JOIN `filling` ON `cake_filling`.`filling_id` = `filling`.`id`",
302 ]
303 .join(" ")
304 );
305 }
306
307 #[test]
308 fn join_7() {
309 use crate::{Related, Select};
310
311 let find_filling: Select<filling::Entity> = cake::Entity::find_related();
312 assert_eq!(
313 find_filling.build(DbBackend::MySql).to_string(),
314 [
315 "SELECT `filling`.`id`, `filling`.`name`, `filling`.`vendor_id` FROM `filling`",
316 "INNER JOIN `cake_filling` ON `cake_filling`.`filling_id` = `filling`.`id`",
317 "INNER JOIN `cake` ON `cake`.`id` = `cake_filling`.`cake_id`",
318 ]
319 .join(" ")
320 );
321 }
322
323 #[test]
324 fn join_8() {
325 use crate::{Related, Select};
326
327 let find_cake_filling_price: Select<cake_filling_price::Entity> =
328 cake_filling::Entity::find_related();
329 assert_eq!(
330 find_cake_filling_price.build(DbBackend::Postgres).to_string(),
331 [
332 r#"SELECT "cake_filling_price"."cake_id", "cake_filling_price"."filling_id", "cake_filling_price"."price""#,
333 r#"FROM "public"."cake_filling_price""#,
334 r#"INNER JOIN "cake_filling" ON"#,
335 r#""cake_filling"."cake_id" = "cake_filling_price"."cake_id" AND"#,
336 r#""cake_filling"."filling_id" = "cake_filling_price"."filling_id""#,
337 ]
338 .join(" ")
339 );
340 }
341
342 #[test]
343 fn join_9() {
344 use crate::{Related, Select};
345
346 let find_cake_filling: Select<cake_filling::Entity> =
347 cake_filling_price::Entity::find_related();
348 assert_eq!(
349 find_cake_filling.build(DbBackend::Postgres).to_string(),
350 [
351 r#"SELECT "cake_filling"."cake_id", "cake_filling"."filling_id""#,
352 r#"FROM "cake_filling""#,
353 r#"INNER JOIN "public"."cake_filling_price" ON"#,
354 r#""cake_filling_price"."cake_id" = "cake_filling"."cake_id" AND"#,
355 r#""cake_filling_price"."filling_id" = "cake_filling"."filling_id""#,
356 ]
357 .join(" ")
358 );
359 }
360
361 #[test]
362 fn join_10() {
363 let cake_model = cake::Model {
364 id: 12,
365 name: "".to_owned(),
366 };
367
368 assert_eq!(
369 cake_model
370 .find_linked(entity_linked::CakeToFilling)
371 .build(DbBackend::MySql)
372 .to_string(),
373 [
374 r#"SELECT `filling`.`id`, `filling`.`name`, `filling`.`vendor_id`"#,
375 r#"FROM `filling`"#,
376 r#"INNER JOIN `cake_filling` AS `r0` ON `r0`.`filling_id` = `filling`.`id`"#,
377 r#"INNER JOIN `cake` AS `r1` ON `r1`.`id` = `r0`.`cake_id`"#,
378 r#"WHERE `r1`.`id` = 12"#,
379 ]
380 .join(" ")
381 );
382 }
383
384 #[test]
385 fn join_11() {
386 let cake_model = cake::Model {
387 id: 18,
388 name: "".to_owned(),
389 };
390
391 assert_eq!(
392 cake_model
393 .find_linked(entity_linked::CakeToFillingVendor)
394 .build(DbBackend::MySql)
395 .to_string(),
396 [
397 r#"SELECT `vendor`.`id`, `vendor`.`name`"#,
398 r#"FROM `vendor`"#,
399 r#"INNER JOIN `filling` AS `r0` ON `r0`.`vendor_id` = `vendor`.`id`"#,
400 r#"INNER JOIN `cake_filling` AS `r1` ON `r1`.`filling_id` = `r0`.`id`"#,
401 r#"INNER JOIN `cake` AS `r2` ON `r2`.`id` = `r1`.`cake_id`"#,
402 r#"WHERE `r2`.`id` = 18"#,
403 ]
404 .join(" ")
405 );
406 }
407
408 #[test]
409 fn join_12() {
410 assert_eq!(
411 cake::Entity::find()
412 .find_also_linked(entity_linked::CakeToFilling)
413 .build(DbBackend::MySql)
414 .to_string(),
415 [
416 r#"SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,"#,
417 r#"`r1`.`id` AS `B_id`, `r1`.`name` AS `B_name`, `r1`.`vendor_id` AS `B_vendor_id`"#,
418 r#"FROM `cake`"#,
419 r#"LEFT JOIN `cake_filling` AS `r0` ON `cake`.`id` = `r0`.`cake_id`"#,
420 r#"LEFT JOIN `filling` AS `r1` ON `r0`.`filling_id` = `r1`.`id`"#,
421 ]
422 .join(" ")
423 );
424 }
425
426 #[test]
427 fn join_13() {
428 assert_eq!(
429 cake::Entity::find()
430 .find_also_linked(entity_linked::CakeToFillingVendor)
431 .build(DbBackend::MySql)
432 .to_string(),
433 [
434 r#"SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,"#,
435 r#"`r2`.`id` AS `B_id`, `r2`.`name` AS `B_name`"#,
436 r#"FROM `cake`"#,
437 r#"LEFT JOIN `cake_filling` AS `r0` ON `cake`.`id` = `r0`.`cake_id`"#,
438 r#"LEFT JOIN `filling` AS `r1` ON `r0`.`filling_id` = `r1`.`id`"#,
439 r#"LEFT JOIN `vendor` AS `r2` ON `r1`.`vendor_id` = `r2`.`id`"#,
440 ]
441 .join(" ")
442 );
443 }
444
445 #[test]
446 fn join_14() {
447 assert_eq!(
448 cake::Entity::find()
449 .join(JoinType::LeftJoin, cake::Relation::TropicalFruit.def())
450 .build(DbBackend::MySql)
451 .to_string(),
452 [
453 "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
454 "LEFT JOIN `fruit` ON `cake`.`id` = `fruit`.`cake_id` AND `fruit`.`name` LIKE '%tropical%'",
455 ]
456 .join(" ")
457 );
458 }
459
460 #[test]
461 fn join_15() {
462 let cake_model = cake::Model {
463 id: 18,
464 name: "".to_owned(),
465 };
466
467 assert_eq!(
468 cake_model
469 .find_linked(entity_linked::CheeseCakeToFillingVendor)
470 .build(DbBackend::MySql)
471 .to_string(),
472 [
473 r#"SELECT `vendor`.`id`, `vendor`.`name`"#,
474 r#"FROM `vendor`"#,
475 r#"INNER JOIN `filling` AS `r0` ON `r0`.`vendor_id` = `vendor`.`id`"#,
476 r#"INNER JOIN `cake_filling` AS `r1` ON `r1`.`filling_id` = `r0`.`id`"#,
477 r#"INNER JOIN `cake` AS `r2` ON `r2`.`id` = `r1`.`cake_id` AND `r2`.`name` LIKE '%cheese%'"#,
478 r#"WHERE `r2`.`id` = 18"#,
479 ]
480 .join(" ")
481 );
482 }
483
484 #[test]
485 fn join_16() {
486 }
488
489 #[test]
490 fn join_17() {
491 assert_eq!(
492 cake::Entity::find()
493 .find_also_linked(entity_linked::CheeseCakeToFillingVendor)
494 .build(DbBackend::MySql)
495 .to_string(),
496 [
497 r#"SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,"#,
498 r#"`r2`.`id` AS `B_id`, `r2`.`name` AS `B_name`"#,
499 r#"FROM `cake`"#,
500 r#"LEFT JOIN `cake_filling` AS `r0` ON `cake`.`id` = `r0`.`cake_id` AND `cake`.`name` LIKE '%cheese%'"#,
501 r#"LEFT JOIN `filling` AS `r1` ON `r0`.`filling_id` = `r1`.`id`"#,
502 r#"LEFT JOIN `vendor` AS `r2` ON `r1`.`vendor_id` = `r2`.`id`"#,
503 ]
504 .join(" ")
505 );
506 }
507
508 #[test]
509 fn join_18() {
510 }
512
513 #[test]
514 fn join_19() {
515 assert_eq!(
516 cake::Entity::find()
517 .join(JoinType::LeftJoin, cake::Relation::TropicalFruit.def())
518 .join(
519 JoinType::LeftJoin,
520 cake_filling::Relation::Cake
521 .def()
522 .rev()
523 .on_condition(|_left, right| {
524 Expr::col((right, cake_filling::Column::CakeId))
525 .gt(10)
526 .into_condition()
527 })
528 )
529 .join(
530 JoinType::LeftJoin,
531 cake_filling::Relation::Filling
532 .def()
533 .on_condition(|_left, right| {
534 Expr::col((right, filling::Column::Name))
535 .like("%lemon%")
536 .into_condition()
537 })
538 )
539 .join(JoinType::LeftJoin, filling::Relation::Vendor.def())
540 .build(DbBackend::MySql)
541 .to_string(),
542 [
543 "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
544 "LEFT JOIN `fruit` ON `cake`.`id` = `fruit`.`cake_id` AND `fruit`.`name` LIKE '%tropical%'",
545 "LEFT JOIN `cake_filling` ON `cake`.`id` = `cake_filling`.`cake_id` AND `cake_filling`.`cake_id` > 10",
546 "LEFT JOIN `filling` ON `cake_filling`.`filling_id` = `filling`.`id` AND `filling`.`name` LIKE '%lemon%'",
547 "LEFT JOIN `vendor` ON `filling`.`vendor_id` = `vendor`.`id`",
548 ]
549 .join(" ")
550 );
551 }
552
553 #[test]
554 fn join_20() {
555 assert_eq!(
556 cake::Entity::find()
557 .column_as(
558 Expr::col((Alias::new("fruit_alias"), fruit::Column::Name)),
559 "fruit_name"
560 )
561 .join_as(
562 JoinType::LeftJoin,
563 cake::Relation::Fruit
564 .def()
565 .on_condition(|_left, right| {
566 Expr::col((right, fruit::Column::Name))
567 .like("%tropical%")
568 .into_condition()
569 }),
570 Alias::new("fruit_alias")
571 )
572 .build(DbBackend::MySql)
573 .to_string(),
574 [
575 "SELECT `cake`.`id`, `cake`.`name`, `fruit_alias`.`name` AS `fruit_name` FROM `cake`",
576 "LEFT JOIN `fruit` AS `fruit_alias` ON `cake`.`id` = `fruit_alias`.`cake_id` AND `fruit_alias`.`name` LIKE '%tropical%'",
577 ]
578 .join(" ")
579 );
580 }
581
582 #[test]
583 fn join_21() {
584 assert_eq!(
585 cake::Entity::find()
586 .column_as(
587 Expr::col((Alias::new("cake_filling_alias"), cake_filling::Column::CakeId)),
588 "cake_filling_cake_id"
589 )
590 .join(JoinType::LeftJoin, cake::Relation::TropicalFruit.def())
591 .join_as_rev(
592 JoinType::LeftJoin,
593 cake_filling::Relation::Cake
594 .def()
595 .on_condition(|left, _right| {
596 Expr::col((left, cake_filling::Column::CakeId))
597 .gt(10)
598 .into_condition()
599 }),
600 Alias::new("cake_filling_alias")
601 )
602 .build(DbBackend::MySql)
603 .to_string(),
604 [
605 "SELECT `cake`.`id`, `cake`.`name`, `cake_filling_alias`.`cake_id` AS `cake_filling_cake_id` FROM `cake`",
606 "LEFT JOIN `fruit` ON `cake`.`id` = `fruit`.`cake_id` AND `fruit`.`name` LIKE '%tropical%'",
607 "LEFT JOIN `cake_filling` AS `cake_filling_alias` ON `cake_filling_alias`.`cake_id` = `cake`.`id` AND `cake_filling_alias`.`cake_id` > 10",
608 ]
609 .join(" ")
610 );
611 }
612
613 #[test]
614 fn join_22() {
615 assert_eq!(
616 cake::Entity::find()
617 .column_as(
618 Expr::col((Alias::new("cake_filling_alias"), cake_filling::Column::CakeId)),
619 "cake_filling_cake_id"
620 )
621 .join(JoinType::LeftJoin, cake::Relation::OrTropicalFruit.def())
622 .join_as_rev(
623 JoinType::LeftJoin,
624 cake_filling::Relation::Cake
625 .def()
626 .condition_type(ConditionType::Any)
627 .on_condition(|left, _right| {
628 Expr::col((left, cake_filling::Column::CakeId))
629 .gt(10)
630 .into_condition()
631 }),
632 Alias::new("cake_filling_alias")
633 )
634 .build(DbBackend::MySql)
635 .to_string(),
636 [
637 "SELECT `cake`.`id`, `cake`.`name`, `cake_filling_alias`.`cake_id` AS `cake_filling_cake_id` FROM `cake`",
638 "LEFT JOIN `fruit` ON `cake`.`id` = `fruit`.`cake_id` OR `fruit`.`name` LIKE '%tropical%'",
639 "LEFT JOIN `cake_filling` AS `cake_filling_alias` ON `cake_filling_alias`.`cake_id` = `cake`.`id` OR `cake_filling_alias`.`cake_id` > 10",
640 ]
641 .join(" ")
642 );
643 }
644
645 #[test]
646 fn join_23() {
647 let cake_model = cake::Model {
648 id: 18,
649 name: "".to_owned(),
650 };
651
652 assert_eq!(
653 cake_model
654 .find_linked(entity_linked::CakeToCakeViaFilling)
655 .build(DbBackend::MySql)
656 .to_string(),
657 [
658 "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
659 "INNER JOIN `cake_filling` AS `r0` ON `r0`.`cake_id` = `cake`.`id`",
660 "INNER JOIN `filling` AS `r1` ON `r1`.`id` = `r0`.`filling_id`",
661 "INNER JOIN `cake_filling` AS `r2` ON `r2`.`filling_id` = `r1`.`id`",
662 "INNER JOIN `cake` AS `r3` ON `r3`.`id` = `r2`.`cake_id`",
663 "WHERE `r3`.`id` = 18",
664 ]
665 .join(" ")
666 );
667 }
668
669 #[test]
670 fn join_24() {
671 let cake_model = cake::Model {
672 id: 12,
673 name: "".to_owned(),
674 };
675
676 assert_eq!(
677 cake_model
678 .find_linked_recursive(entity_linked::CakeToCakeViaFilling)
679 .build(DbBackend::MySql)
680 .to_string(),
681 [
682 "WITH `cte` AS (SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
683 "INNER JOIN `cake_filling` AS `r0` ON `r0`.`cake_id` = `cake`.`id`",
684 "INNER JOIN `filling` AS `r1` ON `r1`.`id` = `r0`.`filling_id`",
685 "INNER JOIN `cake_filling` AS `r2` ON `r2`.`filling_id` = `r1`.`id`",
686 "INNER JOIN `cake` AS `r3` ON `r3`.`id` = `r2`.`cake_id`",
687 "WHERE `r3`.`id` = 12",
688 "UNION ALL (SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
689 "INNER JOIN `cake_filling` AS `r0` ON `r0`.`cake_id` = `cake`.`id`",
690 "INNER JOIN `filling` AS `r1` ON `r1`.`id` = `r0`.`filling_id`",
691 "INNER JOIN `cake_filling` AS `r2` ON `r2`.`filling_id` = `r1`.`id`",
692 "INNER JOIN `cte` AS `r3` ON `r3`.`id` = `r2`.`cake_id`))",
693 "SELECT `cake`.`id`, `cake`.`name` FROM `cte` AS `cake`",
694 ]
695 .join(" ")
696 );
697 }
698
699 #[test]
700 fn join_25() {
701 assert_eq!(
702 cake::Entity::find()
703 .find_with_linked_recursive(entity_linked::CakeToCakeViaFilling)
704 .build(DbBackend::MySql)
705 .to_string(),
706 [
707 "WITH `cte` AS (SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
708 "UNION ALL (SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
709 "INNER JOIN `cake_filling` AS `r0` ON `r0`.`cake_id` = `cake`.`id`",
710 "INNER JOIN `filling` AS `r1` ON `r1`.`id` = `r0`.`filling_id`",
711 "INNER JOIN `cake_filling` AS `r2` ON `r2`.`filling_id` = `r1`.`id`",
712 "INNER JOIN `cte` AS `r3` ON `r3`.`id` = `r2`.`cake_id`))",
713 "SELECT `cake`.`id`, `cake`.`name` FROM `cte` AS `cake`",
714 ]
715 .join(" ")
716 );
717 }
718}