sea_orm/executor/select/
three.rs

1use super::*;
2use crate::{
3    JoinType, Paginator, PaginatorTrait, QueryFilter, QueryOrder, QuerySelect, QueryTrait, Related,
4    SelectC, SelectFour, SelectThree, SelectThreeMany, Topology, TopologyChain, TopologyStar,
5    combine::prepare_select_col,
6};
7
8impl<E, F, G, TOP> SelectThree<E, F, G, TOP>
9where
10    E: EntityTrait,
11    F: EntityTrait,
12    G: EntityTrait,
13    TOP: Topology,
14{
15    pub(crate) fn new(query: SelectStatement) -> Self {
16        Self::new_without_prepare(query).prepare_select()
17    }
18
19    pub(crate) fn new_without_prepare(query: SelectStatement) -> Self {
20        Self {
21            query,
22            entity: PhantomData,
23        }
24    }
25
26    fn prepare_select(mut self) -> Self {
27        prepare_select_col::<G, _, _>(&mut self, SelectC);
28        self
29    }
30
31    /// Left Join with a Related Entity and select all Entities.
32    pub fn find_also<T, H>(self, _: T, _: H) -> SelectFour<E, F, G, H, TopologyStar>
33    where
34        H: EntityTrait,
35        T: EntityTrait + Related<H>,
36    {
37        SelectFour::new(
38            self.join_join(JoinType::LeftJoin, T::to(), T::via())
39                .into_query(),
40        )
41    }
42}
43
44macro_rules! impl_query_trait {
45    ( $trait: ident ) => {
46        impl<E, F, G, TOP> $trait for SelectThree<E, F, G, TOP>
47        where
48            E: EntityTrait,
49            F: EntityTrait,
50            G: EntityTrait,
51            TOP: Topology,
52        {
53            type QueryStatement = SelectStatement;
54
55            fn query(&mut self) -> &mut SelectStatement {
56                &mut self.query
57            }
58        }
59    };
60}
61
62impl<E, F, G, TOP> QueryTrait for SelectThree<E, F, G, TOP>
63where
64    E: EntityTrait,
65    F: EntityTrait,
66    G: EntityTrait,
67    TOP: Topology,
68{
69    type QueryStatement = SelectStatement;
70    fn query(&mut self) -> &mut SelectStatement {
71        &mut self.query
72    }
73    fn as_query(&self) -> &SelectStatement {
74        &self.query
75    }
76    fn into_query(self) -> SelectStatement {
77        self.query
78    }
79}
80
81impl_query_trait!(QuerySelect);
82impl_query_trait!(QueryFilter);
83impl_query_trait!(QueryOrder);
84
85impl<M, N, O> SelectorTrait for SelectThreeModel<M, N, O>
86where
87    M: FromQueryResult + Sized,
88    N: FromQueryResult + Sized,
89    O: FromQueryResult + Sized,
90{
91    type Item = (M, Option<N>, Option<O>);
92
93    fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
94        Ok((
95            M::from_query_result(&res, SelectA.as_str())?,
96            N::from_query_result_optional(&res, SelectB.as_str())?,
97            O::from_query_result_optional(&res, SelectC.as_str())?,
98        ))
99    }
100}
101
102impl<E, F, G, TOP> SelectThree<E, F, G, TOP>
103where
104    E: EntityTrait,
105    F: EntityTrait,
106    G: EntityTrait,
107    TOP: Topology,
108{
109    /// Perform a conversion into a [SelectThreeModel]
110    pub fn into_model<M, N, O>(self) -> Selector<SelectThreeModel<M, N, O>>
111    where
112        M: FromQueryResult,
113        N: FromQueryResult,
114        O: FromQueryResult,
115    {
116        Selector {
117            query: self.query,
118            selector: PhantomData,
119        }
120    }
121
122    /// Perform a conversion into a [SelectThreeModel] with [PartialModel](PartialModelTrait)
123    pub fn into_partial_model<M, N, O>(self) -> Selector<SelectThreeModel<M, N, O>>
124    where
125        M: PartialModelTrait,
126        N: PartialModelTrait,
127        O: PartialModelTrait,
128    {
129        let select = QuerySelect::select_only(self);
130        let select = M::select_cols(select);
131        let select = N::select_cols(select);
132        let select = O::select_cols(select);
133        select.into_model::<M, N, O>()
134    }
135
136    /// Convert the Models into JsonValue
137    #[cfg(feature = "with-json")]
138    pub fn into_json(self) -> Selector<SelectThreeModel<JsonValue, JsonValue, JsonValue>> {
139        Selector {
140            query: self.query,
141            selector: PhantomData,
142        }
143    }
144
145    /// Get one Model from the Select query
146    pub fn one<C>(
147        self,
148        db: &C,
149    ) -> Result<Option<(E::Model, Option<F::Model>, Option<G::Model>)>, DbErr>
150    where
151        C: ConnectionTrait,
152    {
153        self.into_model().one(db)
154    }
155
156    /// Get all Models from the Select query
157    pub fn all<C>(
158        self,
159        db: &C,
160    ) -> Result<Vec<(E::Model, Option<F::Model>, Option<G::Model>)>, DbErr>
161    where
162        C: ConnectionTrait,
163    {
164        self.into_model().all(db)
165    }
166
167    /// Stream the results of a Select operation on a Model
168    pub fn stream<'a: 'b, 'b, C>(
169        self,
170        db: &'a C,
171    ) -> Result<
172        impl Iterator<Item = Result<(E::Model, Option<F::Model>, Option<G::Model>), DbErr>> + 'b,
173        DbErr,
174    >
175    where
176        C: ConnectionTrait + StreamTrait,
177    {
178        self.into_model().stream(db)
179    }
180
181    /// Stream the result of the operation with PartialModel
182    pub fn stream_partial_model<'a: 'b, 'b, C, M, N, O>(
183        self,
184        db: &'a C,
185    ) -> Result<impl Iterator<Item = Result<(M, Option<N>, Option<O>), DbErr>> + 'b, DbErr>
186    where
187        C: ConnectionTrait + StreamTrait,
188        M: PartialModelTrait + 'b,
189        N: PartialModelTrait + 'b,
190        O: PartialModelTrait + 'b,
191    {
192        self.into_partial_model().stream(db)
193    }
194
195    /// Consolidate query result by first / second model depending on join topology
196    /// ```
197    /// # use sea_orm::{tests_cfg::*, *};
198    /// # fn function(db: &DbConn) -> Result<(), DbErr> {
199    /// // fruit -> cake -> filling
200    /// let items: Vec<(fruit::Model, Vec<(cake::Model, Vec<filling::Model>)>)> = fruit::Entity::find()
201    ///     .find_also_related(cake::Entity)
202    ///     .and_also_related(filling::Entity)
203    ///     .consolidate()
204    ///     .all(db)
205    ///     ?;
206    ///
207    /// // cake -> fruit
208    /// //      -> filling
209    /// let items: Vec<(cake::Model, Vec<fruit::Model>, Vec<filling::Model>)> = cake::Entity::find()
210    ///     .find_also_related(fruit::Entity)
211    ///     .find_also_related(filling::Entity)
212    ///     .consolidate()
213    ///     .all(db)
214    ///     ?;
215    /// # Ok(())
216    /// # }
217    /// ```
218    pub fn consolidate(self) -> SelectThreeMany<E, F, G, TOP> {
219        SelectThreeMany {
220            query: self.query,
221            entity: self.entity,
222        }
223    }
224}
225
226impl<E, F, G, TOP> SelectThreeMany<E, F, G, TOP>
227where
228    E: EntityTrait,
229    F: EntityTrait,
230    G: EntityTrait,
231    TOP: Topology,
232{
233    /// Performs a conversion to [Selector]
234    fn into_model<M, N, O>(self) -> Selector<SelectThreeModel<M, N, O>>
235    where
236        M: FromQueryResult,
237        N: FromQueryResult,
238        O: FromQueryResult,
239    {
240        Selector {
241            query: self.query,
242            selector: PhantomData,
243        }
244    }
245}
246
247impl<E, F, G> SelectThreeMany<E, F, G, TopologyStar>
248where
249    E: EntityTrait,
250    F: EntityTrait,
251    G: EntityTrait,
252{
253    /// Execute query and consolidate rows by E
254    pub fn all<C>(self, db: &C) -> Result<Vec<(E::Model, Vec<F::Model>, Vec<G::Model>)>, DbErr>
255    where
256        C: ConnectionTrait,
257    {
258        let rows = self.into_model().all(db)?;
259        Ok(consolidate_query_result_tee::<E, F, G>(rows))
260    }
261}
262
263impl<E, F, G> SelectThreeMany<E, F, G, TopologyChain>
264where
265    E: EntityTrait,
266    F: EntityTrait,
267    G: EntityTrait,
268{
269    /// Execute query and consolidate rows in two passes, first by E, then by F
270    pub fn all<C>(self, db: &C) -> Result<Vec<(E::Model, Vec<(F::Model, Vec<G::Model>)>)>, DbErr>
271    where
272        C: ConnectionTrait,
273    {
274        let rows = self.into_model().all(db)?;
275        Ok(consolidate_query_result_chain::<E, F, G>(rows))
276    }
277}
278
279impl<'db, C, M, N, O, E, F, G, TOP> PaginatorTrait<'db, C> for SelectThree<E, F, G, TOP>
280where
281    C: ConnectionTrait,
282    E: EntityTrait<Model = M>,
283    F: EntityTrait<Model = N>,
284    G: EntityTrait<Model = O>,
285    M: FromQueryResult + Sized + 'db,
286    N: FromQueryResult + Sized + 'db,
287    O: FromQueryResult + Sized + 'db,
288    TOP: Topology,
289{
290    type Selector = SelectThreeModel<M, N, O>;
291
292    fn paginate(self, db: &'db C, page_size: u64) -> Paginator<'db, C, Self::Selector> {
293        self.into_model().paginate(db, page_size)
294    }
295}