1use crate::{
2 Condition, ConnectionTrait, DbErr, EntityTrait, Identity, JoinType, ModelTrait, QueryFilter,
3 QuerySelect, Related, RelationType, Select, dynamic, error::*,
4};
5use async_trait::async_trait;
6use sea_query::{
7 ColumnRef, DynIden, Expr, ExprTrait, IntoColumnRef, SimpleExpr, TableRef, ValueTuple,
8};
9use std::{
10 collections::{HashMap, HashSet},
11 str::FromStr,
12};
13
14pub trait EntityOrSelect<E: EntityTrait>: Send {
16 fn select(self) -> Select<E>;
18}
19
20#[async_trait]
22pub trait LoaderTrait {
23 type Model: ModelTrait;
25
26 async fn load_one<R, S, C>(&self, stmt: S, db: &C) -> Result<Vec<Option<R::Model>>, DbErr>
28 where
29 C: ConnectionTrait,
30 R: EntityTrait,
31 R::Model: Send + Sync,
32 S: EntityOrSelect<R>,
33 <<Self as LoaderTrait>::Model as ModelTrait>::Entity: Related<R>;
34
35 async fn load_many<R, S, C>(&self, stmt: S, db: &C) -> Result<Vec<Vec<R::Model>>, DbErr>
37 where
38 C: ConnectionTrait,
39 R: EntityTrait,
40 R::Model: Send + Sync,
41 S: EntityOrSelect<R>,
42 <<Self as LoaderTrait>::Model as ModelTrait>::Entity: Related<R>;
43
44 async fn load_many_to_many<R, S, V, C>(
46 &self,
47 stmt: S,
48 via: V,
49 db: &C,
50 ) -> Result<Vec<Vec<R::Model>>, DbErr>
51 where
52 C: ConnectionTrait,
53 R: EntityTrait,
54 R::Model: Send + Sync,
55 S: EntityOrSelect<R>,
56 V: EntityTrait,
57 V::Model: Send + Sync,
58 <<Self as LoaderTrait>::Model as ModelTrait>::Entity: Related<R>;
59}
60
61impl<E> EntityOrSelect<E> for E
62where
63 E: EntityTrait,
64{
65 fn select(self) -> Select<E> {
66 E::find()
67 }
68}
69
70impl<E> EntityOrSelect<E> for Select<E>
71where
72 E: EntityTrait,
73{
74 fn select(self) -> Select<E> {
75 self
76 }
77}
78
79#[async_trait]
80impl<M> LoaderTrait for Vec<M>
81where
82 M: ModelTrait + Sync,
83{
84 type Model = M;
85
86 async fn load_one<R, S, C>(&self, stmt: S, db: &C) -> Result<Vec<Option<R::Model>>, DbErr>
87 where
88 C: ConnectionTrait,
89 R: EntityTrait,
90 R::Model: Send + Sync,
91 S: EntityOrSelect<R>,
92 <<Self as LoaderTrait>::Model as ModelTrait>::Entity: Related<R>,
93 {
94 self.as_slice().load_one(stmt, db).await
95 }
96
97 async fn load_many<R, S, C>(&self, stmt: S, db: &C) -> Result<Vec<Vec<R::Model>>, DbErr>
98 where
99 C: ConnectionTrait,
100 R: EntityTrait,
101 R::Model: Send + Sync,
102 S: EntityOrSelect<R>,
103 <<Self as LoaderTrait>::Model as ModelTrait>::Entity: Related<R>,
104 {
105 self.as_slice().load_many(stmt, db).await
106 }
107
108 async fn load_many_to_many<R, S, V, C>(
109 &self,
110 stmt: S,
111 via: V,
112 db: &C,
113 ) -> Result<Vec<Vec<R::Model>>, DbErr>
114 where
115 C: ConnectionTrait,
116 R: EntityTrait,
117 R::Model: Send + Sync,
118 S: EntityOrSelect<R>,
119 V: EntityTrait,
120 V::Model: Send + Sync,
121 <<Self as LoaderTrait>::Model as ModelTrait>::Entity: Related<R>,
122 {
123 self.as_slice().load_many_to_many(stmt, via, db).await
124 }
125}
126
127#[async_trait]
128impl<M> LoaderTrait for &[M]
129where
130 M: ModelTrait + Sync,
131{
132 type Model = M;
133
134 async fn load_one<R, S, C>(&self, stmt: S, db: &C) -> Result<Vec<Option<R::Model>>, DbErr>
135 where
136 C: ConnectionTrait,
137 R: EntityTrait,
138 R::Model: Send + Sync,
139 S: EntityOrSelect<R>,
140 <<Self as LoaderTrait>::Model as ModelTrait>::Entity: Related<R>,
141 {
142 if <<<Self as LoaderTrait>::Model as ModelTrait>::Entity as Related<R>>::via().is_some() {
144 return Err(query_err("Relation is ManytoMany instead of HasOne"));
145 }
146 let rel_def = <<<Self as LoaderTrait>::Model as ModelTrait>::Entity as Related<R>>::to();
147 if rel_def.rel_type == RelationType::HasMany {
148 return Err(query_err("Relation is HasMany instead of HasOne"));
149 }
150
151 if self.is_empty() {
152 return Ok(Vec::new());
153 }
154
155 let keys = self
156 .iter()
157 .map(|model| extract_key(&rel_def.from_col, model))
158 .collect::<Result<Vec<_>, _>>()?;
159
160 let condition = prepare_condition(&rel_def.to_tbl, &rel_def.to_col, &keys);
161
162 let stmt = <Select<R> as QueryFilter>::filter(stmt.select(), condition);
163
164 let data = stmt.all(db).await?;
165
166 let hashmap = data.into_iter().try_fold(
167 HashMap::<ValueTuple, <R as EntityTrait>::Model>::new(),
168 |mut acc, value| {
169 extract_key(&rel_def.to_col, &value).map(|key| {
170 acc.insert(key, value);
171
172 acc
173 })
174 },
175 )?;
176
177 let result: Vec<Option<<R as EntityTrait>::Model>> =
178 keys.iter().map(|key| hashmap.get(key).cloned()).collect();
179
180 Ok(result)
181 }
182
183 async fn load_many<R, S, C>(&self, stmt: S, db: &C) -> Result<Vec<Vec<R::Model>>, DbErr>
184 where
185 C: ConnectionTrait,
186 R: EntityTrait,
187 R::Model: Send + Sync,
188 S: EntityOrSelect<R>,
189 <<Self as LoaderTrait>::Model as ModelTrait>::Entity: Related<R>,
190 {
191 if self.is_empty() {
192 return Ok(Vec::new());
193 }
194
195 if let Some(via_def) =
196 <<<Self as LoaderTrait>::Model as ModelTrait>::Entity as Related<R>>::via()
197 {
198 let keys = self
199 .iter()
200 .map(|model| extract_key(&via_def.from_col, model))
201 .collect::<Result<Vec<_>, _>>()?;
202
203 let condition = prepare_condition(&via_def.to_tbl, &via_def.to_col, &keys);
204
205 let stmt = <Select<R> as QueryFilter>::filter(
206 stmt.select().join_rev(
207 JoinType::InnerJoin,
208 <<<Self as LoaderTrait>::Model as ModelTrait>::Entity as Related<R>>::to(),
209 ),
210 condition,
211 );
212
213 let data = stmt
223 .select_also_dyn_model(
224 via_def.to_tbl.sea_orm_table().clone(),
225 dynamic::ModelType {
226 fields: extract_col_type::<M>(&via_def.from_col, &via_def.to_col)?,
228 },
229 )
230 .all(db)
231 .await?;
232
233 let mut hashmap: HashMap<ValueTuple, Vec<<R as EntityTrait>::Model>> = keys
234 .iter()
235 .fold(HashMap::new(), |mut acc, key: &ValueTuple| {
236 acc.insert(key.clone(), Vec::new());
237 acc
238 });
239
240 for (item, key) in data {
241 let key = dyn_model_to_key(key)?;
242
243 let vec = hashmap.get_mut(&key).ok_or_else(|| {
244 DbErr::RecordNotFound(format!("Loader: failed to find model for {key:?}"))
245 })?;
246
247 vec.push(item);
248 }
249
250 let result: Vec<Vec<R::Model>> = keys
251 .iter()
252 .map(|key: &ValueTuple| hashmap.get(key).cloned().unwrap_or_default())
253 .collect();
254
255 Ok(result)
256 } else {
257 let rel_def =
258 <<<Self as LoaderTrait>::Model as ModelTrait>::Entity as Related<R>>::to();
259
260 let keys = self
261 .iter()
262 .map(|model| extract_key(&rel_def.from_col, model))
263 .collect::<Result<Vec<_>, _>>()?;
264
265 let condition = prepare_condition(&rel_def.to_tbl, &rel_def.to_col, &keys);
266
267 let stmt = <Select<R> as QueryFilter>::filter(stmt.select(), condition);
268
269 let data = stmt.all(db).await?;
270
271 let mut hashmap: HashMap<ValueTuple, Vec<<R as EntityTrait>::Model>> = keys
272 .iter()
273 .fold(HashMap::new(), |mut acc, key: &ValueTuple| {
274 acc.insert(key.clone(), Vec::new());
275 acc
276 });
277
278 for value in data {
279 let key = extract_key(&rel_def.to_col, &value)?;
280
281 let vec = hashmap.get_mut(&key).ok_or_else(|| {
282 DbErr::RecordNotFound(format!("Loader: failed to find model for {key:?}"))
283 })?;
284
285 vec.push(value);
286 }
287
288 let result: Vec<Vec<R::Model>> = keys
289 .iter()
290 .map(|key: &ValueTuple| hashmap.get(key).cloned().unwrap_or_default())
291 .collect();
292
293 Ok(result)
294 }
295 }
296
297 async fn load_many_to_many<R, S, V, C>(
298 &self,
299 stmt: S,
300 via: V,
301 db: &C,
302 ) -> Result<Vec<Vec<R::Model>>, DbErr>
303 where
304 C: ConnectionTrait,
305 R: EntityTrait,
306 R::Model: Send + Sync,
307 S: EntityOrSelect<R>,
308 V: EntityTrait,
309 V::Model: Send + Sync,
310 <<Self as LoaderTrait>::Model as ModelTrait>::Entity: Related<R>,
311 {
312 if let Some(via_rel) =
313 <<<Self as LoaderTrait>::Model as ModelTrait>::Entity as Related<R>>::via()
314 {
315 let rel_def =
316 <<<Self as LoaderTrait>::Model as ModelTrait>::Entity as Related<R>>::to();
317 if rel_def.rel_type != RelationType::HasOne {
318 return Err(query_err("Relation to is not HasOne"));
319 }
320
321 if !cmp_table_ref(&via_rel.to_tbl, &via.table_ref()) {
322 return Err(query_err(format!(
323 "The given via Entity is incorrect: expected: {:?}, given: {:?}",
324 via_rel.to_tbl,
325 via.table_ref()
326 )));
327 }
328
329 if self.is_empty() {
330 return Ok(Vec::new());
331 }
332
333 let pkeys = self
334 .iter()
335 .map(|model| extract_key(&via_rel.from_col, model))
336 .collect::<Result<Vec<_>, _>>()?;
337
338 let mut keymap: HashMap<ValueTuple, Vec<ValueTuple>> = Default::default();
340
341 let keys: Vec<ValueTuple> = {
342 let condition = prepare_condition(&via_rel.to_tbl, &via_rel.to_col, &pkeys);
343 let stmt = V::find().filter(condition);
344 let data = stmt.all(db).await?;
345 for model in data {
346 let pk = extract_key(&via_rel.to_col, &model)?;
347 let entry = keymap.entry(pk).or_default();
348
349 let fk = extract_key(&rel_def.from_col, &model)?;
350 entry.push(fk);
351 }
352
353 keymap.values().flatten().cloned().collect()
354 };
355
356 let condition = prepare_condition(&rel_def.to_tbl, &rel_def.to_col, &keys);
357
358 let stmt = <Select<R> as QueryFilter>::filter(stmt.select(), condition);
359
360 let models = stmt.all(db).await?;
361
362 let data = models.into_iter().try_fold(
364 HashMap::<ValueTuple, <R as EntityTrait>::Model>::new(),
365 |mut acc, model| {
366 extract_key(&rel_def.to_col, &model).map(|key| {
367 acc.insert(key, model);
368
369 acc
370 })
371 },
372 )?;
373
374 let result: Vec<Vec<R::Model>> = pkeys
375 .into_iter()
376 .map(|pkey| {
377 let fkeys = keymap.get(&pkey).cloned().unwrap_or_default();
378
379 let models: Vec<_> = fkeys
380 .into_iter()
381 .filter_map(|fkey| data.get(&fkey).cloned())
382 .collect();
383
384 models
385 })
386 .collect();
387
388 Ok(result)
389 } else {
390 return Err(query_err("Relation is not ManyToMany"));
391 }
392 }
393}
394
395fn cmp_table_ref(left: &TableRef, right: &TableRef) -> bool {
396 left == right
397}
398
399fn extract_key<Model>(target_col: &Identity, model: &Model) -> Result<ValueTuple, DbErr>
400where
401 Model: ModelTrait,
402{
403 Ok(match target_col {
404 Identity::Unary(a) => {
405 let a = a.to_string();
406 let column_a =
407 <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(&a)
408 .map_err(|_| DbErr::Type(format!("Failed at mapping '{a}' to column A:1")))?;
409 ValueTuple::One(model.get(column_a))
410 }
411 Identity::Binary(a, b) => {
412 let a = a.to_string();
413 let b = b.to_string();
414 let column_a =
415 <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(&a)
416 .map_err(|_| DbErr::Type(format!("Failed at mapping '{a}' to column A:2")))?;
417 let column_b =
418 <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(&b)
419 .map_err(|_| DbErr::Type(format!("Failed at mapping '{b}' to column B:2")))?;
420 ValueTuple::Two(model.get(column_a), model.get(column_b))
421 }
422 Identity::Ternary(a, b, c) => {
423 let a = a.to_string();
424 let b = b.to_string();
425 let c = c.to_string();
426 let column_a =
427 <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(
428 &a.to_string(),
429 )
430 .map_err(|_| DbErr::Type(format!("Failed at mapping '{a}' to column A:3")))?;
431 let column_b =
432 <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(
433 &b.to_string(),
434 )
435 .map_err(|_| DbErr::Type(format!("Failed at mapping '{b}' to column B:3")))?;
436 let column_c =
437 <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(
438 &c.to_string(),
439 )
440 .map_err(|_| DbErr::Type(format!("Failed at mapping '{c}' to column C:3")))?;
441 ValueTuple::Three(
442 model.get(column_a),
443 model.get(column_b),
444 model.get(column_c),
445 )
446 }
447 Identity::Many(cols) => {
448 let mut values = Vec::new();
449 for col in cols {
450 let col_name = col.to_string();
451 let column =
452 <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(
453 &col_name,
454 )
455 .map_err(|_| DbErr::Type(format!("Failed at mapping '{col_name}' to colum")))?;
456 values.push(model.get(column))
457 }
458 ValueTuple::Many(values)
459 }
460 })
461}
462
463fn extract_col_type<Model>(
464 left: &Identity,
465 right: &Identity,
466) -> Result<Vec<dynamic::FieldType>, DbErr>
467where
468 Model: ModelTrait,
469{
470 Ok(match (left, right) {
471 (Identity::Unary(a), Identity::Unary(aa)) => {
472 let col_a =
473 <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(
474 &a.inner(),
475 )
476 .map_err(|_| DbErr::Type(format!("Failed at mapping '{a}'")))?;
477 vec![dynamic::FieldType::new(
478 aa.clone(),
479 Model::get_value_type(col_a),
480 )]
481 }
482 (Identity::Binary(a, b), Identity::Binary(aa, bb)) => {
483 let col_a =
484 <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(
485 &a.inner(),
486 )
487 .map_err(|_| DbErr::Type(format!("Failed at mapping '{a}'")))?;
488 let col_b =
489 <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(
490 &b.inner(),
491 )
492 .map_err(|_| DbErr::Type(format!("Failed at mapping '{b}'")))?;
493 vec![
494 dynamic::FieldType::new(aa.clone(), Model::get_value_type(col_a)),
495 dynamic::FieldType::new(bb.clone(), Model::get_value_type(col_b)),
496 ]
497 }
498 (Identity::Ternary(a, b, c), Identity::Ternary(aa, bb, cc)) => {
499 let col_a =
500 <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(
501 &a.inner(),
502 )
503 .map_err(|_| DbErr::Type(format!("Failed at mapping '{a}'")))?;
504 let col_b =
505 <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(
506 &b.inner(),
507 )
508 .map_err(|_| DbErr::Type(format!("Failed at mapping '{b}'")))?;
509 let col_c =
510 <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(
511 &c.inner(),
512 )
513 .map_err(|_| DbErr::Type(format!("Failed at mapping '{c}'")))?;
514 vec![
515 dynamic::FieldType::new(aa.clone(), Model::get_value_type(col_a)),
516 dynamic::FieldType::new(bb.clone(), Model::get_value_type(col_b)),
517 dynamic::FieldType::new(cc.clone(), Model::get_value_type(col_c)),
518 ]
519 }
520 (Identity::Many(left), Identity::Many(right)) => {
521 let mut vec = Vec::new();
522 for (a, aa) in left.iter().zip(right) {
523 let col_a =
524 <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(
525 &a.inner(),
526 )
527 .map_err(|_| DbErr::Type(format!("Failed at mapping '{a}'")))?;
528 vec.push(dynamic::FieldType::new(
529 aa.clone(),
530 Model::get_value_type(col_a),
531 ));
532 }
533 vec
534 }
535 _ => {
536 return Err(DbErr::Type(format!(
537 "Identity mismatch: {left:?} != {right:?}"
538 )));
539 }
540 })
541}
542
543#[allow(clippy::unwrap_used)]
544fn dyn_model_to_key(dyn_model: dynamic::Model) -> Result<ValueTuple, DbErr> {
545 Ok(match dyn_model.fields.len() {
546 0 => return Err(DbErr::Type("Identity zero?".into())),
547 1 => ValueTuple::One(dyn_model.fields.into_iter().next().unwrap().value),
548 2 => {
549 let mut iter = dyn_model.fields.into_iter();
550 ValueTuple::Two(iter.next().unwrap().value, iter.next().unwrap().value)
551 }
552 3 => {
553 let mut iter = dyn_model.fields.into_iter();
554 ValueTuple::Three(
555 iter.next().unwrap().value,
556 iter.next().unwrap().value,
557 iter.next().unwrap().value,
558 )
559 }
560 _ => ValueTuple::Many(dyn_model.fields.into_iter().map(|v| v.value).collect()),
561 })
562}
563
564fn prepare_condition(table: &TableRef, col: &Identity, keys: &[ValueTuple]) -> Condition {
565 let keys = if !keys.is_empty() {
566 let set: HashSet<_> = keys.iter().cloned().collect();
567 set.into_iter().collect()
568 } else {
569 Vec::new()
570 };
571
572 match col {
573 Identity::Unary(column_a) => {
574 let column_a = table_column(table, column_a);
575 Condition::all().add(Expr::col(column_a).is_in(keys.into_iter().flatten()))
576 }
577 Identity::Binary(column_a, column_b) => Condition::all().add(
578 Expr::tuple([
579 SimpleExpr::Column(table_column(table, column_a)),
580 SimpleExpr::Column(table_column(table, column_b)),
581 ])
582 .in_tuples(keys),
583 ),
584 Identity::Ternary(column_a, column_b, column_c) => Condition::all().add(
585 Expr::tuple([
586 SimpleExpr::Column(table_column(table, column_a)),
587 SimpleExpr::Column(table_column(table, column_b)),
588 SimpleExpr::Column(table_column(table, column_c)),
589 ])
590 .in_tuples(keys),
591 ),
592 Identity::Many(cols) => {
593 let columns = cols
594 .iter()
595 .map(|col| SimpleExpr::Column(table_column(table, col)));
596 Condition::all().add(Expr::tuple(columns).in_tuples(keys))
597 }
598 }
599}
600
601fn table_column(tbl: &TableRef, col: &DynIden) -> ColumnRef {
602 (tbl.sea_orm_table().to_owned(), col.clone()).into_column_ref()
603}
604
605#[cfg(test)]
606mod tests {
607 fn cake_model(id: i32) -> sea_orm::tests_cfg::cake::Model {
608 let name = match id {
609 1 => "apple cake",
610 2 => "orange cake",
611 3 => "fruit cake",
612 4 => "chocolate cake",
613 _ => "",
614 }
615 .to_string();
616 sea_orm::tests_cfg::cake::Model { id, name }
617 }
618
619 fn fruit_model(id: i32, cake_id: Option<i32>) -> sea_orm::tests_cfg::fruit::Model {
620 let name = match id {
621 1 => "apple",
622 2 => "orange",
623 3 => "grape",
624 4 => "strawberry",
625 _ => "",
626 }
627 .to_string();
628 sea_orm::tests_cfg::fruit::Model { id, name, cake_id }
629 }
630
631 fn filling_model(id: i32) -> sea_orm::tests_cfg::filling::Model {
632 let name = match id {
633 1 => "apple juice",
634 2 => "orange jam",
635 3 => "chocolate crust",
636 4 => "strawberry jam",
637 _ => "",
638 }
639 .to_string();
640 sea_orm::tests_cfg::filling::Model {
641 id,
642 name,
643 vendor_id: Some(1),
644 ignored_attr: 0,
645 }
646 }
647
648 fn cake_filling_model(
649 cake_id: i32,
650 filling_id: i32,
651 ) -> sea_orm::tests_cfg::cake_filling::Model {
652 sea_orm::tests_cfg::cake_filling::Model {
653 cake_id,
654 filling_id,
655 }
656 }
657
658 #[tokio::test]
659 async fn test_load_one() {
660 use sea_orm::{DbBackend, LoaderTrait, MockDatabase, entity::prelude::*, tests_cfg::*};
661
662 let db = MockDatabase::new(DbBackend::Postgres)
663 .append_query_results([[cake_model(1), cake_model(2)]])
664 .into_connection();
665
666 let fruits = vec![fruit_model(1, Some(1))];
667
668 let cakes = fruits
669 .load_one(cake::Entity::find(), &db)
670 .await
671 .expect("Should return something");
672
673 assert_eq!(cakes, [Some(cake_model(1))]);
674 }
675
676 #[tokio::test]
677 async fn test_load_one_same_cake() {
678 use sea_orm::{DbBackend, LoaderTrait, MockDatabase, entity::prelude::*, tests_cfg::*};
679
680 let db = MockDatabase::new(DbBackend::Postgres)
681 .append_query_results([[cake_model(1), cake_model(2)]])
682 .into_connection();
683
684 let fruits = vec![fruit_model(1, Some(1)), fruit_model(2, Some(1))];
685
686 let cakes = fruits
687 .load_one(cake::Entity::find(), &db)
688 .await
689 .expect("Should return something");
690
691 assert_eq!(cakes, [Some(cake_model(1)), Some(cake_model(1))]);
692 }
693
694 #[tokio::test]
695 async fn test_load_one_empty() {
696 use sea_orm::{DbBackend, LoaderTrait, MockDatabase, entity::prelude::*, tests_cfg::*};
697
698 let db = MockDatabase::new(DbBackend::Postgres)
699 .append_query_results([[cake_model(1), cake_model(2)]])
700 .into_connection();
701
702 let fruits: Vec<fruit::Model> = vec![];
703
704 let cakes = fruits
705 .load_one(cake::Entity::find(), &db)
706 .await
707 .expect("Should return something");
708
709 assert_eq!(cakes, []);
710 }
711
712 #[tokio::test]
713 async fn test_load_many() {
714 use sea_orm::{DbBackend, LoaderTrait, MockDatabase, entity::prelude::*, tests_cfg::*};
715
716 let db = MockDatabase::new(DbBackend::Postgres)
717 .append_query_results([[fruit_model(1, Some(1))]])
718 .into_connection();
719
720 let cakes = vec![cake_model(1), cake_model(2)];
721
722 let fruits = cakes
723 .load_many(fruit::Entity::find(), &db)
724 .await
725 .expect("Should return something");
726
727 assert_eq!(fruits, [vec![fruit_model(1, Some(1))], vec![]]);
728 }
729
730 #[tokio::test]
731 async fn test_load_many_same_fruit() {
732 use sea_orm::{DbBackend, LoaderTrait, MockDatabase, entity::prelude::*, tests_cfg::*};
733
734 let db = MockDatabase::new(DbBackend::Postgres)
735 .append_query_results([[fruit_model(1, Some(1)), fruit_model(2, Some(1))]])
736 .into_connection();
737
738 let cakes = vec![cake_model(1), cake_model(2)];
739
740 let fruits = cakes
741 .load_many(fruit::Entity::find(), &db)
742 .await
743 .expect("Should return something");
744
745 assert_eq!(
746 fruits,
747 [
748 vec![fruit_model(1, Some(1)), fruit_model(2, Some(1))],
749 vec![]
750 ]
751 );
752 }
753
754 #[tokio::test]
755 async fn test_load_many_empty() {
756 use sea_orm::{DbBackend, MockDatabase, entity::prelude::*, tests_cfg::*};
757
758 let db = MockDatabase::new(DbBackend::Postgres).into_connection();
759
760 let cakes: Vec<cake::Model> = vec![];
761
762 let fruits = cakes
763 .load_many(fruit::Entity::find(), &db)
764 .await
765 .expect("Should return something");
766
767 let empty_vec: Vec<Vec<fruit::Model>> = vec![];
768
769 assert_eq!(fruits, empty_vec);
770 }
771
772 #[tokio::test]
773 async fn test_load_many_to_many_base() {
774 use sea_orm::{DbBackend, IntoMockRow, LoaderTrait, MockDatabase, tests_cfg::*};
775
776 let db = MockDatabase::new(DbBackend::Postgres)
777 .append_query_results([
778 [cake_filling_model(1, 1).into_mock_row()],
779 [filling_model(1).into_mock_row()],
780 ])
781 .into_connection();
782
783 let cakes = vec![cake_model(1)];
784
785 let fillings = cakes
786 .load_many_to_many(Filling, CakeFilling, &db)
787 .await
788 .expect("Should return something");
789
790 assert_eq!(fillings, vec![vec![filling_model(1)]]);
791 }
792
793 #[tokio::test]
794 async fn test_load_many_to_many_complex() {
795 use sea_orm::{DbBackend, IntoMockRow, LoaderTrait, MockDatabase, tests_cfg::*};
796
797 let db = MockDatabase::new(DbBackend::Postgres)
798 .append_query_results([
799 [
800 cake_filling_model(1, 1).into_mock_row(),
801 cake_filling_model(1, 2).into_mock_row(),
802 cake_filling_model(1, 3).into_mock_row(),
803 cake_filling_model(2, 1).into_mock_row(),
804 cake_filling_model(2, 2).into_mock_row(),
805 ],
806 [
807 filling_model(1).into_mock_row(),
808 filling_model(2).into_mock_row(),
809 filling_model(3).into_mock_row(),
810 filling_model(4).into_mock_row(),
811 filling_model(5).into_mock_row(),
812 ],
813 ])
814 .into_connection();
815
816 let cakes = vec![cake_model(1), cake_model(2), cake_model(3)];
817
818 let fillings = cakes
819 .load_many_to_many(Filling, CakeFilling, &db)
820 .await
821 .expect("Should return something");
822
823 assert_eq!(
824 fillings,
825 vec![
826 vec![filling_model(1), filling_model(2), filling_model(3)],
827 vec![filling_model(1), filling_model(2)],
828 vec![],
829 ]
830 );
831 }
832
833 #[tokio::test]
834 async fn test_load_many_to_many_empty() {
835 use sea_orm::{DbBackend, IntoMockRow, LoaderTrait, MockDatabase, tests_cfg::*};
836
837 let db = MockDatabase::new(DbBackend::Postgres)
838 .append_query_results([
839 [cake_filling_model(1, 1).into_mock_row()],
840 [filling_model(1).into_mock_row()],
841 ])
842 .into_connection();
843
844 let cakes: Vec<cake::Model> = vec![];
845
846 let fillings = cakes
847 .load_many_to_many(Filling, CakeFilling, &db)
848 .await
849 .expect("Should return something");
850
851 let empty_vec: Vec<Vec<filling::Model>> = vec![];
852
853 assert_eq!(fillings, empty_vec);
854 }
855
856 #[tokio::test]
857 async fn test_load_one_duplicate_keys() {
858 use sea_orm::{DbBackend, LoaderTrait, MockDatabase, entity::prelude::*, tests_cfg::*};
859
860 let db = MockDatabase::new(DbBackend::Postgres)
861 .append_query_results([[cake_model(1), cake_model(2)]])
862 .into_connection();
863
864 let fruits = vec![
865 fruit_model(1, Some(1)),
866 fruit_model(2, Some(1)),
867 fruit_model(3, Some(1)),
868 fruit_model(4, Some(1)),
869 ];
870
871 let cakes = fruits
872 .load_one(cake::Entity::find(), &db)
873 .await
874 .expect("Should return something");
875
876 assert_eq!(cakes.len(), 4);
877 for cake in &cakes {
878 assert_eq!(cake, &Some(cake_model(1)));
879 }
880 let logs = db.into_transaction_log();
881 let sql = format!("{:?}", logs[0]);
882
883 let values_count = sql.matches("$1").count();
884 assert_eq!(values_count, 1, "Duplicate values were not removed");
885 }
886
887 #[tokio::test]
888 async fn test_load_many_duplicate_keys() {
889 use sea_orm::{DbBackend, LoaderTrait, MockDatabase, entity::prelude::*, tests_cfg::*};
890
891 let db = MockDatabase::new(DbBackend::Postgres)
892 .append_query_results([[
893 fruit_model(1, Some(1)),
894 fruit_model(2, Some(1)),
895 fruit_model(3, Some(2)),
896 ]])
897 .into_connection();
898
899 let cakes = vec![cake_model(1), cake_model(1), cake_model(2), cake_model(2)];
900
901 let fruits = cakes
902 .load_many(fruit::Entity::find(), &db)
903 .await
904 .expect("Should return something");
905
906 assert_eq!(fruits.len(), 4);
907
908 let logs = db.into_transaction_log();
909 let sql = format!("{:?}", logs[0]);
910
911 let values_count = sql.matches("$1").count() + sql.matches("$2").count();
912 assert_eq!(values_count, 2, "Duplicate values were not removed");
913 }
914}