sea_orm/query/
join.rs

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