sea_orm/executor/
select.rs

1use crate::{
2    error::*, ConnectionTrait, DbBackend, EntityTrait, FromQueryResult, IdenStatic, Iterable,
3    ModelTrait, PartialModelTrait, PrimaryKeyArity, PrimaryKeyToColumn, PrimaryKeyTrait,
4    QueryResult, QuerySelect, Select, SelectA, SelectB, SelectTwo, SelectTwoMany, Statement,
5    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/// Defines a type to do `SELECT` operations through a [SelectStatement] on a Model
16#[derive(Clone, Debug)]
17pub struct Selector<S>
18where
19    S: SelectorTrait,
20{
21    pub(crate) query: SelectStatement,
22    selector: S,
23}
24
25/// Performs a raw `SELECT` operation on a model
26#[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
36/// A Trait for any type that can perform SELECT queries
37pub trait SelectorTrait {
38    #[allow(missing_docs)]
39    type Item: Sized;
40
41    /// The method to perform a query on a Model
42    fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr>;
43}
44
45/// Get tuple from query result based on a list of column identifiers
46#[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/// Get tuple from query result based on column index
57#[derive(Debug)]
58pub struct SelectGetableTuple<T>
59where
60    T: TryGetableMany,
61{
62    model: PhantomData<T>,
63}
64
65/// Defines a type to get a Model
66#[derive(Debug)]
67pub struct SelectModel<M>
68where
69    M: FromQueryResult,
70{
71    model: PhantomData<M>,
72}
73
74/// Defines a type to get two Models
75#[derive(Clone, Debug)]
76pub struct SelectTwoModel<M, N>
77where
78    M: FromQueryResult,
79    N: FromQueryResult,
80{
81    model: PhantomData<(M, N)>,
82}
83
84impl<T, C> SelectorTrait for SelectGetableValue<T, C>
85where
86    T: TryGetableMany,
87    C: strum::IntoEnumIterator + sea_query::Iden,
88{
89    type Item = T;
90
91    fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
92        let cols: Vec<String> = C::iter().map(|col| col.to_string()).collect();
93        T::try_get_many(&res, "", &cols).map_err(Into::into)
94    }
95}
96
97impl<T> SelectorTrait for SelectGetableTuple<T>
98where
99    T: TryGetableMany,
100{
101    type Item = T;
102
103    fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
104        T::try_get_many_by_index(&res).map_err(Into::into)
105    }
106}
107
108impl<M> SelectorTrait for SelectModel<M>
109where
110    M: FromQueryResult + Sized,
111{
112    type Item = M;
113
114    fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
115        M::from_query_result(&res, "")
116    }
117}
118
119impl<M, N> SelectorTrait for SelectTwoModel<M, N>
120where
121    M: FromQueryResult + Sized,
122    N: FromQueryResult + Sized,
123{
124    type Item = (M, Option<N>);
125
126    fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
127        Ok((
128            M::from_query_result(&res, SelectA.as_str())?,
129            N::from_query_result_optional(&res, SelectB.as_str())?,
130        ))
131    }
132}
133
134impl<E> Select<E>
135where
136    E: EntityTrait,
137{
138    /// Perform a Select operation on a Model using a [Statement]
139    #[allow(clippy::wrong_self_convention)]
140    pub fn from_raw_sql(self, stmt: Statement) -> SelectorRaw<SelectModel<E::Model>> {
141        SelectorRaw {
142            stmt,
143            selector: SelectModel { model: PhantomData },
144        }
145    }
146
147    /// Return a [Selector] from `Self` that wraps a [SelectModel]
148    pub fn into_model<M>(self) -> Selector<SelectModel<M>>
149    where
150        M: FromQueryResult,
151    {
152        Selector {
153            query: self.query,
154            selector: SelectModel { model: PhantomData },
155        }
156    }
157
158    /// Return a [Selector] from `Self` that wraps a [SelectModel] with a [PartialModel](PartialModelTrait)
159    ///
160    /// ```
161    /// # #[cfg(feature = "macros")]
162    /// # {
163    /// use sea_orm::{
164    ///     entity::*,
165    ///     query::*,
166    ///     tests_cfg::cake::{self, Entity as Cake},
167    ///     DbBackend, DerivePartialModel, FromQueryResult,
168    /// };
169    /// use sea_query::{Expr, Func, SimpleExpr};
170    ///
171    /// #[derive(DerivePartialModel, FromQueryResult)]
172    /// #[sea_orm(entity = "Cake")]
173    /// struct PartialCake {
174    ///     name: String,
175    ///     #[sea_orm(
176    ///         from_expr = r#"SimpleExpr::FunctionCall(Func::upper(Expr::col((Cake, cake::Column::Name))))"#
177    ///     )]
178    ///     name_upper: String,
179    /// }
180    ///
181    /// assert_eq!(
182    ///     cake::Entity::find()
183    ///         .into_partial_model::<PartialCake>()
184    ///         .into_statement(DbBackend::Sqlite)
185    ///         .to_string(),
186    ///     r#"SELECT "cake"."name", UPPER("cake"."name") AS "name_upper" FROM "cake""#
187    /// );
188    /// # }
189    /// ```
190    pub fn into_partial_model<M>(self) -> Selector<SelectModel<M>>
191    where
192        M: PartialModelTrait,
193    {
194        M::select_cols(QuerySelect::select_only(self)).into_model::<M>()
195    }
196
197    /// Get a selectable Model as a [JsonValue] for SQL JSON operations
198    #[cfg(feature = "with-json")]
199    pub fn into_json(self) -> Selector<SelectModel<JsonValue>> {
200        Selector {
201            query: self.query,
202            selector: SelectModel { model: PhantomData },
203        }
204    }
205
206    /// ```
207    /// # use sea_orm::{error::*, tests_cfg::*, *};
208    /// #
209    /// # #[smol_potat::main]
210    /// # #[cfg(all(feature = "mock", feature = "macros"))]
211    /// # pub async fn main() -> Result<(), DbErr> {
212    /// #
213    /// # let db = MockDatabase::new(DbBackend::Postgres)
214    /// #     .append_query_results([[
215    /// #         maplit::btreemap! {
216    /// #             "cake_name" => Into::<Value>::into("Chocolate Forest"),
217    /// #         },
218    /// #         maplit::btreemap! {
219    /// #             "cake_name" => Into::<Value>::into("New York Cheese"),
220    /// #         },
221    /// #     ]])
222    /// #     .into_connection();
223    /// #
224    /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DeriveColumn, EnumIter};
225    ///
226    /// #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
227    /// enum QueryAs {
228    ///     CakeName,
229    /// }
230    ///
231    /// let res: Vec<String> = cake::Entity::find()
232    ///     .select_only()
233    ///     .column_as(cake::Column::Name, QueryAs::CakeName)
234    ///     .into_values::<_, QueryAs>()
235    ///     .all(&db)
236    ///     .await?;
237    ///
238    /// assert_eq!(
239    ///     res,
240    ///     ["Chocolate Forest".to_owned(), "New York Cheese".to_owned()]
241    /// );
242    ///
243    /// assert_eq!(
244    ///     db.into_transaction_log(),
245    ///     [Transaction::from_sql_and_values(
246    ///         DbBackend::Postgres,
247    ///         r#"SELECT "cake"."name" AS "cake_name" FROM "cake""#,
248    ///         []
249    ///     )]
250    /// );
251    /// #
252    /// # Ok(())
253    /// # }
254    /// ```
255    ///
256    /// ```
257    /// # use sea_orm::{error::*, tests_cfg::*, *};
258    /// #
259    /// # #[smol_potat::main]
260    /// # #[cfg(all(feature = "mock", feature = "macros"))]
261    /// # pub async fn main() -> Result<(), DbErr> {
262    /// #
263    /// # let db = MockDatabase::new(DbBackend::Postgres)
264    /// #     .append_query_results([[
265    /// #         maplit::btreemap! {
266    /// #             "cake_name" => Into::<Value>::into("Chocolate Forest"),
267    /// #             "num_of_cakes" => Into::<Value>::into(2i64),
268    /// #         },
269    /// #     ]])
270    /// #     .into_connection();
271    /// #
272    /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DeriveColumn, EnumIter};
273    ///
274    /// #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
275    /// enum QueryAs {
276    ///     CakeName,
277    ///     NumOfCakes,
278    /// }
279    ///
280    /// let res: Vec<(String, i64)> = cake::Entity::find()
281    ///     .select_only()
282    ///     .column_as(cake::Column::Name, QueryAs::CakeName)
283    ///     .column_as(cake::Column::Id.count(), QueryAs::NumOfCakes)
284    ///     .group_by(cake::Column::Name)
285    ///     .into_values::<_, QueryAs>()
286    ///     .all(&db)
287    ///     .await?;
288    ///
289    /// assert_eq!(res, [("Chocolate Forest".to_owned(), 2i64)]);
290    ///
291    /// assert_eq!(
292    ///     db.into_transaction_log(),
293    ///     [Transaction::from_sql_and_values(
294    ///         DbBackend::Postgres,
295    ///         [
296    ///             r#"SELECT "cake"."name" AS "cake_name", COUNT("cake"."id") AS "num_of_cakes""#,
297    ///             r#"FROM "cake" GROUP BY "cake"."name""#,
298    ///         ]
299    ///         .join(" ")
300    ///         .as_str(),
301    ///         []
302    ///     )]
303    /// );
304    /// #
305    /// # Ok(())
306    /// # }
307    /// ```
308    pub fn into_values<T, C>(self) -> Selector<SelectGetableValue<T, C>>
309    where
310        T: TryGetableMany,
311        C: strum::IntoEnumIterator + sea_query::Iden,
312    {
313        Selector::<SelectGetableValue<T, C>>::with_columns(self.query)
314    }
315
316    /// ```
317    /// # use sea_orm::{error::*, tests_cfg::*, *};
318    /// #
319    /// # #[smol_potat::main]
320    /// # #[cfg(all(feature = "mock", feature = "macros"))]
321    /// # pub async fn main() -> Result<(), DbErr> {
322    /// #
323    /// # let db = MockDatabase::new(DbBackend::Postgres)
324    /// #     .append_query_results(vec![vec![
325    /// #         maplit::btreemap! {
326    /// #             "cake_name" => Into::<Value>::into("Chocolate Forest"),
327    /// #         },
328    /// #         maplit::btreemap! {
329    /// #             "cake_name" => Into::<Value>::into("New York Cheese"),
330    /// #         },
331    /// #     ]])
332    /// #     .into_connection();
333    /// #
334    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
335    ///
336    /// let res: Vec<String> = cake::Entity::find()
337    ///     .select_only()
338    ///     .column(cake::Column::Name)
339    ///     .into_tuple()
340    ///     .all(&db)
341    ///     .await?;
342    ///
343    /// assert_eq!(
344    ///     res,
345    ///     vec!["Chocolate Forest".to_owned(), "New York Cheese".to_owned()]
346    /// );
347    ///
348    /// assert_eq!(
349    ///     db.into_transaction_log(),
350    ///     vec![Transaction::from_sql_and_values(
351    ///         DbBackend::Postgres,
352    ///         r#"SELECT "cake"."name" FROM "cake""#,
353    ///         vec![]
354    ///     )]
355    /// );
356    /// #
357    /// # Ok(())
358    /// # }
359    /// ```
360    ///
361    /// ```
362    /// # use sea_orm::{error::*, tests_cfg::*, *};
363    /// #
364    /// # #[smol_potat::main]
365    /// # #[cfg(all(feature = "mock", feature = "macros"))]
366    /// # pub async fn main() -> Result<(), DbErr> {
367    /// #
368    /// # let db = MockDatabase::new(DbBackend::Postgres)
369    /// #     .append_query_results(vec![vec![
370    /// #         maplit::btreemap! {
371    /// #             "cake_name" => Into::<Value>::into("Chocolate Forest"),
372    /// #             "num_of_cakes" => Into::<Value>::into(2i64),
373    /// #         },
374    /// #     ]])
375    /// #     .into_connection();
376    /// #
377    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
378    ///
379    /// let res: Vec<(String, i64)> = cake::Entity::find()
380    ///     .select_only()
381    ///     .column(cake::Column::Name)
382    ///     .column(cake::Column::Id)
383    ///     .group_by(cake::Column::Name)
384    ///     .into_tuple()
385    ///     .all(&db)
386    ///     .await?;
387    ///
388    /// assert_eq!(res, vec![("Chocolate Forest".to_owned(), 2i64)]);
389    ///
390    /// assert_eq!(
391    ///     db.into_transaction_log(),
392    ///     vec![Transaction::from_sql_and_values(
393    ///         DbBackend::Postgres,
394    ///         vec![
395    ///             r#"SELECT "cake"."name", "cake"."id""#,
396    ///             r#"FROM "cake" GROUP BY "cake"."name""#,
397    ///         ]
398    ///         .join(" ")
399    ///         .as_str(),
400    ///         vec![]
401    ///     )]
402    /// );
403    /// #
404    /// # Ok(())
405    /// # }
406    /// ```
407    pub fn into_tuple<T>(self) -> Selector<SelectGetableTuple<T>>
408    where
409        T: TryGetableMany,
410    {
411        Selector::<SelectGetableTuple<T>>::into_tuple(self.query)
412    }
413
414    /// Get one Model from the SELECT query
415    pub async fn one<C>(self, db: &C) -> Result<Option<E::Model>, DbErr>
416    where
417        C: ConnectionTrait,
418    {
419        self.into_model().one(db).await
420    }
421
422    /// Get all Models from the SELECT query
423    pub async fn all<C>(self, db: &C) -> Result<Vec<E::Model>, DbErr>
424    where
425        C: ConnectionTrait,
426    {
427        self.into_model().all(db).await
428    }
429
430    /// Stream the results of a SELECT operation on a Model
431    pub async fn stream<'a: 'b, 'b, C>(
432        self,
433        db: &'a C,
434    ) -> Result<impl Stream<Item = Result<E::Model, DbErr>> + 'b + Send, DbErr>
435    where
436        C: ConnectionTrait + StreamTrait + Send,
437    {
438        self.into_model().stream(db).await
439    }
440
441    /// Stream the result of the operation with PartialModel
442    pub async fn stream_partial_model<'a: 'b, 'b, C, M>(
443        self,
444        db: &'a C,
445    ) -> Result<impl Stream<Item = Result<M, DbErr>> + 'b + Send, DbErr>
446    where
447        C: ConnectionTrait + StreamTrait + Send,
448        M: PartialModelTrait + Send + 'b,
449    {
450        self.into_partial_model().stream(db).await
451    }
452}
453
454impl<E, F> SelectTwo<E, F>
455where
456    E: EntityTrait,
457    F: EntityTrait,
458{
459    /// Perform a conversion into a [SelectTwoModel]
460    pub fn into_model<M, N>(self) -> Selector<SelectTwoModel<M, N>>
461    where
462        M: FromQueryResult,
463        N: FromQueryResult,
464    {
465        Selector {
466            query: self.query,
467            selector: SelectTwoModel { model: PhantomData },
468        }
469    }
470
471    /// Perform a conversion into a [SelectTwoModel] with [PartialModel](PartialModelTrait)
472    pub fn into_partial_model<M, N>(self) -> Selector<SelectTwoModel<M, N>>
473    where
474        M: PartialModelTrait,
475        N: PartialModelTrait,
476    {
477        let select = QuerySelect::select_only(self);
478        let select = M::select_cols(select);
479        let select = N::select_cols(select);
480        select.into_model::<M, N>()
481    }
482
483    /// Convert the Models into JsonValue
484    #[cfg(feature = "with-json")]
485    pub fn into_json(self) -> Selector<SelectTwoModel<JsonValue, JsonValue>> {
486        Selector {
487            query: self.query,
488            selector: SelectTwoModel { model: PhantomData },
489        }
490    }
491
492    /// Get one Model from the Select query
493    pub async fn one<C>(self, db: &C) -> Result<Option<(E::Model, Option<F::Model>)>, DbErr>
494    where
495        C: ConnectionTrait,
496    {
497        self.into_model().one(db).await
498    }
499
500    /// Get all Models from the Select query
501    pub async fn all<C>(self, db: &C) -> Result<Vec<(E::Model, Option<F::Model>)>, DbErr>
502    where
503        C: ConnectionTrait,
504    {
505        self.into_model().all(db).await
506    }
507
508    /// Stream the results of a Select operation on a Model
509    pub async fn stream<'a: 'b, 'b, C>(
510        self,
511        db: &'a C,
512    ) -> Result<impl Stream<Item = Result<(E::Model, Option<F::Model>), DbErr>> + 'b, DbErr>
513    where
514        C: ConnectionTrait + StreamTrait + Send,
515    {
516        self.into_model().stream(db).await
517    }
518
519    /// Stream the result of the operation with PartialModel
520    pub async fn stream_partial_model<'a: 'b, 'b, C, M, N>(
521        self,
522        db: &'a C,
523    ) -> Result<impl Stream<Item = Result<(M, Option<N>), DbErr>> + 'b + Send, DbErr>
524    where
525        C: ConnectionTrait + StreamTrait + Send,
526        M: PartialModelTrait + Send + 'b,
527        N: PartialModelTrait + Send + 'b,
528    {
529        self.into_partial_model().stream(db).await
530    }
531}
532
533impl<E, F> SelectTwoMany<E, F>
534where
535    E: EntityTrait,
536    F: EntityTrait,
537{
538    /// Performs a conversion to [Selector]
539    fn into_model<M, N>(self) -> Selector<SelectTwoModel<M, N>>
540    where
541        M: FromQueryResult,
542        N: FromQueryResult,
543    {
544        Selector {
545            query: self.query,
546            selector: SelectTwoModel { model: PhantomData },
547        }
548    }
549
550    /// Performs a conversion to [Selector] with partial model
551    fn into_partial_model<M, N>(self) -> Selector<SelectTwoModel<M, N>>
552    where
553        M: PartialModelTrait,
554        N: PartialModelTrait,
555    {
556        let select = self.select_only();
557        let select = M::select_cols(select);
558        let select = N::select_cols(select);
559        select.into_model()
560    }
561
562    /// Convert the results to JSON
563    #[cfg(feature = "with-json")]
564    pub fn into_json(self) -> Selector<SelectTwoModel<JsonValue, JsonValue>> {
565        Selector {
566            query: self.query,
567            selector: SelectTwoModel { model: PhantomData },
568        }
569    }
570
571    /// Stream the result of the operation
572    pub async fn stream<'a: 'b, 'b, C>(
573        self,
574        db: &'a C,
575    ) -> Result<impl Stream<Item = Result<(E::Model, Option<F::Model>), DbErr>> + 'b + Send, DbErr>
576    where
577        C: ConnectionTrait + StreamTrait + Send,
578    {
579        self.into_model().stream(db).await
580    }
581
582    /// Stream the result of the operation with PartialModel
583    pub async fn stream_partial_model<'a: 'b, 'b, C, M, N>(
584        self,
585        db: &'a C,
586    ) -> Result<impl Stream<Item = Result<(M, Option<N>), DbErr>> + 'b + Send, DbErr>
587    where
588        C: ConnectionTrait + StreamTrait + Send,
589        M: PartialModelTrait + Send + 'b,
590        N: PartialModelTrait + Send + 'b,
591    {
592        self.into_partial_model().stream(db).await
593    }
594
595    /// Get all Models from the select operation
596    ///
597    /// > `SelectTwoMany::one()` method has been dropped (#486)
598    /// >
599    /// > You can get `(Entity, Vec<relatedEntity>)` by first querying a single model from Entity,
600    /// > then use [`ModelTrait::find_related`] on the model.
601    /// >
602    /// > See https://www.sea-ql.org/SeaORM/docs/basic-crud/select#lazy-loading for details.
603    pub async fn all<C>(self, db: &C) -> Result<Vec<(E::Model, Vec<F::Model>)>, DbErr>
604    where
605        C: ConnectionTrait,
606    {
607        let rows = self.into_model().all(db).await?;
608        Ok(consolidate_query_result::<E, F>(rows))
609    }
610
611    // pub fn paginate()
612    // we could not implement paginate easily, if the number of children for a
613    // parent is larger than one page, then we will end up splitting it in two pages
614    // so the correct way is actually perform query in two stages
615    // paginate the parent model and then populate the children
616
617    // pub fn count()
618    // we should only count the number of items of the parent model
619}
620
621impl<S> Selector<S>
622where
623    S: SelectorTrait,
624{
625    /// Create `Selector` from Statement and columns. Executing this `Selector`
626    /// will return a type `T` which implement `TryGetableMany`.
627    pub fn with_columns<T, C>(query: SelectStatement) -> Selector<SelectGetableValue<T, C>>
628    where
629        T: TryGetableMany,
630        C: strum::IntoEnumIterator + sea_query::Iden,
631    {
632        Selector {
633            query,
634            selector: SelectGetableValue {
635                columns: PhantomData,
636                model: PhantomData,
637            },
638        }
639    }
640
641    /// Get tuple from query result based on column index
642    pub fn into_tuple<T>(query: SelectStatement) -> Selector<SelectGetableTuple<T>>
643    where
644        T: TryGetableMany,
645    {
646        Selector {
647            query,
648            selector: SelectGetableTuple { model: PhantomData },
649        }
650    }
651
652    fn into_selector_raw<C>(self, db: &C) -> SelectorRaw<S>
653    where
654        C: ConnectionTrait,
655    {
656        let builder = db.get_database_backend();
657        let stmt = builder.build(&self.query);
658        SelectorRaw {
659            stmt,
660            selector: self.selector,
661        }
662    }
663
664    /// Get the SQL statement
665    pub fn into_statement(self, builder: DbBackend) -> Statement {
666        builder.build(&self.query)
667    }
668
669    /// Get an item from the Select query
670    pub async fn one<C>(mut self, db: &C) -> Result<Option<S::Item>, DbErr>
671    where
672        C: ConnectionTrait,
673    {
674        self.query.limit(1);
675        self.into_selector_raw(db).one(db).await
676    }
677
678    /// Get all items from the Select query
679    pub async fn all<C>(self, db: &C) -> Result<Vec<S::Item>, DbErr>
680    where
681        C: ConnectionTrait,
682    {
683        self.into_selector_raw(db).all(db).await
684    }
685
686    /// Stream the results of the Select operation
687    pub async fn stream<'a: 'b, 'b, C>(
688        self,
689        db: &'a C,
690    ) -> Result<Pin<Box<dyn Stream<Item = Result<S::Item, DbErr>> + 'b + Send>>, DbErr>
691    where
692        C: ConnectionTrait + StreamTrait + Send,
693        S: 'b,
694        S::Item: Send,
695    {
696        self.into_selector_raw(db).stream(db).await
697    }
698}
699
700impl<S> SelectorRaw<S>
701where
702    S: SelectorTrait,
703{
704    /// Select a custom Model from a raw SQL [Statement].
705    pub fn from_statement<M>(stmt: Statement) -> SelectorRaw<SelectModel<M>>
706    where
707        M: FromQueryResult,
708    {
709        SelectorRaw {
710            stmt,
711            selector: SelectModel { model: PhantomData },
712        }
713    }
714
715    /// Create `SelectorRaw` from Statement and columns. Executing this `SelectorRaw` will
716    /// return a type `T` which implement `TryGetableMany`.
717    pub fn with_columns<T, C>(stmt: Statement) -> SelectorRaw<SelectGetableValue<T, C>>
718    where
719        T: TryGetableMany,
720        C: strum::IntoEnumIterator + sea_query::Iden,
721    {
722        SelectorRaw {
723            stmt,
724            selector: SelectGetableValue {
725                columns: PhantomData,
726                model: PhantomData,
727            },
728        }
729    }
730
731    /// ```
732    /// # use sea_orm::{error::*, tests_cfg::*, *};
733    /// #
734    /// # #[smol_potat::main]
735    /// # #[cfg(feature = "mock")]
736    /// # pub async fn main() -> Result<(), DbErr> {
737    /// #
738    /// # let db = MockDatabase::new(DbBackend::Postgres)
739    /// #     .append_query_results([[
740    /// #         maplit::btreemap! {
741    /// #             "name" => Into::<Value>::into("Chocolate Forest"),
742    /// #             "num_of_cakes" => Into::<Value>::into(1),
743    /// #         },
744    /// #         maplit::btreemap! {
745    /// #             "name" => Into::<Value>::into("New York Cheese"),
746    /// #             "num_of_cakes" => Into::<Value>::into(1),
747    /// #         },
748    /// #     ]])
749    /// #     .into_connection();
750    /// #
751    /// use sea_orm::{entity::*, query::*, tests_cfg::cake, FromQueryResult};
752    ///
753    /// #[derive(Debug, PartialEq, FromQueryResult)]
754    /// struct SelectResult {
755    ///     name: String,
756    ///     num_of_cakes: i32,
757    /// }
758    ///
759    /// let res: Vec<SelectResult> = cake::Entity::find()
760    ///     .from_raw_sql(Statement::from_sql_and_values(
761    ///         DbBackend::Postgres,
762    ///         r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
763    ///         [],
764    ///     ))
765    ///     .into_model::<SelectResult>()
766    ///     .all(&db)
767    ///     .await?;
768    ///
769    /// assert_eq!(
770    ///     res,
771    ///     [
772    ///         SelectResult {
773    ///             name: "Chocolate Forest".to_owned(),
774    ///             num_of_cakes: 1,
775    ///         },
776    ///         SelectResult {
777    ///             name: "New York Cheese".to_owned(),
778    ///             num_of_cakes: 1,
779    ///         },
780    ///     ]
781    /// );
782    ///
783    /// assert_eq!(
784    ///     db.into_transaction_log(),
785    ///     [Transaction::from_sql_and_values(
786    ///         DbBackend::Postgres,
787    ///         r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
788    ///         []
789    ///     ),]
790    /// );
791    /// #
792    /// # Ok(())
793    /// # }
794    /// ```
795    pub fn into_model<M>(self) -> SelectorRaw<SelectModel<M>>
796    where
797        M: FromQueryResult,
798    {
799        SelectorRaw {
800            stmt: self.stmt,
801            selector: SelectModel { model: PhantomData },
802        }
803    }
804
805    /// ```
806    /// # use sea_orm::{error::*, tests_cfg::*, *};
807    /// #
808    /// # #[smol_potat::main]
809    /// # #[cfg(feature = "mock")]
810    /// # pub async fn main() -> Result<(), DbErr> {
811    /// #
812    /// # let db = MockDatabase::new(DbBackend::Postgres)
813    /// #     .append_query_results([[
814    /// #         maplit::btreemap! {
815    /// #             "name" => Into::<Value>::into("Chocolate Forest"),
816    /// #             "num_of_cakes" => Into::<Value>::into(1),
817    /// #         },
818    /// #         maplit::btreemap! {
819    /// #             "name" => Into::<Value>::into("New York Cheese"),
820    /// #             "num_of_cakes" => Into::<Value>::into(1),
821    /// #         },
822    /// #     ]])
823    /// #     .into_connection();
824    /// #
825    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
826    ///
827    /// let res: Vec<serde_json::Value> = cake::Entity::find().from_raw_sql(
828    ///     Statement::from_sql_and_values(
829    ///         DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, []
830    ///     )
831    /// )
832    /// .into_json()
833    /// .all(&db)
834    /// .await?;
835    ///
836    /// assert_eq!(
837    ///     res,
838    ///     [
839    ///         serde_json::json!({
840    ///             "name": "Chocolate Forest",
841    ///             "num_of_cakes": 1,
842    ///         }),
843    ///         serde_json::json!({
844    ///             "name": "New York Cheese",
845    ///             "num_of_cakes": 1,
846    ///         }),
847    ///     ]
848    /// );
849    ///
850    /// assert_eq!(
851    ///     db.into_transaction_log(),
852    ///     [
853    ///     Transaction::from_sql_and_values(
854    ///             DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, []
855    ///     ),
856    /// ]);
857    /// #
858    /// # Ok(())
859    /// # }
860    /// ```
861    #[cfg(feature = "with-json")]
862    pub fn into_json(self) -> SelectorRaw<SelectModel<JsonValue>> {
863        SelectorRaw {
864            stmt: self.stmt,
865            selector: SelectModel { model: PhantomData },
866        }
867    }
868
869    /// Get the SQL statement
870    pub fn into_statement(self) -> Statement {
871        self.stmt
872    }
873
874    /// Get an item from the Select query
875    /// ```
876    /// # use sea_orm::{error::*, tests_cfg::*, *};
877    /// #
878    /// # #[smol_potat::main]
879    /// # #[cfg(feature = "mock")]
880    /// # pub async fn main() -> Result<(), DbErr> {
881    /// #
882    /// # let db = MockDatabase::new(DbBackend::Postgres)
883    /// #     .append_query_results([
884    /// #         [cake::Model {
885    /// #             id: 1,
886    /// #             name: "Cake".to_owned(),
887    /// #         }],
888    /// #     ])
889    /// #     .into_connection();
890    /// #
891    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
892    ///
893    /// let _: Option<cake::Model> = cake::Entity::find()
894    ///     .from_raw_sql(Statement::from_sql_and_values(
895    ///         DbBackend::Postgres,
896    ///         r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "id" = $1"#,
897    ///         [1.into()],
898    ///     ))
899    ///     .one(&db)
900    ///     .await?;
901    ///
902    /// assert_eq!(
903    ///     db.into_transaction_log(),
904    ///     [Transaction::from_sql_and_values(
905    ///         DbBackend::Postgres,
906    ///         r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "id" = $1"#,
907    ///         [1.into()]
908    ///     ),]
909    /// );
910    /// #
911    /// # Ok(())
912    /// # }
913    /// ```
914    pub async fn one<C>(self, db: &C) -> Result<Option<S::Item>, DbErr>
915    where
916        C: ConnectionTrait,
917    {
918        let row = db.query_one(self.stmt).await?;
919        match row {
920            Some(row) => Ok(Some(S::from_raw_query_result(row)?)),
921            None => Ok(None),
922        }
923    }
924
925    /// Get all items from the Select query
926    /// ```
927    /// # use sea_orm::{error::*, tests_cfg::*, *};
928    /// #
929    /// # #[smol_potat::main]
930    /// # #[cfg(feature = "mock")]
931    /// # pub async fn main() -> Result<(), DbErr> {
932    /// #
933    /// # let db = MockDatabase::new(DbBackend::Postgres)
934    /// #     .append_query_results([
935    /// #         [cake::Model {
936    /// #             id: 1,
937    /// #             name: "Cake".to_owned(),
938    /// #         }],
939    /// #     ])
940    /// #     .into_connection();
941    /// #
942    /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
943    ///
944    /// let _: Vec<cake::Model> = cake::Entity::find()
945    ///     .from_raw_sql(Statement::from_sql_and_values(
946    ///         DbBackend::Postgres,
947    ///         r#"SELECT "cake"."id", "cake"."name" FROM "cake""#,
948    ///         [],
949    ///     ))
950    ///     .all(&db)
951    ///     .await?;
952    ///
953    /// assert_eq!(
954    ///     db.into_transaction_log(),
955    ///     [Transaction::from_sql_and_values(
956    ///         DbBackend::Postgres,
957    ///         r#"SELECT "cake"."id", "cake"."name" FROM "cake""#,
958    ///         []
959    ///     ),]
960    /// );
961    /// #
962    /// # Ok(())
963    /// # }
964    /// ```
965    pub async fn all<C>(self, db: &C) -> Result<Vec<S::Item>, DbErr>
966    where
967        C: ConnectionTrait,
968    {
969        let rows = db.query_all(self.stmt).await?;
970        let mut models = Vec::new();
971        for row in rows.into_iter() {
972            models.push(S::from_raw_query_result(row)?);
973        }
974        Ok(models)
975    }
976
977    /// Stream the results of the Select operation
978    pub async fn stream<'a: 'b, 'b, C>(
979        self,
980        db: &'a C,
981    ) -> Result<Pin<Box<dyn Stream<Item = Result<S::Item, DbErr>> + 'b + Send>>, DbErr>
982    where
983        C: ConnectionTrait + StreamTrait + Send,
984        S: 'b,
985        S::Item: Send,
986    {
987        let stream = db.stream(self.stmt).await?;
988        Ok(Box::pin(stream.and_then(|row| {
989            futures_util::future::ready(S::from_raw_query_result(row))
990        })))
991    }
992}
993
994#[allow(clippy::unwrap_used)]
995fn consolidate_query_result<L, R>(
996    rows: Vec<(L::Model, Option<R::Model>)>,
997) -> Vec<(L::Model, Vec<R::Model>)>
998where
999    L: EntityTrait,
1000    R: EntityTrait,
1001{
1002    match <<L::PrimaryKey as PrimaryKeyTrait>::ValueType as PrimaryKeyArity>::ARITY {
1003        1 => {
1004            let col = <L::PrimaryKey as Iterable>::iter()
1005                .next()
1006                .unwrap()
1007                .into_column();
1008            consolidate_query_result_of::<L, R, UnitPk<L>>(rows, UnitPk(col))
1009        }
1010        2 => {
1011            let mut iter = <L::PrimaryKey as Iterable>::iter();
1012            let col1 = iter.next().unwrap().into_column();
1013            let col2 = iter.next().unwrap().into_column();
1014            consolidate_query_result_of::<L, R, PairPk<L>>(rows, PairPk(col1, col2))
1015        }
1016        _ => {
1017            let cols: Vec<_> = <L::PrimaryKey as Iterable>::iter()
1018                .map(|pk| pk.into_column())
1019                .collect();
1020            consolidate_query_result_of::<L, R, TuplePk<L>>(rows, TuplePk(cols))
1021        }
1022    }
1023}
1024
1025trait ModelKey<E: EntityTrait> {
1026    type Type: Hash + PartialEq + Eq;
1027    fn get(&self, model: &E::Model) -> Self::Type;
1028}
1029
1030// This could have been an array of [E::Column; <E::PrimaryKey as PrimaryKeyTrait>::ARITY], but it still doesn't compile
1031struct UnitPk<E: EntityTrait>(E::Column);
1032struct PairPk<E: EntityTrait>(E::Column, E::Column);
1033struct TuplePk<E: EntityTrait>(Vec<E::Column>);
1034
1035impl<E: EntityTrait> ModelKey<E> for UnitPk<E> {
1036    type Type = Value;
1037    fn get(&self, model: &E::Model) -> Self::Type {
1038        model.get(self.0)
1039    }
1040}
1041
1042impl<E: EntityTrait> ModelKey<E> for PairPk<E> {
1043    type Type = (Value, Value);
1044    fn get(&self, model: &E::Model) -> Self::Type {
1045        (model.get(self.0), model.get(self.1))
1046    }
1047}
1048
1049impl<E: EntityTrait> ModelKey<E> for TuplePk<E> {
1050    type Type = Vec<Value>;
1051    fn get(&self, model: &E::Model) -> Self::Type {
1052        let mut key = Vec::new();
1053        for col in self.0.iter() {
1054            key.push(model.get(*col));
1055        }
1056        key
1057    }
1058}
1059
1060fn consolidate_query_result_of<L, R, KEY: ModelKey<L>>(
1061    mut rows: Vec<(L::Model, Option<R::Model>)>,
1062    model_key: KEY,
1063) -> Vec<(L::Model, Vec<R::Model>)>
1064where
1065    L: EntityTrait,
1066    R: EntityTrait,
1067{
1068    let mut hashmap: HashMap<KEY::Type, Vec<R::Model>> =
1069        rows.iter_mut().fold(HashMap::new(), |mut acc, row| {
1070            let key = model_key.get(&row.0);
1071            if let Some(value) = row.1.take() {
1072                let vec: Option<&mut Vec<R::Model>> = acc.get_mut(&key);
1073                if let Some(vec) = vec {
1074                    vec.push(value)
1075                } else {
1076                    acc.insert(key, vec![value]);
1077                }
1078            } else {
1079                acc.entry(key).or_default();
1080            }
1081
1082            acc
1083        });
1084
1085    rows.into_iter()
1086        .filter_map(|(l_model, _)| {
1087            let l_pk = model_key.get(&l_model);
1088            let r_models = hashmap.remove(&l_pk);
1089            r_models.map(|r_models| (l_model, r_models))
1090        })
1091        .collect()
1092}
1093
1094/// This is the legacy consolidate algorithm. Kept for reference
1095#[allow(dead_code)]
1096fn consolidate_query_result_of_ordered_rows<L, R>(
1097    rows: Vec<(L::Model, Option<R::Model>)>,
1098) -> Vec<(L::Model, Vec<R::Model>)>
1099where
1100    L: EntityTrait,
1101    R: EntityTrait,
1102{
1103    let mut acc: Vec<(L::Model, Vec<R::Model>)> = Vec::new();
1104    for (l, r) in rows {
1105        if let Some((last_l, last_r)) = acc.last_mut() {
1106            let mut same_l = true;
1107            for pk_col in <L::PrimaryKey as Iterable>::iter() {
1108                let col = pk_col.into_column();
1109                let val = l.get(col);
1110                let last_val = last_l.get(col);
1111                if !val.eq(&last_val) {
1112                    same_l = false;
1113                    break;
1114                }
1115            }
1116            if same_l {
1117                if let Some(r) = r {
1118                    last_r.push(r);
1119                    continue;
1120                }
1121            }
1122        }
1123        let rows = match r {
1124            Some(r) => vec![r],
1125            None => vec![],
1126        };
1127        acc.push((l, rows));
1128    }
1129    acc
1130}
1131
1132#[cfg(test)]
1133mod tests {
1134    use pretty_assertions::assert_eq;
1135
1136    fn cake_fruit_model(
1137        cake_id: i32,
1138        fruit_id: i32,
1139    ) -> (
1140        sea_orm::tests_cfg::cake::Model,
1141        sea_orm::tests_cfg::fruit::Model,
1142    ) {
1143        (cake_model(cake_id), fruit_model(fruit_id, Some(cake_id)))
1144    }
1145
1146    fn cake_model(id: i32) -> sea_orm::tests_cfg::cake::Model {
1147        let name = match id {
1148            1 => "apple cake",
1149            2 => "orange cake",
1150            3 => "fruit cake",
1151            4 => "chocolate cake",
1152            _ => "",
1153        }
1154        .to_string();
1155        sea_orm::tests_cfg::cake::Model { id, name }
1156    }
1157
1158    fn filling_model(id: i32) -> sea_orm::tests_cfg::filling::Model {
1159        let name = match id {
1160            1 => "apple juice",
1161            2 => "orange jam",
1162            3 => "fruit",
1163            4 => "chocolate crust",
1164            _ => "",
1165        }
1166        .to_string();
1167        sea_orm::tests_cfg::filling::Model {
1168            id,
1169            name,
1170            vendor_id: Some(1),
1171            ignored_attr: 0,
1172        }
1173    }
1174
1175    fn cake_filling_models(
1176        cake_id: i32,
1177        filling_id: i32,
1178    ) -> (
1179        sea_orm::tests_cfg::cake::Model,
1180        sea_orm::tests_cfg::filling::Model,
1181    ) {
1182        (cake_model(cake_id), filling_model(filling_id))
1183    }
1184
1185    fn fruit_model(id: i32, cake_id: Option<i32>) -> sea_orm::tests_cfg::fruit::Model {
1186        let name = match id {
1187            1 => "apple",
1188            2 => "orange",
1189            3 => "grape",
1190            4 => "strawberry",
1191            _ => "",
1192        }
1193        .to_string();
1194        sea_orm::tests_cfg::fruit::Model { id, name, cake_id }
1195    }
1196
1197    fn cake_vendor_link(
1198        cake_id: i32,
1199        vendor_id: i32,
1200    ) -> (
1201        sea_orm::tests_cfg::cake::Model,
1202        sea_orm::tests_cfg::vendor::Model,
1203    ) {
1204        (cake_model(cake_id), vendor_model(vendor_id))
1205    }
1206
1207    fn vendor_model(id: i32) -> sea_orm::tests_cfg::vendor::Model {
1208        let name = match id {
1209            1 => "Apollo",
1210            2 => "Benny",
1211            3 => "Christine",
1212            4 => "David",
1213            _ => "",
1214        }
1215        .to_string();
1216        sea_orm::tests_cfg::vendor::Model { id, name }
1217    }
1218
1219    #[smol_potat::test]
1220    pub async fn also_related() -> Result<(), sea_orm::DbErr> {
1221        use sea_orm::tests_cfg::*;
1222        use sea_orm::{DbBackend, EntityTrait, MockDatabase, Statement, Transaction};
1223
1224        let db = MockDatabase::new(DbBackend::Postgres)
1225            .append_query_results([[cake_fruit_model(1, 1)]])
1226            .into_connection();
1227
1228        assert_eq!(
1229            Cake::find().find_also_related(Fruit).all(&db).await?,
1230            [(cake_model(1), Some(fruit_model(1, Some(1))))]
1231        );
1232
1233        assert_eq!(
1234            db.into_transaction_log(),
1235            [Transaction::many([Statement::from_sql_and_values(
1236                DbBackend::Postgres,
1237                [
1238                    r#"SELECT "cake"."id" AS "A_id", "cake"."name" AS "A_name","#,
1239                    r#""fruit"."id" AS "B_id", "fruit"."name" AS "B_name", "fruit"."cake_id" AS "B_cake_id""#,
1240                    r#"FROM "cake""#,
1241                    r#"LEFT JOIN "fruit" ON "cake"."id" = "fruit"."cake_id""#,
1242                ]
1243                .join(" ")
1244                .as_str(),
1245                []
1246            ),])]
1247        );
1248
1249        Ok(())
1250    }
1251
1252    #[smol_potat::test]
1253    pub async fn also_related_2() -> Result<(), sea_orm::DbErr> {
1254        use sea_orm::tests_cfg::*;
1255        use sea_orm::{DbBackend, EntityTrait, MockDatabase};
1256
1257        let db = MockDatabase::new(DbBackend::Postgres)
1258            .append_query_results([[cake_fruit_model(1, 1), cake_fruit_model(1, 2)]])
1259            .into_connection();
1260
1261        assert_eq!(
1262            Cake::find().find_also_related(Fruit).all(&db).await?,
1263            [
1264                (cake_model(1), Some(fruit_model(1, Some(1)))),
1265                (cake_model(1), Some(fruit_model(2, Some(1))))
1266            ]
1267        );
1268
1269        Ok(())
1270    }
1271
1272    #[smol_potat::test]
1273    pub async fn also_related_3() -> Result<(), sea_orm::DbErr> {
1274        use sea_orm::tests_cfg::*;
1275        use sea_orm::{DbBackend, EntityTrait, MockDatabase};
1276
1277        let db = MockDatabase::new(DbBackend::Postgres)
1278            .append_query_results([[
1279                cake_fruit_model(1, 1),
1280                cake_fruit_model(1, 2),
1281                cake_fruit_model(2, 3),
1282            ]])
1283            .into_connection();
1284
1285        assert_eq!(
1286            Cake::find().find_also_related(Fruit).all(&db).await?,
1287            [
1288                (cake_model(1), Some(fruit_model(1, Some(1)))),
1289                (cake_model(1), Some(fruit_model(2, Some(1)))),
1290                (cake_model(2), Some(fruit_model(3, Some(2))))
1291            ]
1292        );
1293
1294        Ok(())
1295    }
1296
1297    #[smol_potat::test]
1298    pub async fn also_related_4() -> Result<(), sea_orm::DbErr> {
1299        use sea_orm::tests_cfg::*;
1300        use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1301
1302        let db = MockDatabase::new(DbBackend::Postgres)
1303            .append_query_results([[
1304                cake_fruit_model(1, 1).into_mock_row(),
1305                cake_fruit_model(1, 2).into_mock_row(),
1306                cake_fruit_model(2, 3).into_mock_row(),
1307                (cake_model(3), None::<fruit::Model>).into_mock_row(),
1308            ]])
1309            .into_connection();
1310
1311        assert_eq!(
1312            Cake::find().find_also_related(Fruit).all(&db).await?,
1313            [
1314                (cake_model(1), Some(fruit_model(1, Some(1)))),
1315                (cake_model(1), Some(fruit_model(2, Some(1)))),
1316                (cake_model(2), Some(fruit_model(3, Some(2)))),
1317                (cake_model(3), None)
1318            ]
1319        );
1320
1321        Ok(())
1322    }
1323
1324    #[smol_potat::test]
1325    pub async fn also_related_many_to_many() -> Result<(), sea_orm::DbErr> {
1326        use sea_orm::tests_cfg::*;
1327        use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1328
1329        let db = MockDatabase::new(DbBackend::Postgres)
1330            .append_query_results([[
1331                cake_filling_models(1, 1).into_mock_row(),
1332                cake_filling_models(1, 2).into_mock_row(),
1333                cake_filling_models(2, 2).into_mock_row(),
1334            ]])
1335            .into_connection();
1336
1337        assert_eq!(
1338            Cake::find().find_also_related(Filling).all(&db).await?,
1339            [
1340                (cake_model(1), Some(filling_model(1))),
1341                (cake_model(1), Some(filling_model(2))),
1342                (cake_model(2), Some(filling_model(2))),
1343            ]
1344        );
1345
1346        Ok(())
1347    }
1348
1349    #[smol_potat::test]
1350    pub async fn also_related_many_to_many_2() -> Result<(), sea_orm::DbErr> {
1351        use sea_orm::tests_cfg::*;
1352        use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1353
1354        let db = MockDatabase::new(DbBackend::Postgres)
1355            .append_query_results([[
1356                cake_filling_models(1, 1).into_mock_row(),
1357                cake_filling_models(1, 2).into_mock_row(),
1358                cake_filling_models(2, 2).into_mock_row(),
1359                (cake_model(3), None::<filling::Model>).into_mock_row(),
1360            ]])
1361            .into_connection();
1362
1363        assert_eq!(
1364            Cake::find().find_also_related(Filling).all(&db).await?,
1365            [
1366                (cake_model(1), Some(filling_model(1))),
1367                (cake_model(1), Some(filling_model(2))),
1368                (cake_model(2), Some(filling_model(2))),
1369                (cake_model(3), None)
1370            ]
1371        );
1372
1373        Ok(())
1374    }
1375
1376    #[smol_potat::test]
1377    pub async fn with_related() -> Result<(), sea_orm::DbErr> {
1378        use sea_orm::tests_cfg::*;
1379        use sea_orm::{DbBackend, EntityTrait, MockDatabase, Statement, Transaction};
1380
1381        let db = MockDatabase::new(DbBackend::Postgres)
1382            .append_query_results([[
1383                cake_fruit_model(1, 1),
1384                cake_fruit_model(2, 2),
1385                cake_fruit_model(2, 3),
1386            ]])
1387            .into_connection();
1388
1389        assert_eq!(
1390            Cake::find().find_with_related(Fruit).all(&db).await?,
1391            [
1392                (cake_model(1), vec![fruit_model(1, Some(1))]),
1393                (
1394                    cake_model(2),
1395                    vec![fruit_model(2, Some(2)), fruit_model(3, Some(2))]
1396                )
1397            ]
1398        );
1399
1400        assert_eq!(
1401            db.into_transaction_log(),
1402            [Transaction::many([Statement::from_sql_and_values(
1403                DbBackend::Postgres,
1404                [
1405                    r#"SELECT "cake"."id" AS "A_id", "cake"."name" AS "A_name","#,
1406                    r#""fruit"."id" AS "B_id", "fruit"."name" AS "B_name", "fruit"."cake_id" AS "B_cake_id""#,
1407                    r#"FROM "cake""#,
1408                    r#"LEFT JOIN "fruit" ON "cake"."id" = "fruit"."cake_id""#,
1409                    r#"ORDER BY "cake"."id" ASC"#
1410                ]
1411                .join(" ")
1412                .as_str(),
1413                []
1414            ),])]
1415        );
1416
1417        Ok(())
1418    }
1419
1420    #[smol_potat::test]
1421    pub async fn with_related_2() -> Result<(), sea_orm::DbErr> {
1422        use sea_orm::tests_cfg::*;
1423        use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1424
1425        let db = MockDatabase::new(DbBackend::Postgres)
1426            .append_query_results([[
1427                cake_fruit_model(1, 1).into_mock_row(),
1428                cake_fruit_model(2, 2).into_mock_row(),
1429                cake_fruit_model(2, 3).into_mock_row(),
1430                cake_fruit_model(2, 4).into_mock_row(),
1431            ]])
1432            .into_connection();
1433
1434        assert_eq!(
1435            Cake::find().find_with_related(Fruit).all(&db).await?,
1436            [
1437                (cake_model(1), vec![fruit_model(1, Some(1)),]),
1438                (
1439                    cake_model(2),
1440                    vec![
1441                        fruit_model(2, Some(2)),
1442                        fruit_model(3, Some(2)),
1443                        fruit_model(4, Some(2)),
1444                    ]
1445                ),
1446            ]
1447        );
1448
1449        Ok(())
1450    }
1451
1452    #[smol_potat::test]
1453    pub async fn with_related_empty() -> Result<(), sea_orm::DbErr> {
1454        use sea_orm::tests_cfg::*;
1455        use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1456
1457        let db = MockDatabase::new(DbBackend::Postgres)
1458            .append_query_results([[
1459                cake_fruit_model(1, 1).into_mock_row(),
1460                cake_fruit_model(2, 2).into_mock_row(),
1461                cake_fruit_model(2, 3).into_mock_row(),
1462                cake_fruit_model(2, 4).into_mock_row(),
1463                (cake_model(3), None::<fruit::Model>).into_mock_row(),
1464            ]])
1465            .into_connection();
1466
1467        assert_eq!(
1468            Cake::find().find_with_related(Fruit).all(&db).await?,
1469            [
1470                (cake_model(1), vec![fruit_model(1, Some(1)),]),
1471                (
1472                    cake_model(2),
1473                    vec![
1474                        fruit_model(2, Some(2)),
1475                        fruit_model(3, Some(2)),
1476                        fruit_model(4, Some(2)),
1477                    ]
1478                ),
1479                (cake_model(3), vec![])
1480            ]
1481        );
1482
1483        Ok(())
1484    }
1485
1486    #[smol_potat::test]
1487    pub async fn with_related_many_to_many() -> Result<(), sea_orm::DbErr> {
1488        use sea_orm::tests_cfg::*;
1489        use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1490
1491        let db = MockDatabase::new(DbBackend::Postgres)
1492            .append_query_results([[
1493                cake_filling_models(1, 1).into_mock_row(),
1494                cake_filling_models(1, 2).into_mock_row(),
1495                cake_filling_models(2, 2).into_mock_row(),
1496            ]])
1497            .into_connection();
1498
1499        assert_eq!(
1500            Cake::find().find_with_related(Filling).all(&db).await?,
1501            [
1502                (cake_model(1), vec![filling_model(1), filling_model(2)]),
1503                (cake_model(2), vec![filling_model(2)]),
1504            ]
1505        );
1506
1507        Ok(())
1508    }
1509
1510    #[smol_potat::test]
1511    pub async fn with_related_many_to_many_2() -> Result<(), sea_orm::DbErr> {
1512        use sea_orm::tests_cfg::*;
1513        use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1514
1515        let db = MockDatabase::new(DbBackend::Postgres)
1516            .append_query_results([[
1517                cake_filling_models(1, 1).into_mock_row(),
1518                cake_filling_models(1, 2).into_mock_row(),
1519                cake_filling_models(2, 2).into_mock_row(),
1520                (cake_model(3), None::<filling::Model>).into_mock_row(),
1521            ]])
1522            .into_connection();
1523
1524        assert_eq!(
1525            Cake::find().find_with_related(Filling).all(&db).await?,
1526            [
1527                (cake_model(1), vec![filling_model(1), filling_model(2)]),
1528                (cake_model(2), vec![filling_model(2)]),
1529                (cake_model(3), vec![])
1530            ]
1531        );
1532
1533        Ok(())
1534    }
1535
1536    #[smol_potat::test]
1537    pub async fn also_linked_base() -> Result<(), sea_orm::DbErr> {
1538        use sea_orm::tests_cfg::*;
1539        use sea_orm::{DbBackend, EntityTrait, MockDatabase, Statement, Transaction};
1540
1541        let db = MockDatabase::new(DbBackend::Postgres)
1542            .append_query_results([[cake_vendor_link(1, 1)]])
1543            .into_connection();
1544
1545        assert_eq!(
1546            Cake::find()
1547                .find_also_linked(entity_linked::CakeToFillingVendor)
1548                .all(&db)
1549                .await?,
1550            [(cake_model(1), Some(vendor_model(1)))]
1551        );
1552
1553        assert_eq!(
1554            db.into_transaction_log(),
1555            [Transaction::many([Statement::from_sql_and_values(
1556                DbBackend::Postgres,
1557                [
1558                    r#"SELECT "cake"."id" AS "A_id", "cake"."name" AS "A_name","#,
1559                    r#""r2"."id" AS "B_id", "r2"."name" AS "B_name""#,
1560                    r#"FROM "cake""#,
1561                    r#"LEFT JOIN "cake_filling" AS "r0" ON "cake"."id" = "r0"."cake_id""#,
1562                    r#"LEFT JOIN "filling" AS "r1" ON "r0"."filling_id" = "r1"."id""#,
1563                    r#"LEFT JOIN "vendor" AS "r2" ON "r1"."vendor_id" = "r2"."id""#,
1564                ]
1565                .join(" ")
1566                .as_str(),
1567                []
1568            ),])]
1569        );
1570
1571        Ok(())
1572    }
1573
1574    #[smol_potat::test]
1575    pub async fn also_linked_same_cake() -> Result<(), sea_orm::DbErr> {
1576        use sea_orm::tests_cfg::*;
1577        use sea_orm::{DbBackend, EntityTrait, MockDatabase};
1578
1579        let db = MockDatabase::new(DbBackend::Postgres)
1580            .append_query_results([[
1581                cake_vendor_link(1, 1),
1582                cake_vendor_link(1, 2),
1583                cake_vendor_link(2, 3),
1584            ]])
1585            .into_connection();
1586
1587        assert_eq!(
1588            Cake::find()
1589                .find_also_linked(entity_linked::CakeToFillingVendor)
1590                .all(&db)
1591                .await?,
1592            [
1593                (cake_model(1), Some(vendor_model(1))),
1594                (cake_model(1), Some(vendor_model(2))),
1595                (cake_model(2), Some(vendor_model(3)))
1596            ]
1597        );
1598
1599        Ok(())
1600    }
1601
1602    #[smol_potat::test]
1603    pub async fn also_linked_same_vendor() -> Result<(), sea_orm::DbErr> {
1604        use sea_orm::tests_cfg::*;
1605        use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1606
1607        let db = MockDatabase::new(DbBackend::Postgres)
1608            .append_query_results([[
1609                cake_vendor_link(1, 1).into_mock_row(),
1610                cake_vendor_link(2, 1).into_mock_row(),
1611                cake_vendor_link(3, 2).into_mock_row(),
1612            ]])
1613            .into_connection();
1614
1615        assert_eq!(
1616            Cake::find()
1617                .find_also_linked(entity_linked::CakeToFillingVendor)
1618                .all(&db)
1619                .await?,
1620            [
1621                (cake_model(1), Some(vendor_model(1))),
1622                (cake_model(2), Some(vendor_model(1))),
1623                (cake_model(3), Some(vendor_model(2))),
1624            ]
1625        );
1626
1627        Ok(())
1628    }
1629
1630    #[smol_potat::test]
1631    pub async fn also_linked_many_to_many() -> 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_vendor_link(1, 1).into_mock_row(),
1638                cake_vendor_link(1, 2).into_mock_row(),
1639                cake_vendor_link(1, 3).into_mock_row(),
1640                cake_vendor_link(2, 1).into_mock_row(),
1641                cake_vendor_link(2, 2).into_mock_row(),
1642            ]])
1643            .into_connection();
1644
1645        assert_eq!(
1646            Cake::find()
1647                .find_also_linked(entity_linked::CakeToFillingVendor)
1648                .all(&db)
1649                .await?,
1650            [
1651                (cake_model(1), Some(vendor_model(1))),
1652                (cake_model(1), Some(vendor_model(2))),
1653                (cake_model(1), Some(vendor_model(3))),
1654                (cake_model(2), Some(vendor_model(1))),
1655                (cake_model(2), Some(vendor_model(2))),
1656            ]
1657        );
1658
1659        Ok(())
1660    }
1661
1662    #[smol_potat::test]
1663    pub async fn also_linked_empty() -> Result<(), sea_orm::DbErr> {
1664        use sea_orm::tests_cfg::*;
1665        use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1666
1667        let db = MockDatabase::new(DbBackend::Postgres)
1668            .append_query_results([[
1669                cake_vendor_link(1, 1).into_mock_row(),
1670                cake_vendor_link(2, 2).into_mock_row(),
1671                cake_vendor_link(3, 3).into_mock_row(),
1672                (cake_model(4), None::<vendor::Model>).into_mock_row(),
1673            ]])
1674            .into_connection();
1675
1676        assert_eq!(
1677            Cake::find()
1678                .find_also_linked(entity_linked::CakeToFillingVendor)
1679                .all(&db)
1680                .await?,
1681            [
1682                (cake_model(1), Some(vendor_model(1))),
1683                (cake_model(2), Some(vendor_model(2))),
1684                (cake_model(3), Some(vendor_model(3))),
1685                (cake_model(4), None)
1686            ]
1687        );
1688
1689        Ok(())
1690    }
1691
1692    #[smol_potat::test]
1693    pub async fn with_linked_base() -> Result<(), sea_orm::DbErr> {
1694        use sea_orm::tests_cfg::*;
1695        use sea_orm::{DbBackend, EntityTrait, MockDatabase, Statement, Transaction};
1696
1697        let db = MockDatabase::new(DbBackend::Postgres)
1698            .append_query_results([[
1699                cake_vendor_link(1, 1),
1700                cake_vendor_link(2, 2),
1701                cake_vendor_link(2, 3),
1702            ]])
1703            .into_connection();
1704
1705        assert_eq!(
1706            Cake::find()
1707                .find_with_linked(entity_linked::CakeToFillingVendor)
1708                .all(&db)
1709                .await?,
1710            [
1711                (cake_model(1), vec![vendor_model(1)]),
1712                (cake_model(2), vec![vendor_model(2), vendor_model(3)])
1713            ]
1714        );
1715
1716        assert_eq!(
1717            db.into_transaction_log(),
1718            [Transaction::many([Statement::from_sql_and_values(
1719                DbBackend::Postgres,
1720                [
1721                    r#"SELECT "cake"."id" AS "A_id", "cake"."name" AS "A_name","#,
1722                    r#""r2"."id" AS "B_id", "r2"."name" AS "B_name" FROM "cake""#,
1723                    r#"LEFT JOIN "cake_filling" AS "r0" ON "cake"."id" = "r0"."cake_id""#,
1724                    r#"LEFT JOIN "filling" AS "r1" ON "r0"."filling_id" = "r1"."id""#,
1725                    r#"LEFT JOIN "vendor" AS "r2" ON "r1"."vendor_id" = "r2"."id""#,
1726                ]
1727                .join(" ")
1728                .as_str(),
1729                []
1730            ),])]
1731        );
1732
1733        Ok(())
1734    }
1735
1736    #[smol_potat::test]
1737    pub async fn with_linked_same_vendor() -> Result<(), sea_orm::DbErr> {
1738        use sea_orm::tests_cfg::*;
1739        use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1740
1741        let db = MockDatabase::new(DbBackend::Postgres)
1742            .append_query_results([[
1743                cake_vendor_link(1, 1).into_mock_row(),
1744                cake_vendor_link(2, 2).into_mock_row(),
1745                cake_vendor_link(3, 2).into_mock_row(),
1746            ]])
1747            .into_connection();
1748
1749        assert_eq!(
1750            Cake::find()
1751                .find_with_linked(entity_linked::CakeToFillingVendor)
1752                .all(&db)
1753                .await?,
1754            [
1755                (cake_model(1), vec![vendor_model(1)]),
1756                (cake_model(2), vec![vendor_model(2)]),
1757                (cake_model(3), vec![vendor_model(2)])
1758            ]
1759        );
1760
1761        Ok(())
1762    }
1763
1764    #[smol_potat::test]
1765    pub async fn with_linked_empty() -> Result<(), sea_orm::DbErr> {
1766        use sea_orm::tests_cfg::*;
1767        use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1768
1769        let db = MockDatabase::new(DbBackend::Postgres)
1770            .append_query_results([[
1771                cake_vendor_link(1, 1).into_mock_row(),
1772                cake_vendor_link(2, 1).into_mock_row(),
1773                cake_vendor_link(2, 2).into_mock_row(),
1774                (cake_model(3), None::<vendor::Model>).into_mock_row(),
1775            ]])
1776            .into_connection();
1777
1778        assert_eq!(
1779            Cake::find()
1780                .find_with_linked(entity_linked::CakeToFillingVendor)
1781                .all(&db)
1782                .await?,
1783            [
1784                (cake_model(1), vec![vendor_model(1)]),
1785                (cake_model(2), vec![vendor_model(1), vendor_model(2)]),
1786                (cake_model(3), vec![])
1787            ]
1788        );
1789
1790        Ok(())
1791    }
1792
1793    // normally would not happen
1794    #[smol_potat::test]
1795    pub async fn with_linked_repeated() -> Result<(), sea_orm::DbErr> {
1796        use sea_orm::tests_cfg::*;
1797        use sea_orm::{DbBackend, EntityTrait, IntoMockRow, MockDatabase};
1798
1799        let db = MockDatabase::new(DbBackend::Postgres)
1800            .append_query_results([[
1801                cake_vendor_link(1, 1).into_mock_row(),
1802                cake_vendor_link(1, 1).into_mock_row(),
1803                cake_vendor_link(2, 1).into_mock_row(),
1804                cake_vendor_link(2, 2).into_mock_row(),
1805            ]])
1806            .into_connection();
1807
1808        assert_eq!(
1809            Cake::find()
1810                .find_with_linked(entity_linked::CakeToFillingVendor)
1811                .all(&db)
1812                .await?,
1813            [
1814                (cake_model(1), vec![vendor_model(1), vendor_model(1)]),
1815                (cake_model(2), vec![vendor_model(1), vendor_model(2)]),
1816            ]
1817        );
1818
1819        Ok(())
1820    }
1821}