1use crate::{
2 error::*, ConnectionTrait, DbBackend, EntityTrait, FromQueryResult, IdenStatic, Iterable,
3 ModelTrait, PartialModelTrait, PrimaryKeyArity, PrimaryKeyToColumn, PrimaryKeyTrait,
4 QueryResult, QuerySelect, Select, SelectA, SelectB, SelectC, SelectThree, SelectTwo,
5 SelectTwoMany, Statement, StreamTrait, TryGetableMany,
6};
7use futures_util::{Stream, TryStreamExt};
8use sea_query::{SelectStatement, Value};
9use std::collections::HashMap;
10use std::{hash::Hash, marker::PhantomData, pin::Pin};
11
12#[cfg(feature = "with-json")]
13use crate::JsonValue;
14
15#[derive(Clone, Debug)]
17pub struct Selector<S>
18where
19 S: SelectorTrait,
20{
21 pub(crate) query: SelectStatement,
22 selector: S,
23}
24
25#[derive(Clone, Debug)]
27pub struct SelectorRaw<S>
28where
29 S: SelectorTrait,
30{
31 pub(crate) stmt: Statement,
32 #[allow(dead_code)]
33 selector: S,
34}
35
36pub trait SelectorTrait {
38 #[allow(missing_docs)]
39 type Item: Sized;
40
41 fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr>;
43}
44
45#[derive(Debug)]
47pub struct SelectGetableValue<T, C>
48where
49 T: TryGetableMany,
50 C: strum::IntoEnumIterator + sea_query::Iden,
51{
52 columns: PhantomData<C>,
53 model: PhantomData<T>,
54}
55
56#[derive(Debug)]
58pub struct SelectGetableTuple<T>
59where
60 T: TryGetableMany,
61{
62 model: PhantomData<T>,
63}
64
65#[derive(Debug)]
67pub struct SelectModel<M>
68where
69 M: FromQueryResult,
70{
71 model: PhantomData<M>,
72}
73
74#[derive(Clone, Debug)]
76pub struct SelectTwoModel<M, N>
77where
78 M: FromQueryResult,
79 N: FromQueryResult,
80{
81 model: PhantomData<(M, N)>,
82}
83
84#[derive(Clone, Debug)]
86pub struct SelectThreeModel<M, N, O>
87where
88 M: FromQueryResult,
89 N: FromQueryResult,
90 O: FromQueryResult,
91{
92 model: PhantomData<(M, N, O)>,
93}
94
95impl<T, C> SelectorTrait for SelectGetableValue<T, C>
96where
97 T: TryGetableMany,
98 C: strum::IntoEnumIterator + sea_query::Iden,
99{
100 type Item = T;
101
102 fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
103 let cols: Vec<String> = C::iter().map(|col| col.to_string()).collect();
104 T::try_get_many(&res, "", &cols).map_err(Into::into)
105 }
106}
107
108impl<T> SelectorTrait for SelectGetableTuple<T>
109where
110 T: TryGetableMany,
111{
112 type Item = T;
113
114 fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
115 T::try_get_many_by_index(&res).map_err(Into::into)
116 }
117}
118
119impl<M> SelectorTrait for SelectModel<M>
120where
121 M: FromQueryResult + Sized,
122{
123 type Item = M;
124
125 fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
126 M::from_query_result(&res, "")
127 }
128}
129
130impl<M, N> SelectorTrait for SelectTwoModel<M, N>
131where
132 M: FromQueryResult + Sized,
133 N: FromQueryResult + Sized,
134{
135 type Item = (M, Option<N>);
136
137 fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
138 Ok((
139 M::from_query_result(&res, SelectA.as_str())?,
140 N::from_query_result_optional(&res, SelectB.as_str())?,
141 ))
142 }
143}
144
145impl<M, N, O> SelectorTrait for SelectThreeModel<M, N, O>
146where
147 M: FromQueryResult + Sized,
148 N: FromQueryResult + Sized,
149 O: FromQueryResult + Sized,
150{
151 type Item = (M, Option<N>, Option<O>);
152
153 fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
154 Ok((
155 M::from_query_result(&res, SelectA.as_str())?,
156 N::from_query_result_optional(&res, SelectB.as_str())?,
157 O::from_query_result_optional(&res, SelectC.as_str())?,
158 ))
159 }
160}
161
162impl<E> Select<E>
163where
164 E: EntityTrait,
165{
166 #[allow(clippy::wrong_self_convention)]
168 pub fn from_raw_sql(self, stmt: Statement) -> SelectorRaw<SelectModel<E::Model>> {
169 SelectorRaw {
170 stmt,
171 selector: SelectModel { model: PhantomData },
172 }
173 }
174
175 pub fn into_model<M>(self) -> Selector<SelectModel<M>>
177 where
178 M: FromQueryResult,
179 {
180 Selector {
181 query: self.query,
182 selector: SelectModel { model: PhantomData },
183 }
184 }
185
186 pub fn into_partial_model<M>(self) -> Selector<SelectModel<M>>
219 where
220 M: PartialModelTrait,
221 {
222 M::select_cols(QuerySelect::select_only(self)).into_model::<M>()
223 }
224
225 #[cfg(feature = "with-json")]
227 pub fn into_json(self) -> Selector<SelectModel<JsonValue>> {
228 Selector {
229 query: self.query,
230 selector: SelectModel { model: PhantomData },
231 }
232 }
233
234 pub fn into_values<T, C>(self) -> Selector<SelectGetableValue<T, C>>
337 where
338 T: TryGetableMany,
339 C: strum::IntoEnumIterator + sea_query::Iden,
340 {
341 Selector::<SelectGetableValue<T, C>>::with_columns(self.query)
342 }
343
344 pub fn into_tuple<T>(self) -> Selector<SelectGetableTuple<T>>
436 where
437 T: TryGetableMany,
438 {
439 Selector::<SelectGetableTuple<T>>::into_tuple(self.query)
440 }
441
442 pub async fn one<C>(self, db: &C) -> Result<Option<E::Model>, DbErr>
444 where
445 C: ConnectionTrait,
446 {
447 self.into_model().one(db).await
448 }
449
450 pub async fn all<C>(self, db: &C) -> Result<Vec<E::Model>, DbErr>
452 where
453 C: ConnectionTrait,
454 {
455 self.into_model().all(db).await
456 }
457
458 pub async fn stream<'a: 'b, 'b, C>(
460 self,
461 db: &'a C,
462 ) -> Result<impl Stream<Item = Result<E::Model, DbErr>> + 'b + Send, DbErr>
463 where
464 C: ConnectionTrait + StreamTrait + Send,
465 {
466 self.into_model().stream(db).await
467 }
468
469 pub async fn stream_partial_model<'a: 'b, 'b, C, M>(
471 self,
472 db: &'a C,
473 ) -> Result<impl Stream<Item = Result<M, DbErr>> + 'b + Send, DbErr>
474 where
475 C: ConnectionTrait + StreamTrait + Send,
476 M: PartialModelTrait + Send + 'b,
477 {
478 self.into_partial_model().stream(db).await
479 }
480}
481
482impl<E, F> SelectTwo<E, F>
483where
484 E: EntityTrait,
485 F: EntityTrait,
486{
487 pub fn into_model<M, N>(self) -> Selector<SelectTwoModel<M, N>>
489 where
490 M: FromQueryResult,
491 N: FromQueryResult,
492 {
493 Selector {
494 query: self.query,
495 selector: SelectTwoModel { model: PhantomData },
496 }
497 }
498
499 pub fn into_partial_model<M, N>(self) -> Selector<SelectTwoModel<M, N>>
501 where
502 M: PartialModelTrait,
503 N: PartialModelTrait,
504 {
505 let select = QuerySelect::select_only(self);
506 let select = M::select_cols(select);
507 let select = N::select_cols(select);
508 select.into_model::<M, N>()
509 }
510
511 #[cfg(feature = "with-json")]
513 pub fn into_json(self) -> Selector<SelectTwoModel<JsonValue, JsonValue>> {
514 Selector {
515 query: self.query,
516 selector: SelectTwoModel { model: PhantomData },
517 }
518 }
519
520 pub async fn one<C>(self, db: &C) -> Result<Option<(E::Model, Option<F::Model>)>, DbErr>
522 where
523 C: ConnectionTrait,
524 {
525 self.into_model().one(db).await
526 }
527
528 pub async fn all<C>(self, db: &C) -> Result<Vec<(E::Model, Option<F::Model>)>, DbErr>
530 where
531 C: ConnectionTrait,
532 {
533 self.into_model().all(db).await
534 }
535
536 pub async fn stream<'a: 'b, 'b, C>(
538 self,
539 db: &'a C,
540 ) -> Result<impl Stream<Item = Result<(E::Model, Option<F::Model>), DbErr>> + 'b, DbErr>
541 where
542 C: ConnectionTrait + StreamTrait + Send,
543 {
544 self.into_model().stream(db).await
545 }
546
547 pub async fn stream_partial_model<'a: 'b, 'b, C, M, N>(
549 self,
550 db: &'a C,
551 ) -> Result<impl Stream<Item = Result<(M, Option<N>), DbErr>> + 'b + Send, DbErr>
552 where
553 C: ConnectionTrait + StreamTrait + Send,
554 M: PartialModelTrait + Send + 'b,
555 N: PartialModelTrait + Send + 'b,
556 {
557 self.into_partial_model().stream(db).await
558 }
559}
560
561impl<E, F> SelectTwoMany<E, F>
562where
563 E: EntityTrait,
564 F: EntityTrait,
565{
566 fn into_model<M, N>(self) -> Selector<SelectTwoModel<M, N>>
568 where
569 M: FromQueryResult,
570 N: FromQueryResult,
571 {
572 Selector {
573 query: self.query,
574 selector: SelectTwoModel { model: PhantomData },
575 }
576 }
577
578 fn into_partial_model<M, N>(self) -> Selector<SelectTwoModel<M, N>>
580 where
581 M: PartialModelTrait,
582 N: PartialModelTrait,
583 {
584 let select = self.select_only();
585 let select = M::select_cols(select);
586 let select = N::select_cols(select);
587 select.into_model()
588 }
589
590 #[cfg(feature = "with-json")]
592 pub fn into_json(self) -> Selector<SelectTwoModel<JsonValue, JsonValue>> {
593 Selector {
594 query: self.query,
595 selector: SelectTwoModel { model: PhantomData },
596 }
597 }
598
599 pub async fn stream<'a: 'b, 'b, C>(
601 self,
602 db: &'a C,
603 ) -> Result<impl Stream<Item = Result<(E::Model, Option<F::Model>), DbErr>> + 'b + Send, DbErr>
604 where
605 C: ConnectionTrait + StreamTrait + Send,
606 {
607 self.into_model().stream(db).await
608 }
609
610 pub async fn stream_partial_model<'a: 'b, 'b, C, M, N>(
612 self,
613 db: &'a C,
614 ) -> Result<impl Stream<Item = Result<(M, Option<N>), DbErr>> + 'b + Send, DbErr>
615 where
616 C: ConnectionTrait + StreamTrait + Send,
617 M: PartialModelTrait + Send + 'b,
618 N: PartialModelTrait + Send + 'b,
619 {
620 self.into_partial_model().stream(db).await
621 }
622
623 pub async fn all<C>(self, db: &C) -> Result<Vec<(E::Model, Vec<F::Model>)>, DbErr>
632 where
633 C: ConnectionTrait,
634 {
635 let rows = self.into_model().all(db).await?;
636 Ok(consolidate_query_result::<E, F>(rows))
637 }
638
639 }
648
649impl<E, F, G> SelectThree<E, F, G>
650where
651 E: EntityTrait,
652 F: EntityTrait,
653 G: EntityTrait,
654{
655 pub fn into_model<M, N, O>(self) -> Selector<SelectThreeModel<M, N, O>>
657 where
658 M: FromQueryResult,
659 N: FromQueryResult,
660 O: FromQueryResult,
661 {
662 Selector {
663 query: self.query,
664 selector: SelectThreeModel { model: PhantomData },
665 }
666 }
667
668 pub fn into_partial_model<M, N, O>(self) -> Selector<SelectThreeModel<M, N, O>>
670 where
671 M: PartialModelTrait,
672 N: PartialModelTrait,
673 O: PartialModelTrait,
674 {
675 let select = QuerySelect::select_only(self);
676 let select = M::select_cols(select);
677 let select = N::select_cols(select);
678 select.into_model::<M, N, O>()
679 }
680
681 #[cfg(feature = "with-json")]
683 pub fn into_json(self) -> Selector<SelectThreeModel<JsonValue, JsonValue, JsonValue>> {
684 Selector {
685 query: self.query,
686 selector: SelectThreeModel { model: PhantomData },
687 }
688 }
689
690 pub async fn one<C>(
692 self,
693 db: &C,
694 ) -> Result<Option<(E::Model, Option<F::Model>, Option<G::Model>)>, DbErr>
695 where
696 C: ConnectionTrait,
697 {
698 self.into_model().one(db).await
699 }
700
701 pub async fn all<C>(
703 self,
704 db: &C,
705 ) -> Result<Vec<(E::Model, Option<F::Model>, Option<G::Model>)>, DbErr>
706 where
707 C: ConnectionTrait,
708 {
709 self.into_model().all(db).await
710 }
711
712 pub async fn stream<'a: 'b, 'b, C>(
714 self,
715 db: &'a C,
716 ) -> Result<
717 impl Stream<Item = Result<(E::Model, Option<F::Model>, Option<G::Model>), DbErr>> + 'b,
718 DbErr,
719 >
720 where
721 C: ConnectionTrait + StreamTrait + Send,
722 {
723 self.into_model().stream(db).await
724 }
725
726 pub async fn stream_partial_model<'a: 'b, 'b, C, M, N, O>(
728 self,
729 db: &'a C,
730 ) -> Result<impl Stream<Item = Result<(M, Option<N>, Option<O>), DbErr>> + 'b + Send, DbErr>
731 where
732 C: ConnectionTrait + StreamTrait + Send,
733 M: PartialModelTrait + Send + 'b,
734 N: PartialModelTrait + Send + 'b,
735 O: PartialModelTrait + Send + 'b,
736 {
737 self.into_partial_model().stream(db).await
738 }
739}
740
741impl<S> Selector<S>
742where
743 S: SelectorTrait,
744{
745 pub fn with_columns<T, C>(query: SelectStatement) -> Selector<SelectGetableValue<T, C>>
748 where
749 T: TryGetableMany,
750 C: strum::IntoEnumIterator + sea_query::Iden,
751 {
752 Selector {
753 query,
754 selector: SelectGetableValue {
755 columns: PhantomData,
756 model: PhantomData,
757 },
758 }
759 }
760
761 pub fn into_tuple<T>(query: SelectStatement) -> Selector<SelectGetableTuple<T>>
763 where
764 T: TryGetableMany,
765 {
766 Selector {
767 query,
768 selector: SelectGetableTuple { model: PhantomData },
769 }
770 }
771
772 fn into_selector_raw<C>(self, db: &C) -> SelectorRaw<S>
773 where
774 C: ConnectionTrait,
775 {
776 let builder = db.get_database_backend();
777 let stmt = builder.build(&self.query);
778 SelectorRaw {
779 stmt,
780 selector: self.selector,
781 }
782 }
783
784 pub fn into_statement(self, builder: DbBackend) -> Statement {
786 builder.build(&self.query)
787 }
788
789 pub async fn one<C>(mut self, db: &C) -> Result<Option<S::Item>, DbErr>
791 where
792 C: ConnectionTrait,
793 {
794 self.query.limit(1);
795 self.into_selector_raw(db).one(db).await
796 }
797
798 pub async fn all<C>(self, db: &C) -> Result<Vec<S::Item>, DbErr>
800 where
801 C: ConnectionTrait,
802 {
803 self.into_selector_raw(db).all(db).await
804 }
805
806 pub async fn stream<'a: 'b, 'b, C>(
808 self,
809 db: &'a C,
810 ) -> Result<Pin<Box<dyn Stream<Item = Result<S::Item, DbErr>> + 'b + Send>>, DbErr>
811 where
812 C: ConnectionTrait + StreamTrait + Send,
813 S: 'b,
814 S::Item: Send,
815 {
816 self.into_selector_raw(db).stream(db).await
817 }
818}
819
820impl<S> SelectorRaw<S>
821where
822 S: SelectorTrait,
823{
824 pub fn from_statement<M>(stmt: Statement) -> SelectorRaw<SelectModel<M>>
826 where
827 M: FromQueryResult,
828 {
829 SelectorRaw {
830 stmt,
831 selector: SelectModel { model: PhantomData },
832 }
833 }
834
835 pub fn with_columns<T, C>(stmt: Statement) -> SelectorRaw<SelectGetableValue<T, C>>
838 where
839 T: TryGetableMany,
840 C: strum::IntoEnumIterator + sea_query::Iden,
841 {
842 SelectorRaw {
843 stmt,
844 selector: SelectGetableValue {
845 columns: PhantomData,
846 model: PhantomData,
847 },
848 }
849 }
850
851 pub fn into_model<M>(self) -> SelectorRaw<SelectModel<M>>
916 where
917 M: FromQueryResult,
918 {
919 SelectorRaw {
920 stmt: self.stmt,
921 selector: SelectModel { model: PhantomData },
922 }
923 }
924
925 #[cfg(feature = "with-json")]
982 pub fn into_json(self) -> SelectorRaw<SelectModel<JsonValue>> {
983 SelectorRaw {
984 stmt: self.stmt,
985 selector: SelectModel { model: PhantomData },
986 }
987 }
988
989 pub fn into_statement(self) -> Statement {
991 self.stmt
992 }
993
994 pub async fn one<C>(self, db: &C) -> Result<Option<S::Item>, DbErr>
1035 where
1036 C: ConnectionTrait,
1037 {
1038 let row = db.query_one(self.stmt).await?;
1039 match row {
1040 Some(row) => Ok(Some(S::from_raw_query_result(row)?)),
1041 None => Ok(None),
1042 }
1043 }
1044
1045 pub async fn all<C>(self, db: &C) -> Result<Vec<S::Item>, DbErr>
1086 where
1087 C: ConnectionTrait,
1088 {
1089 let rows = db.query_all(self.stmt).await?;
1090 let mut models = Vec::new();
1091 for row in rows.into_iter() {
1092 models.push(S::from_raw_query_result(row)?);
1093 }
1094 Ok(models)
1095 }
1096
1097 pub async fn stream<'a: 'b, 'b, C>(
1099 self,
1100 db: &'a C,
1101 ) -> Result<Pin<Box<dyn Stream<Item = Result<S::Item, DbErr>> + 'b + Send>>, DbErr>
1102 where
1103 C: ConnectionTrait + StreamTrait + Send,
1104 S: 'b,
1105 S::Item: Send,
1106 {
1107 let stream = db.stream(self.stmt).await?;
1108 Ok(Box::pin(stream.and_then(|row| {
1109 futures_util::future::ready(S::from_raw_query_result(row))
1110 })))
1111 }
1112}
1113
1114#[allow(clippy::unwrap_used)]
1115fn consolidate_query_result<L, R>(
1116 rows: Vec<(L::Model, Option<R::Model>)>,
1117) -> Vec<(L::Model, Vec<R::Model>)>
1118where
1119 L: EntityTrait,
1120 R: EntityTrait,
1121{
1122 match <<L::PrimaryKey as PrimaryKeyTrait>::ValueType as PrimaryKeyArity>::ARITY {
1123 1 => {
1124 let col = <L::PrimaryKey as Iterable>::iter()
1125 .next()
1126 .unwrap()
1127 .into_column();
1128 consolidate_query_result_of::<L, R, UnitPk<L>>(rows, UnitPk(col))
1129 }
1130 2 => {
1131 let mut iter = <L::PrimaryKey as Iterable>::iter();
1132 let col1 = iter.next().unwrap().into_column();
1133 let col2 = iter.next().unwrap().into_column();
1134 consolidate_query_result_of::<L, R, PairPk<L>>(rows, PairPk(col1, col2))
1135 }
1136 _ => {
1137 let cols: Vec<_> = <L::PrimaryKey as Iterable>::iter()
1138 .map(|pk| pk.into_column())
1139 .collect();
1140 consolidate_query_result_of::<L, R, TuplePk<L>>(rows, TuplePk(cols))
1141 }
1142 }
1143}
1144
1145trait ModelKey<E: EntityTrait> {
1146 type Type: Hash + PartialEq + Eq;
1147 fn get(&self, model: &E::Model) -> Self::Type;
1148}
1149
1150struct UnitPk<E: EntityTrait>(E::Column);
1152struct PairPk<E: EntityTrait>(E::Column, E::Column);
1153struct TuplePk<E: EntityTrait>(Vec<E::Column>);
1154
1155impl<E: EntityTrait> ModelKey<E> for UnitPk<E> {
1156 type Type = Value;
1157 fn get(&self, model: &E::Model) -> Self::Type {
1158 model.get(self.0)
1159 }
1160}
1161
1162impl<E: EntityTrait> ModelKey<E> for PairPk<E> {
1163 type Type = (Value, Value);
1164 fn get(&self, model: &E::Model) -> Self::Type {
1165 (model.get(self.0), model.get(self.1))
1166 }
1167}
1168
1169impl<E: EntityTrait> ModelKey<E> for TuplePk<E> {
1170 type Type = Vec<Value>;
1171 fn get(&self, model: &E::Model) -> Self::Type {
1172 let mut key = Vec::new();
1173 for col in self.0.iter() {
1174 key.push(model.get(*col));
1175 }
1176 key
1177 }
1178}
1179
1180fn consolidate_query_result_of<L, R, KEY: ModelKey<L>>(
1181 mut rows: Vec<(L::Model, Option<R::Model>)>,
1182 model_key: KEY,
1183) -> Vec<(L::Model, Vec<R::Model>)>
1184where
1185 L: EntityTrait,
1186 R: EntityTrait,
1187{
1188 let mut hashmap: HashMap<KEY::Type, Vec<R::Model>> =
1189 rows.iter_mut().fold(HashMap::new(), |mut acc, row| {
1190 let key = model_key.get(&row.0);
1191 if let Some(value) = row.1.take() {
1192 let vec: Option<&mut Vec<R::Model>> = acc.get_mut(&key);
1193 if let Some(vec) = vec {
1194 vec.push(value)
1195 } else {
1196 acc.insert(key, vec![value]);
1197 }
1198 } else {
1199 acc.entry(key).or_default();
1200 }
1201
1202 acc
1203 });
1204
1205 rows.into_iter()
1206 .filter_map(|(l_model, _)| {
1207 let l_pk = model_key.get(&l_model);
1208 let r_models = hashmap.remove(&l_pk);
1209 r_models.map(|r_models| (l_model, r_models))
1210 })
1211 .collect()
1212}
1213
1214#[allow(dead_code)]
1216fn consolidate_query_result_of_ordered_rows<L, R>(
1217 rows: Vec<(L::Model, Option<R::Model>)>,
1218) -> Vec<(L::Model, Vec<R::Model>)>
1219where
1220 L: EntityTrait,
1221 R: EntityTrait,
1222{
1223 let mut acc: Vec<(L::Model, Vec<R::Model>)> = Vec::new();
1224 for (l, r) in rows {
1225 if let Some((last_l, last_r)) = acc.last_mut() {
1226 let mut same_l = true;
1227 for pk_col in <L::PrimaryKey as Iterable>::iter() {
1228 let col = pk_col.into_column();
1229 let val = l.get(col);
1230 let last_val = last_l.get(col);
1231 if !val.eq(&last_val) {
1232 same_l = false;
1233 break;
1234 }
1235 }
1236 if same_l {
1237 if let Some(r) = r {
1238 last_r.push(r);
1239 continue;
1240 }
1241 }
1242 }
1243 let rows = match r {
1244 Some(r) => vec![r],
1245 None => vec![],
1246 };
1247 acc.push((l, rows));
1248 }
1249 acc
1250}
1251
1252#[cfg(test)]
1253mod tests {
1254 use pretty_assertions::assert_eq;
1255
1256 fn cake_fruit_model(
1257 cake_id: i32,
1258 fruit_id: i32,
1259 ) -> (
1260 sea_orm::tests_cfg::cake::Model,
1261 sea_orm::tests_cfg::fruit::Model,
1262 ) {
1263 (cake_model(cake_id), fruit_model(fruit_id, Some(cake_id)))
1264 }
1265
1266 fn cake_model(id: i32) -> sea_orm::tests_cfg::cake::Model {
1267 let name = match id {
1268 1 => "apple cake",
1269 2 => "orange cake",
1270 3 => "fruit cake",
1271 4 => "chocolate cake",
1272 _ => "",
1273 }
1274 .to_string();
1275 sea_orm::tests_cfg::cake::Model { id, name }
1276 }
1277
1278 fn filling_model(id: i32) -> sea_orm::tests_cfg::filling::Model {
1279 let name = match id {
1280 1 => "apple juice",
1281 2 => "orange jam",
1282 3 => "fruit",
1283 4 => "chocolate crust",
1284 _ => "",
1285 }
1286 .to_string();
1287 sea_orm::tests_cfg::filling::Model {
1288 id,
1289 name,
1290 vendor_id: Some(1),
1291 ignored_attr: 0,
1292 }
1293 }
1294
1295 fn cake_filling_models(
1296 cake_id: i32,
1297 filling_id: i32,
1298 ) -> (
1299 sea_orm::tests_cfg::cake::Model,
1300 sea_orm::tests_cfg::filling::Model,
1301 ) {
1302 (cake_model(cake_id), filling_model(filling_id))
1303 }
1304
1305 fn fruit_model(id: i32, cake_id: Option<i32>) -> sea_orm::tests_cfg::fruit::Model {
1306 let name = match id {
1307 1 => "apple",
1308 2 => "orange",
1309 3 => "grape",
1310 4 => "strawberry",
1311 _ => "",
1312 }
1313 .to_string();
1314 sea_orm::tests_cfg::fruit::Model { id, name, cake_id }
1315 }
1316
1317 fn cake_vendor_link(
1318 cake_id: i32,
1319 vendor_id: i32,
1320 ) -> (
1321 sea_orm::tests_cfg::cake::Model,
1322 sea_orm::tests_cfg::vendor::Model,
1323 ) {
1324 (cake_model(cake_id), vendor_model(vendor_id))
1325 }
1326
1327 fn vendor_model(id: i32) -> sea_orm::tests_cfg::vendor::Model {
1328 let name = match id {
1329 1 => "Apollo",
1330 2 => "Benny",
1331 3 => "Christine",
1332 4 => "David",
1333 _ => "",
1334 }
1335 .to_string();
1336 sea_orm::tests_cfg::vendor::Model { id, name }
1337 }
1338
1339 #[smol_potat::test]
1340 pub async fn also_related() -> Result<(), sea_orm::DbErr> {
1341 use sea_orm::tests_cfg::*;
1342 use sea_orm::{DbBackend, EntityTrait, MockDatabase, Statement, Transaction};
1343
1344 let db = MockDatabase::new(DbBackend::Postgres)
1345 .append_query_results([[cake_fruit_model(1, 1)]])
1346 .into_connection();
1347
1348 assert_eq!(
1349 Cake::find().find_also_related(Fruit).all(&db).await?,
1350 [(cake_model(1), Some(fruit_model(1, Some(1))))]
1351 );
1352
1353 assert_eq!(
1354 db.into_transaction_log(),
1355 [Transaction::many([Statement::from_sql_and_values(
1356 DbBackend::Postgres,
1357 [
1358 r#"SELECT "cake"."id" AS "A_id", "cake"."name" AS "A_name","#,
1359 r#""fruit"."id" AS "B_id", "fruit"."name" AS "B_name", "fruit"."cake_id" AS "B_cake_id""#,
1360 r#"FROM "cake""#,
1361 r#"LEFT JOIN "fruit" ON "cake"."id" = "fruit"."cake_id""#,
1362 ]
1363 .join(" ")
1364 .as_str(),
1365 []
1366 ),])]
1367 );
1368
1369 Ok(())
1370 }
1371
1372 #[smol_potat::test]
1373 pub async fn also_related_2() -> Result<(), sea_orm::DbErr> {
1374 use sea_orm::tests_cfg::*;
1375 use sea_orm::{DbBackend, EntityTrait, MockDatabase};
1376
1377 let db = MockDatabase::new(DbBackend::Postgres)
1378 .append_query_results([[cake_fruit_model(1, 1), cake_fruit_model(1, 2)]])
1379 .into_connection();
1380
1381 assert_eq!(
1382 Cake::find().find_also_related(Fruit).all(&db).await?,
1383 [
1384 (cake_model(1), Some(fruit_model(1, Some(1)))),
1385 (cake_model(1), Some(fruit_model(2, Some(1))))
1386 ]
1387 );
1388
1389 Ok(())
1390 }
1391
1392 #[smol_potat::test]
1393 pub async fn also_related_3() -> Result<(), sea_orm::DbErr> {
1394 use sea_orm::tests_cfg::*;
1395 use sea_orm::{DbBackend, EntityTrait, MockDatabase};
1396
1397 let db = MockDatabase::new(DbBackend::Postgres)
1398 .append_query_results([[
1399 cake_fruit_model(1, 1),
1400 cake_fruit_model(1, 2),
1401 cake_fruit_model(2, 3),
1402 ]])
1403 .into_connection();
1404
1405 assert_eq!(
1406 Cake::find().find_also_related(Fruit).all(&db).await?,
1407 [
1408 (cake_model(1), Some(fruit_model(1, Some(1)))),
1409 (cake_model(1), Some(fruit_model(2, Some(1)))),
1410 (cake_model(2), Some(fruit_model(3, Some(2))))
1411 ]
1412 );
1413
1414 Ok(())
1415 }
1416
1417 #[smol_potat::test]
1418 pub async fn also_related_4() -> Result<(), sea_orm::DbErr> {
1419 use sea_orm::tests_cfg::*;
1420 use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1421
1422 let db = MockDatabase::new(DbBackend::Postgres)
1423 .append_query_results([[
1424 cake_fruit_model(1, 1).into_mock_row(),
1425 cake_fruit_model(1, 2).into_mock_row(),
1426 cake_fruit_model(2, 3).into_mock_row(),
1427 (cake_model(3), None::<fruit::Model>).into_mock_row(),
1428 ]])
1429 .into_connection();
1430
1431 assert_eq!(
1432 Cake::find().find_also_related(Fruit).all(&db).await?,
1433 [
1434 (cake_model(1), Some(fruit_model(1, Some(1)))),
1435 (cake_model(1), Some(fruit_model(2, Some(1)))),
1436 (cake_model(2), Some(fruit_model(3, Some(2)))),
1437 (cake_model(3), None)
1438 ]
1439 );
1440
1441 Ok(())
1442 }
1443
1444 #[smol_potat::test]
1445 pub async fn also_related_many_to_many() -> Result<(), sea_orm::DbErr> {
1446 use sea_orm::tests_cfg::*;
1447 use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1448
1449 let db = MockDatabase::new(DbBackend::Postgres)
1450 .append_query_results([[
1451 cake_filling_models(1, 1).into_mock_row(),
1452 cake_filling_models(1, 2).into_mock_row(),
1453 cake_filling_models(2, 2).into_mock_row(),
1454 ]])
1455 .into_connection();
1456
1457 assert_eq!(
1458 Cake::find().find_also_related(Filling).all(&db).await?,
1459 [
1460 (cake_model(1), Some(filling_model(1))),
1461 (cake_model(1), Some(filling_model(2))),
1462 (cake_model(2), Some(filling_model(2))),
1463 ]
1464 );
1465
1466 Ok(())
1467 }
1468
1469 #[smol_potat::test]
1470 pub async fn also_related_many_to_many_2() -> Result<(), sea_orm::DbErr> {
1471 use sea_orm::tests_cfg::*;
1472 use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1473
1474 let db = MockDatabase::new(DbBackend::Postgres)
1475 .append_query_results([[
1476 cake_filling_models(1, 1).into_mock_row(),
1477 cake_filling_models(1, 2).into_mock_row(),
1478 cake_filling_models(2, 2).into_mock_row(),
1479 (cake_model(3), None::<filling::Model>).into_mock_row(),
1480 ]])
1481 .into_connection();
1482
1483 assert_eq!(
1484 Cake::find().find_also_related(Filling).all(&db).await?,
1485 [
1486 (cake_model(1), Some(filling_model(1))),
1487 (cake_model(1), Some(filling_model(2))),
1488 (cake_model(2), Some(filling_model(2))),
1489 (cake_model(3), None)
1490 ]
1491 );
1492
1493 Ok(())
1494 }
1495
1496 #[smol_potat::test]
1497 pub async fn with_related() -> Result<(), sea_orm::DbErr> {
1498 use sea_orm::tests_cfg::*;
1499 use sea_orm::{DbBackend, EntityTrait, MockDatabase, Statement, Transaction};
1500
1501 let db = MockDatabase::new(DbBackend::Postgres)
1502 .append_query_results([[
1503 cake_fruit_model(1, 1),
1504 cake_fruit_model(2, 2),
1505 cake_fruit_model(2, 3),
1506 ]])
1507 .into_connection();
1508
1509 assert_eq!(
1510 Cake::find().find_with_related(Fruit).all(&db).await?,
1511 [
1512 (cake_model(1), vec![fruit_model(1, Some(1))]),
1513 (
1514 cake_model(2),
1515 vec![fruit_model(2, Some(2)), fruit_model(3, Some(2))]
1516 )
1517 ]
1518 );
1519
1520 assert_eq!(
1521 db.into_transaction_log(),
1522 [Transaction::many([Statement::from_sql_and_values(
1523 DbBackend::Postgres,
1524 [
1525 r#"SELECT "cake"."id" AS "A_id", "cake"."name" AS "A_name","#,
1526 r#""fruit"."id" AS "B_id", "fruit"."name" AS "B_name", "fruit"."cake_id" AS "B_cake_id""#,
1527 r#"FROM "cake""#,
1528 r#"LEFT JOIN "fruit" ON "cake"."id" = "fruit"."cake_id""#,
1529 r#"ORDER BY "cake"."id" ASC"#
1530 ]
1531 .join(" ")
1532 .as_str(),
1533 []
1534 ),])]
1535 );
1536
1537 Ok(())
1538 }
1539
1540 #[smol_potat::test]
1541 pub async fn with_related_2() -> Result<(), sea_orm::DbErr> {
1542 use sea_orm::tests_cfg::*;
1543 use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1544
1545 let db = MockDatabase::new(DbBackend::Postgres)
1546 .append_query_results([[
1547 cake_fruit_model(1, 1).into_mock_row(),
1548 cake_fruit_model(2, 2).into_mock_row(),
1549 cake_fruit_model(2, 3).into_mock_row(),
1550 cake_fruit_model(2, 4).into_mock_row(),
1551 ]])
1552 .into_connection();
1553
1554 assert_eq!(
1555 Cake::find().find_with_related(Fruit).all(&db).await?,
1556 [
1557 (cake_model(1), vec![fruit_model(1, Some(1)),]),
1558 (
1559 cake_model(2),
1560 vec![
1561 fruit_model(2, Some(2)),
1562 fruit_model(3, Some(2)),
1563 fruit_model(4, Some(2)),
1564 ]
1565 ),
1566 ]
1567 );
1568
1569 Ok(())
1570 }
1571
1572 #[smol_potat::test]
1573 pub async fn with_related_empty() -> Result<(), sea_orm::DbErr> {
1574 use sea_orm::tests_cfg::*;
1575 use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1576
1577 let db = MockDatabase::new(DbBackend::Postgres)
1578 .append_query_results([[
1579 cake_fruit_model(1, 1).into_mock_row(),
1580 cake_fruit_model(2, 2).into_mock_row(),
1581 cake_fruit_model(2, 3).into_mock_row(),
1582 cake_fruit_model(2, 4).into_mock_row(),
1583 (cake_model(3), None::<fruit::Model>).into_mock_row(),
1584 ]])
1585 .into_connection();
1586
1587 assert_eq!(
1588 Cake::find().find_with_related(Fruit).all(&db).await?,
1589 [
1590 (cake_model(1), vec![fruit_model(1, Some(1)),]),
1591 (
1592 cake_model(2),
1593 vec![
1594 fruit_model(2, Some(2)),
1595 fruit_model(3, Some(2)),
1596 fruit_model(4, Some(2)),
1597 ]
1598 ),
1599 (cake_model(3), vec![])
1600 ]
1601 );
1602
1603 Ok(())
1604 }
1605
1606 #[smol_potat::test]
1607 pub async fn with_related_many_to_many() -> Result<(), sea_orm::DbErr> {
1608 use sea_orm::tests_cfg::*;
1609 use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1610
1611 let db = MockDatabase::new(DbBackend::Postgres)
1612 .append_query_results([[
1613 cake_filling_models(1, 1).into_mock_row(),
1614 cake_filling_models(1, 2).into_mock_row(),
1615 cake_filling_models(2, 2).into_mock_row(),
1616 ]])
1617 .into_connection();
1618
1619 assert_eq!(
1620 Cake::find().find_with_related(Filling).all(&db).await?,
1621 [
1622 (cake_model(1), vec![filling_model(1), filling_model(2)]),
1623 (cake_model(2), vec![filling_model(2)]),
1624 ]
1625 );
1626
1627 Ok(())
1628 }
1629
1630 #[smol_potat::test]
1631 pub async fn with_related_many_to_many_2() -> Result<(), sea_orm::DbErr> {
1632 use sea_orm::tests_cfg::*;
1633 use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1634
1635 let db = MockDatabase::new(DbBackend::Postgres)
1636 .append_query_results([[
1637 cake_filling_models(1, 1).into_mock_row(),
1638 cake_filling_models(1, 2).into_mock_row(),
1639 cake_filling_models(2, 2).into_mock_row(),
1640 (cake_model(3), None::<filling::Model>).into_mock_row(),
1641 ]])
1642 .into_connection();
1643
1644 assert_eq!(
1645 Cake::find().find_with_related(Filling).all(&db).await?,
1646 [
1647 (cake_model(1), vec![filling_model(1), filling_model(2)]),
1648 (cake_model(2), vec![filling_model(2)]),
1649 (cake_model(3), vec![])
1650 ]
1651 );
1652
1653 Ok(())
1654 }
1655
1656 #[smol_potat::test]
1657 pub async fn also_linked_base() -> Result<(), sea_orm::DbErr> {
1658 use sea_orm::tests_cfg::*;
1659 use sea_orm::{DbBackend, EntityTrait, MockDatabase, Statement, Transaction};
1660
1661 let db = MockDatabase::new(DbBackend::Postgres)
1662 .append_query_results([[cake_vendor_link(1, 1)]])
1663 .into_connection();
1664
1665 assert_eq!(
1666 Cake::find()
1667 .find_also_linked(entity_linked::CakeToFillingVendor)
1668 .all(&db)
1669 .await?,
1670 [(cake_model(1), Some(vendor_model(1)))]
1671 );
1672
1673 assert_eq!(
1674 db.into_transaction_log(),
1675 [Transaction::many([Statement::from_sql_and_values(
1676 DbBackend::Postgres,
1677 [
1678 r#"SELECT "cake"."id" AS "A_id", "cake"."name" AS "A_name","#,
1679 r#""r2"."id" AS "B_id", "r2"."name" AS "B_name""#,
1680 r#"FROM "cake""#,
1681 r#"LEFT JOIN "cake_filling" AS "r0" ON "cake"."id" = "r0"."cake_id""#,
1682 r#"LEFT JOIN "filling" AS "r1" ON "r0"."filling_id" = "r1"."id""#,
1683 r#"LEFT JOIN "vendor" AS "r2" ON "r1"."vendor_id" = "r2"."id""#,
1684 ]
1685 .join(" ")
1686 .as_str(),
1687 []
1688 ),])]
1689 );
1690
1691 Ok(())
1692 }
1693
1694 #[smol_potat::test]
1695 pub async fn also_linked_same_cake() -> Result<(), sea_orm::DbErr> {
1696 use sea_orm::tests_cfg::*;
1697 use sea_orm::{DbBackend, EntityTrait, MockDatabase};
1698
1699 let db = MockDatabase::new(DbBackend::Postgres)
1700 .append_query_results([[
1701 cake_vendor_link(1, 1),
1702 cake_vendor_link(1, 2),
1703 cake_vendor_link(2, 3),
1704 ]])
1705 .into_connection();
1706
1707 assert_eq!(
1708 Cake::find()
1709 .find_also_linked(entity_linked::CakeToFillingVendor)
1710 .all(&db)
1711 .await?,
1712 [
1713 (cake_model(1), Some(vendor_model(1))),
1714 (cake_model(1), Some(vendor_model(2))),
1715 (cake_model(2), Some(vendor_model(3)))
1716 ]
1717 );
1718
1719 Ok(())
1720 }
1721
1722 #[smol_potat::test]
1723 pub async fn also_linked_same_vendor() -> Result<(), sea_orm::DbErr> {
1724 use sea_orm::tests_cfg::*;
1725 use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1726
1727 let db = MockDatabase::new(DbBackend::Postgres)
1728 .append_query_results([[
1729 cake_vendor_link(1, 1).into_mock_row(),
1730 cake_vendor_link(2, 1).into_mock_row(),
1731 cake_vendor_link(3, 2).into_mock_row(),
1732 ]])
1733 .into_connection();
1734
1735 assert_eq!(
1736 Cake::find()
1737 .find_also_linked(entity_linked::CakeToFillingVendor)
1738 .all(&db)
1739 .await?,
1740 [
1741 (cake_model(1), Some(vendor_model(1))),
1742 (cake_model(2), Some(vendor_model(1))),
1743 (cake_model(3), Some(vendor_model(2))),
1744 ]
1745 );
1746
1747 Ok(())
1748 }
1749
1750 #[smol_potat::test]
1751 pub async fn also_linked_many_to_many() -> Result<(), sea_orm::DbErr> {
1752 use sea_orm::tests_cfg::*;
1753 use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1754
1755 let db = MockDatabase::new(DbBackend::Postgres)
1756 .append_query_results([[
1757 cake_vendor_link(1, 1).into_mock_row(),
1758 cake_vendor_link(1, 2).into_mock_row(),
1759 cake_vendor_link(1, 3).into_mock_row(),
1760 cake_vendor_link(2, 1).into_mock_row(),
1761 cake_vendor_link(2, 2).into_mock_row(),
1762 ]])
1763 .into_connection();
1764
1765 assert_eq!(
1766 Cake::find()
1767 .find_also_linked(entity_linked::CakeToFillingVendor)
1768 .all(&db)
1769 .await?,
1770 [
1771 (cake_model(1), Some(vendor_model(1))),
1772 (cake_model(1), Some(vendor_model(2))),
1773 (cake_model(1), Some(vendor_model(3))),
1774 (cake_model(2), Some(vendor_model(1))),
1775 (cake_model(2), Some(vendor_model(2))),
1776 ]
1777 );
1778
1779 Ok(())
1780 }
1781
1782 #[smol_potat::test]
1783 pub async fn also_linked_empty() -> Result<(), sea_orm::DbErr> {
1784 use sea_orm::tests_cfg::*;
1785 use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1786
1787 let db = MockDatabase::new(DbBackend::Postgres)
1788 .append_query_results([[
1789 cake_vendor_link(1, 1).into_mock_row(),
1790 cake_vendor_link(2, 2).into_mock_row(),
1791 cake_vendor_link(3, 3).into_mock_row(),
1792 (cake_model(4), None::<vendor::Model>).into_mock_row(),
1793 ]])
1794 .into_connection();
1795
1796 assert_eq!(
1797 Cake::find()
1798 .find_also_linked(entity_linked::CakeToFillingVendor)
1799 .all(&db)
1800 .await?,
1801 [
1802 (cake_model(1), Some(vendor_model(1))),
1803 (cake_model(2), Some(vendor_model(2))),
1804 (cake_model(3), Some(vendor_model(3))),
1805 (cake_model(4), None)
1806 ]
1807 );
1808
1809 Ok(())
1810 }
1811
1812 #[smol_potat::test]
1813 pub async fn with_linked_base() -> Result<(), sea_orm::DbErr> {
1814 use sea_orm::tests_cfg::*;
1815 use sea_orm::{DbBackend, EntityTrait, MockDatabase, Statement, Transaction};
1816
1817 let db = MockDatabase::new(DbBackend::Postgres)
1818 .append_query_results([[
1819 cake_vendor_link(1, 1),
1820 cake_vendor_link(2, 2),
1821 cake_vendor_link(2, 3),
1822 ]])
1823 .into_connection();
1824
1825 assert_eq!(
1826 Cake::find()
1827 .find_with_linked(entity_linked::CakeToFillingVendor)
1828 .all(&db)
1829 .await?,
1830 [
1831 (cake_model(1), vec![vendor_model(1)]),
1832 (cake_model(2), vec![vendor_model(2), vendor_model(3)])
1833 ]
1834 );
1835
1836 assert_eq!(
1837 db.into_transaction_log(),
1838 [Transaction::many([Statement::from_sql_and_values(
1839 DbBackend::Postgres,
1840 [
1841 r#"SELECT "cake"."id" AS "A_id", "cake"."name" AS "A_name","#,
1842 r#""r2"."id" AS "B_id", "r2"."name" AS "B_name" FROM "cake""#,
1843 r#"LEFT JOIN "cake_filling" AS "r0" ON "cake"."id" = "r0"."cake_id""#,
1844 r#"LEFT JOIN "filling" AS "r1" ON "r0"."filling_id" = "r1"."id""#,
1845 r#"LEFT JOIN "vendor" AS "r2" ON "r1"."vendor_id" = "r2"."id""#,
1846 ]
1847 .join(" ")
1848 .as_str(),
1849 []
1850 ),])]
1851 );
1852
1853 Ok(())
1854 }
1855
1856 #[smol_potat::test]
1857 pub async fn with_linked_same_vendor() -> Result<(), sea_orm::DbErr> {
1858 use sea_orm::tests_cfg::*;
1859 use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1860
1861 let db = MockDatabase::new(DbBackend::Postgres)
1862 .append_query_results([[
1863 cake_vendor_link(1, 1).into_mock_row(),
1864 cake_vendor_link(2, 2).into_mock_row(),
1865 cake_vendor_link(3, 2).into_mock_row(),
1866 ]])
1867 .into_connection();
1868
1869 assert_eq!(
1870 Cake::find()
1871 .find_with_linked(entity_linked::CakeToFillingVendor)
1872 .all(&db)
1873 .await?,
1874 [
1875 (cake_model(1), vec![vendor_model(1)]),
1876 (cake_model(2), vec![vendor_model(2)]),
1877 (cake_model(3), vec![vendor_model(2)])
1878 ]
1879 );
1880
1881 Ok(())
1882 }
1883
1884 #[smol_potat::test]
1885 pub async fn with_linked_empty() -> Result<(), sea_orm::DbErr> {
1886 use sea_orm::tests_cfg::*;
1887 use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1888
1889 let db = MockDatabase::new(DbBackend::Postgres)
1890 .append_query_results([[
1891 cake_vendor_link(1, 1).into_mock_row(),
1892 cake_vendor_link(2, 1).into_mock_row(),
1893 cake_vendor_link(2, 2).into_mock_row(),
1894 (cake_model(3), None::<vendor::Model>).into_mock_row(),
1895 ]])
1896 .into_connection();
1897
1898 assert_eq!(
1899 Cake::find()
1900 .find_with_linked(entity_linked::CakeToFillingVendor)
1901 .all(&db)
1902 .await?,
1903 [
1904 (cake_model(1), vec![vendor_model(1)]),
1905 (cake_model(2), vec![vendor_model(1), vendor_model(2)]),
1906 (cake_model(3), vec![])
1907 ]
1908 );
1909
1910 Ok(())
1911 }
1912
1913 #[smol_potat::test]
1915 pub async fn with_linked_repeated() -> Result<(), sea_orm::DbErr> {
1916 use sea_orm::tests_cfg::*;
1917 use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1918
1919 let db = MockDatabase::new(DbBackend::Postgres)
1920 .append_query_results([[
1921 cake_vendor_link(1, 1).into_mock_row(),
1922 cake_vendor_link(1, 1).into_mock_row(),
1923 cake_vendor_link(2, 1).into_mock_row(),
1924 cake_vendor_link(2, 2).into_mock_row(),
1925 ]])
1926 .into_connection();
1927
1928 assert_eq!(
1929 Cake::find()
1930 .find_with_linked(entity_linked::CakeToFillingVendor)
1931 .all(&db)
1932 .await?,
1933 [
1934 (cake_model(1), vec![vendor_model(1), vendor_model(1)]),
1935 (cake_model(2), vec![vendor_model(1), vendor_model(2)]),
1936 ]
1937 );
1938
1939 Ok(())
1940 }
1941}