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