sea_orm/query/
loader.rs

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
14/// Entity, or a Select<Entity>; to be used as parameters in [`LoaderTrait`]
15pub trait EntityOrSelect<E: EntityTrait>: Send {
16    /// If self is Entity, use Entity::find()
17    fn select(self) -> Select<E>;
18}
19
20/// This trait implements the Data Loader API
21#[async_trait]
22pub trait LoaderTrait {
23    /// Source model
24    type Model: ModelTrait;
25
26    /// Used to eager load has_one relations
27    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    /// Used to eager load has_many relations
36    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    /// Used to eager load many_to_many relations
45    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        // we verify that is HasOne relation
143        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            // The idea is to do a SelectTwo with join, then extract key via a dynamic model
214            // i.e. select (baker + cake_baker) and extract cake_id from result rows
215            // SELECT "baker"."id", "baker"."name", "baker"."contact_details", "baker"."bakery_id",
216            //     "cakes_bakers"."cake_id" <- extra select
217            // FROM "baker" <- target
218            // INNER JOIN "cakes_bakers" <- junction
219            //     ON "cakes_bakers"."baker_id" = "baker"."id" <- relation
220            // WHERE "cakes_bakers"."cake_id" IN (..)
221
222            let data = stmt
223                .select_also_dyn_model(
224                    via_def.to_tbl.sea_orm_table().clone(),
225                    dynamic::ModelType {
226                        // we uses the left Model's type but the right Model's field
227                        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            // Map of M::PK -> Vec<R::PK>
339            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            // Map of R::PK -> R::Model
363            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}