sea_orm/executor/select.rs
1use super::{
2 consolidate_query_result, consolidate_query_result_chain, consolidate_query_result_tee,
3};
4use crate::{
5 ConnectionTrait, DbBackend, EntityTrait, FromQueryResult, IdenStatic, PartialModelTrait,
6 QueryResult, QuerySelect, Select, SelectA, SelectB, SelectC, SelectThree, SelectThreeMany,
7 SelectTwo, SelectTwoMany, Statement, StreamTrait, Topology, TopologyChain, TopologyStar,
8 TryGetableMany, error::*,
9};
10use futures_util::{Stream, TryStreamExt};
11use sea_query::SelectStatement;
12use std::{marker::PhantomData, pin::Pin};
13
14#[cfg(feature = "with-json")]
15use crate::JsonValue;
16
17/// Defines a type to do `SELECT` operations through a [SelectStatement] on a Model
18#[derive(Clone, Debug)]
19pub struct Selector<S>
20where
21 S: SelectorTrait,
22{
23 pub(crate) query: SelectStatement,
24 selector: PhantomData<S>,
25}
26
27/// Performs a raw `SELECT` operation on a model
28#[derive(Clone, Debug)]
29pub struct SelectorRaw<S>
30where
31 S: SelectorTrait,
32{
33 pub(crate) stmt: Statement,
34 pub(super) selector: PhantomData<S>,
35}
36
37/// A Trait for any type that can perform SELECT queries
38pub trait SelectorTrait {
39 #[allow(missing_docs)]
40 type Item: Sized;
41
42 /// The method to perform a query on a Model
43 fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr>;
44}
45
46/// Get tuple from query result based on a list of column identifiers
47#[derive(Debug)]
48pub struct SelectGetableValue<T, C>
49where
50 T: TryGetableMany,
51 C: strum::IntoEnumIterator + sea_query::Iden,
52{
53 columns: PhantomData<C>,
54 model: PhantomData<T>,
55}
56
57/// Get tuple from query result based on column index
58#[derive(Debug)]
59pub struct SelectGetableTuple<T>
60where
61 T: TryGetableMany,
62{
63 model: PhantomData<T>,
64}
65
66/// Helper class to handle query result for 1 Model
67#[derive(Debug)]
68pub struct SelectModel<M>
69where
70 M: FromQueryResult,
71{
72 model: PhantomData<M>,
73}
74
75/// Helper class to handle query result for 2 Models
76#[derive(Clone, Debug)]
77pub struct SelectTwoModel<M, N>
78where
79 M: FromQueryResult,
80 N: FromQueryResult,
81{
82 model: PhantomData<(M, N)>,
83}
84
85/// Helper class to handle query result for 3 Models
86#[derive(Clone, Debug)]
87pub struct SelectThreeModel<M, N, O>
88where
89 M: FromQueryResult,
90 N: FromQueryResult,
91 O: FromQueryResult,
92{
93 model: PhantomData<(M, N, O)>,
94}
95
96impl<T, C> Default for SelectGetableValue<T, C>
97where
98 T: TryGetableMany,
99 C: strum::IntoEnumIterator + sea_query::Iden,
100{
101 fn default() -> Self {
102 Self {
103 columns: PhantomData,
104 model: PhantomData,
105 }
106 }
107}
108
109impl<T, C> SelectorTrait for SelectGetableValue<T, C>
110where
111 T: TryGetableMany,
112 C: strum::IntoEnumIterator + sea_query::Iden,
113{
114 type Item = T;
115
116 fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
117 let cols: Vec<String> = C::iter().map(|col| col.to_string()).collect();
118 T::try_get_many(&res, "", &cols).map_err(Into::into)
119 }
120}
121
122impl<T> SelectorTrait for SelectGetableTuple<T>
123where
124 T: TryGetableMany,
125{
126 type Item = T;
127
128 fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
129 T::try_get_many_by_index(&res).map_err(Into::into)
130 }
131}
132
133impl<M> SelectorTrait for SelectModel<M>
134where
135 M: FromQueryResult + Sized,
136{
137 type Item = M;
138
139 fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
140 M::from_query_result(&res, "")
141 }
142}
143
144impl<M, N> SelectorTrait for SelectTwoModel<M, N>
145where
146 M: FromQueryResult + Sized,
147 N: FromQueryResult + Sized,
148{
149 type Item = (M, Option<N>);
150
151 fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
152 Ok((
153 M::from_query_result(&res, SelectA.as_str())?,
154 N::from_query_result_optional(&res, SelectB.as_str())?,
155 ))
156 }
157}
158
159impl<M, N, O> SelectorTrait for SelectThreeModel<M, N, O>
160where
161 M: FromQueryResult + Sized,
162 N: FromQueryResult + Sized,
163 O: FromQueryResult + Sized,
164{
165 type Item = (M, Option<N>, Option<O>);
166
167 fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
168 Ok((
169 M::from_query_result(&res, SelectA.as_str())?,
170 N::from_query_result_optional(&res, SelectB.as_str())?,
171 O::from_query_result_optional(&res, SelectC.as_str())?,
172 ))
173 }
174}
175
176impl<E> Select<E>
177where
178 E: EntityTrait,
179{
180 /// Perform a Select operation on a Model using a [Statement]
181 #[allow(clippy::wrong_self_convention)]
182 pub fn from_raw_sql(self, stmt: Statement) -> SelectorRaw<SelectModel<E::Model>> {
183 SelectorRaw {
184 stmt,
185 selector: PhantomData,
186 }
187 }
188
189 /// Return a [Selector] from `Self` that wraps a [SelectModel]
190 pub fn into_model<M>(self) -> Selector<SelectModel<M>>
191 where
192 M: FromQueryResult,
193 {
194 Selector {
195 query: self.query,
196 selector: PhantomData,
197 }
198 }
199
200 /// Return a [Selector] from `Self` that wraps a [SelectModel] with a [PartialModel](PartialModelTrait)
201 ///
202 /// ```
203 /// # #[cfg(feature = "macros")]
204 /// # {
205 /// use sea_orm::{
206 /// entity::*,
207 /// query::*,
208 /// tests_cfg::cake::{self, Entity as Cake},
209 /// DbBackend, DerivePartialModel,
210 /// };
211 /// use sea_query::{Expr, Func, SimpleExpr};
212 ///
213 /// #[derive(DerivePartialModel)]
214 /// #[sea_orm(entity = "Cake")]
215 /// struct PartialCake {
216 /// name: String,
217 /// #[sea_orm(
218 /// from_expr = r#"SimpleExpr::FunctionCall(Func::upper(Expr::col((Cake, cake::Column::Name))))"#
219 /// )]
220 /// name_upper: String,
221 /// }
222 ///
223 /// assert_eq!(
224 /// cake::Entity::find()
225 /// .into_partial_model::<PartialCake>()
226 /// .into_statement(DbBackend::Sqlite)
227 /// .to_string(),
228 /// r#"SELECT "cake"."name" AS "name", UPPER("cake"."name") AS "name_upper" FROM "cake""#
229 /// );
230 /// # }
231 /// ```
232 pub fn into_partial_model<M>(self) -> Selector<SelectModel<M>>
233 where
234 M: PartialModelTrait,
235 {
236 M::select_cols(QuerySelect::select_only(self)).into_model::<M>()
237 }
238
239 /// Get a selectable Model as a [JsonValue] for SQL JSON operations
240 #[cfg(feature = "with-json")]
241 pub fn into_json(self) -> Selector<SelectModel<JsonValue>> {
242 Selector {
243 query: self.query,
244 selector: PhantomData,
245 }
246 }
247
248 /// ```
249 /// # use sea_orm::{error::*, tests_cfg::*, *};
250 /// #
251 /// # #[smol_potat::main]
252 /// # #[cfg(all(feature = "mock", feature = "macros"))]
253 /// # pub async fn main() -> Result<(), DbErr> {
254 /// #
255 /// # let db = MockDatabase::new(DbBackend::Postgres)
256 /// # .append_query_results([[
257 /// # maplit::btreemap! {
258 /// # "cake_name" => Into::<Value>::into("Chocolate Forest"),
259 /// # },
260 /// # maplit::btreemap! {
261 /// # "cake_name" => Into::<Value>::into("New York Cheese"),
262 /// # },
263 /// # ]])
264 /// # .into_connection();
265 /// #
266 /// use sea_orm::{DeriveColumn, EnumIter, entity::*, query::*, tests_cfg::cake};
267 ///
268 /// #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
269 /// enum QueryAs {
270 /// CakeName,
271 /// }
272 ///
273 /// let res: Vec<String> = cake::Entity::find()
274 /// .select_only()
275 /// .column_as(cake::Column::Name, QueryAs::CakeName)
276 /// .into_values::<_, QueryAs>()
277 /// .all(&db)
278 /// .await?;
279 ///
280 /// assert_eq!(
281 /// res,
282 /// ["Chocolate Forest".to_owned(), "New York Cheese".to_owned()]
283 /// );
284 ///
285 /// assert_eq!(
286 /// db.into_transaction_log(),
287 /// [Transaction::from_sql_and_values(
288 /// DbBackend::Postgres,
289 /// r#"SELECT "cake"."name" AS "cake_name" FROM "cake""#,
290 /// []
291 /// )]
292 /// );
293 /// #
294 /// # Ok(())
295 /// # }
296 /// ```
297 ///
298 /// ```
299 /// # use sea_orm::{error::*, tests_cfg::*, *};
300 /// #
301 /// # #[smol_potat::main]
302 /// # #[cfg(all(feature = "mock", feature = "macros"))]
303 /// # pub async fn main() -> Result<(), DbErr> {
304 /// #
305 /// # let db = MockDatabase::new(DbBackend::Postgres)
306 /// # .append_query_results([[
307 /// # maplit::btreemap! {
308 /// # "cake_name" => Into::<Value>::into("Chocolate Forest"),
309 /// # "num_of_cakes" => Into::<Value>::into(2i64),
310 /// # },
311 /// # ]])
312 /// # .into_connection();
313 /// #
314 /// use sea_orm::{DeriveColumn, EnumIter, entity::*, query::*, tests_cfg::cake};
315 ///
316 /// #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
317 /// enum QueryAs {
318 /// CakeName,
319 /// NumOfCakes,
320 /// }
321 ///
322 /// let res: Vec<(String, i64)> = cake::Entity::find()
323 /// .select_only()
324 /// .column_as(cake::Column::Name, QueryAs::CakeName)
325 /// .column_as(cake::Column::Id.count(), QueryAs::NumOfCakes)
326 /// .group_by(cake::Column::Name)
327 /// .into_values::<_, QueryAs>()
328 /// .all(&db)
329 /// .await?;
330 ///
331 /// assert_eq!(res, [("Chocolate Forest".to_owned(), 2i64)]);
332 ///
333 /// assert_eq!(
334 /// db.into_transaction_log(),
335 /// [Transaction::from_sql_and_values(
336 /// DbBackend::Postgres,
337 /// [
338 /// r#"SELECT "cake"."name" AS "cake_name", COUNT("cake"."id") AS "num_of_cakes""#,
339 /// r#"FROM "cake" GROUP BY "cake"."name""#,
340 /// ]
341 /// .join(" ")
342 /// .as_str(),
343 /// []
344 /// )]
345 /// );
346 /// #
347 /// # Ok(())
348 /// # }
349 /// ```
350 pub fn into_values<T, C>(self) -> Selector<SelectGetableValue<T, C>>
351 where
352 T: TryGetableMany,
353 C: strum::IntoEnumIterator + sea_query::Iden,
354 {
355 Selector {
356 query: self.query,
357 selector: PhantomData,
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 /// # },
373 /// # maplit::btreemap! {
374 /// # "cake_name" => Into::<Value>::into("New York Cheese"),
375 /// # },
376 /// # ]])
377 /// # .into_connection();
378 /// #
379 /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
380 ///
381 /// let res: Vec<String> = cake::Entity::find()
382 /// .select_only()
383 /// .column(cake::Column::Name)
384 /// .into_tuple()
385 /// .all(&db)
386 /// .await?;
387 ///
388 /// assert_eq!(
389 /// res,
390 /// vec!["Chocolate Forest".to_owned(), "New York Cheese".to_owned()]
391 /// );
392 ///
393 /// assert_eq!(
394 /// db.into_transaction_log(),
395 /// vec![Transaction::from_sql_and_values(
396 /// DbBackend::Postgres,
397 /// r#"SELECT "cake"."name" FROM "cake""#,
398 /// vec![]
399 /// )]
400 /// );
401 /// #
402 /// # Ok(())
403 /// # }
404 /// ```
405 ///
406 /// ```
407 /// # use sea_orm::{error::*, tests_cfg::*, *};
408 /// #
409 /// # #[smol_potat::main]
410 /// # #[cfg(all(feature = "mock", feature = "macros"))]
411 /// # pub async fn main() -> Result<(), DbErr> {
412 /// #
413 /// # let db = MockDatabase::new(DbBackend::Postgres)
414 /// # .append_query_results(vec![vec![
415 /// # maplit::btreemap! {
416 /// # "cake_name" => Into::<Value>::into("Chocolate Forest"),
417 /// # "num_of_cakes" => Into::<Value>::into(2i64),
418 /// # },
419 /// # ]])
420 /// # .into_connection();
421 /// #
422 /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
423 ///
424 /// let res: Vec<(String, i64)> = cake::Entity::find()
425 /// .select_only()
426 /// .column(cake::Column::Name)
427 /// .column(cake::Column::Id)
428 /// .group_by(cake::Column::Name)
429 /// .into_tuple()
430 /// .all(&db)
431 /// .await?;
432 ///
433 /// assert_eq!(res, vec![("Chocolate Forest".to_owned(), 2i64)]);
434 ///
435 /// assert_eq!(
436 /// db.into_transaction_log(),
437 /// vec![Transaction::from_sql_and_values(
438 /// DbBackend::Postgres,
439 /// vec![
440 /// r#"SELECT "cake"."name", "cake"."id""#,
441 /// r#"FROM "cake" GROUP BY "cake"."name""#,
442 /// ]
443 /// .join(" ")
444 /// .as_str(),
445 /// vec![]
446 /// )]
447 /// );
448 /// #
449 /// # Ok(())
450 /// # }
451 /// ```
452 pub fn into_tuple<T>(self) -> Selector<SelectGetableTuple<T>>
453 where
454 T: TryGetableMany,
455 {
456 Selector {
457 query: self.query,
458 selector: PhantomData,
459 }
460 }
461
462 /// Get one Model from the SELECT query
463 pub async fn one<C>(self, db: &C) -> Result<Option<E::Model>, DbErr>
464 where
465 C: ConnectionTrait,
466 {
467 self.into_model().one(db).await
468 }
469
470 /// Get all Models from the SELECT query
471 pub async fn all<C>(self, db: &C) -> Result<Vec<E::Model>, DbErr>
472 where
473 C: ConnectionTrait,
474 {
475 self.into_model().all(db).await
476 }
477
478 /// Stream the results of a SELECT operation on a Model
479 pub async fn stream<'a: 'b, 'b, C>(
480 self,
481 db: &'a C,
482 ) -> Result<impl Stream<Item = Result<E::Model, DbErr>> + 'b + Send, DbErr>
483 where
484 C: ConnectionTrait + StreamTrait + Send,
485 {
486 self.into_model().stream(db).await
487 }
488
489 /// Stream the result of the operation with PartialModel
490 pub async fn stream_partial_model<'a: 'b, 'b, C, M>(
491 self,
492 db: &'a C,
493 ) -> Result<impl Stream<Item = Result<M, DbErr>> + 'b + Send, DbErr>
494 where
495 C: ConnectionTrait + StreamTrait + Send,
496 M: PartialModelTrait + Send + 'b,
497 {
498 self.into_partial_model().stream(db).await
499 }
500}
501
502impl<E, F> SelectTwo<E, F>
503where
504 E: EntityTrait,
505 F: EntityTrait,
506{
507 /// Perform a conversion into a [SelectTwoModel]
508 pub fn into_model<M, N>(self) -> Selector<SelectTwoModel<M, N>>
509 where
510 M: FromQueryResult,
511 N: FromQueryResult,
512 {
513 Selector {
514 query: self.query,
515 selector: PhantomData,
516 }
517 }
518
519 /// Perform a conversion into a [SelectTwoModel] with [PartialModel](PartialModelTrait)
520 pub fn into_partial_model<M, N>(self) -> Selector<SelectTwoModel<M, N>>
521 where
522 M: PartialModelTrait,
523 N: PartialModelTrait,
524 {
525 let select = QuerySelect::select_only(self);
526 let select = M::select_cols(select);
527 let select = N::select_cols(select);
528 select.into_model::<M, N>()
529 }
530
531 /// Convert the Models into JsonValue
532 #[cfg(feature = "with-json")]
533 pub fn into_json(self) -> Selector<SelectTwoModel<JsonValue, JsonValue>> {
534 Selector {
535 query: self.query,
536 selector: PhantomData,
537 }
538 }
539
540 /// Get one Model from the Select query
541 pub async fn one<C>(self, db: &C) -> Result<Option<(E::Model, Option<F::Model>)>, DbErr>
542 where
543 C: ConnectionTrait,
544 {
545 self.into_model().one(db).await
546 }
547
548 /// Get all Models from the Select query
549 pub async fn all<C>(self, db: &C) -> Result<Vec<(E::Model, Option<F::Model>)>, DbErr>
550 where
551 C: ConnectionTrait,
552 {
553 self.into_model().all(db).await
554 }
555
556 /// Stream the results of a Select operation on a Model
557 pub async fn stream<'a: 'b, 'b, C>(
558 self,
559 db: &'a C,
560 ) -> Result<impl Stream<Item = Result<(E::Model, Option<F::Model>), DbErr>> + 'b, DbErr>
561 where
562 C: ConnectionTrait + StreamTrait + Send,
563 {
564 self.into_model().stream(db).await
565 }
566
567 /// Stream the result of the operation with PartialModel
568 pub async fn stream_partial_model<'a: 'b, 'b, C, M, N>(
569 self,
570 db: &'a C,
571 ) -> Result<impl Stream<Item = Result<(M, Option<N>), DbErr>> + 'b + Send, DbErr>
572 where
573 C: ConnectionTrait + StreamTrait + Send,
574 M: PartialModelTrait + Send + 'b,
575 N: PartialModelTrait + Send + 'b,
576 {
577 self.into_partial_model().stream(db).await
578 }
579}
580
581impl<E, F> SelectTwoMany<E, F>
582where
583 E: EntityTrait,
584 F: EntityTrait,
585{
586 /// Performs a conversion to [Selector]
587 fn into_model<M, N>(self) -> Selector<SelectTwoModel<M, N>>
588 where
589 M: FromQueryResult,
590 N: FromQueryResult,
591 {
592 Selector {
593 query: self.query,
594 selector: PhantomData,
595 }
596 }
597
598 /// Get all Models from the select operation and consolidate result based on left Model.
599 ///
600 /// > `SelectTwoMany::one()` method has been dropped (#486)
601 /// >
602 /// > You can get `(Entity, Vec<relatedEntity>)` by first querying a single model from Entity,
603 /// > then use [`ModelTrait::find_related`] on the model.
604 /// >
605 /// > See https://www.sea-ql.org/SeaORM/docs/basic-crud/select#lazy-loading for details.
606 pub async fn all<C>(self, db: &C) -> Result<Vec<(E::Model, Vec<F::Model>)>, DbErr>
607 where
608 C: ConnectionTrait,
609 {
610 let rows = self.into_model().all(db).await?;
611 Ok(consolidate_query_result::<E, F>(rows))
612 }
613
614 // pub fn paginate()
615 // we could not implement paginate easily, if the number of children for a
616 // parent is larger than one page, then we will end up splitting it in two pages
617 // so the correct way is actually perform query in two stages
618 // paginate the parent model and then populate the children
619
620 // pub fn count()
621 // we should only count the number of items of the parent model
622}
623
624impl<E, F, G, TOP> SelectThree<E, F, G, TOP>
625where
626 E: EntityTrait,
627 F: EntityTrait,
628 G: EntityTrait,
629 TOP: Topology,
630{
631 /// Perform a conversion into a [SelectThreeModel]
632 pub fn into_model<M, N, O>(self) -> Selector<SelectThreeModel<M, N, O>>
633 where
634 M: FromQueryResult,
635 N: FromQueryResult,
636 O: FromQueryResult,
637 {
638 Selector {
639 query: self.query,
640 selector: PhantomData,
641 }
642 }
643
644 /// Perform a conversion into a [SelectThreeModel] with [PartialModel](PartialModelTrait)
645 pub fn into_partial_model<M, N, O>(self) -> Selector<SelectThreeModel<M, N, O>>
646 where
647 M: PartialModelTrait,
648 N: PartialModelTrait,
649 O: PartialModelTrait,
650 {
651 let select = QuerySelect::select_only(self);
652 let select = M::select_cols(select);
653 let select = N::select_cols(select);
654 select.into_model::<M, N, O>()
655 }
656
657 /// Convert the Models into JsonValue
658 #[cfg(feature = "with-json")]
659 pub fn into_json(self) -> Selector<SelectThreeModel<JsonValue, JsonValue, JsonValue>> {
660 Selector {
661 query: self.query,
662 selector: PhantomData,
663 }
664 }
665
666 /// Get one Model from the Select query
667 pub async fn one<C>(
668 self,
669 db: &C,
670 ) -> Result<Option<(E::Model, Option<F::Model>, Option<G::Model>)>, DbErr>
671 where
672 C: ConnectionTrait,
673 {
674 self.into_model().one(db).await
675 }
676
677 /// Get all Models from the Select query
678 pub async fn all<C>(
679 self,
680 db: &C,
681 ) -> Result<Vec<(E::Model, Option<F::Model>, Option<G::Model>)>, DbErr>
682 where
683 C: ConnectionTrait,
684 {
685 self.into_model().all(db).await
686 }
687
688 /// Stream the results of a Select operation on a Model
689 pub async fn stream<'a: 'b, 'b, C>(
690 self,
691 db: &'a C,
692 ) -> Result<
693 impl Stream<Item = Result<(E::Model, Option<F::Model>, Option<G::Model>), DbErr>> + 'b,
694 DbErr,
695 >
696 where
697 C: ConnectionTrait + StreamTrait + Send,
698 {
699 self.into_model().stream(db).await
700 }
701
702 /// Stream the result of the operation with PartialModel
703 pub async fn stream_partial_model<'a: 'b, 'b, C, M, N, O>(
704 self,
705 db: &'a C,
706 ) -> Result<impl Stream<Item = Result<(M, Option<N>, Option<O>), DbErr>> + 'b + Send, DbErr>
707 where
708 C: ConnectionTrait + StreamTrait + Send,
709 M: PartialModelTrait + Send + 'b,
710 N: PartialModelTrait + Send + 'b,
711 O: PartialModelTrait + Send + 'b,
712 {
713 self.into_partial_model().stream(db).await
714 }
715
716 /// Consolidate query result by first / second model depending on join topology
717 pub fn consolidate(self) -> SelectThreeMany<E, F, G, TOP> {
718 SelectThreeMany {
719 query: self.query,
720 entity: self.entity,
721 }
722 }
723}
724
725impl<E, F, G, TOP> SelectThreeMany<E, F, G, TOP>
726where
727 E: EntityTrait,
728 F: EntityTrait,
729 G: EntityTrait,
730 TOP: Topology,
731{
732 /// Performs a conversion to [Selector]
733 fn into_model<M, N, O>(self) -> Selector<SelectThreeModel<M, N, O>>
734 where
735 M: FromQueryResult,
736 N: FromQueryResult,
737 O: FromQueryResult,
738 {
739 Selector {
740 query: self.query,
741 selector: PhantomData,
742 }
743 }
744}
745
746impl<E, F, G> SelectThreeMany<E, F, G, TopologyStar>
747where
748 E: EntityTrait,
749 F: EntityTrait,
750 G: EntityTrait,
751{
752 /// Execute query and consolidate rows by E
753 pub async fn all<C>(
754 self,
755 db: &C,
756 ) -> Result<Vec<(E::Model, Vec<F::Model>, Vec<G::Model>)>, DbErr>
757 where
758 C: ConnectionTrait,
759 {
760 let rows = self.into_model().all(db).await?;
761 Ok(consolidate_query_result_tee::<E, F, G>(rows))
762 }
763}
764
765impl<E, F, G> SelectThreeMany<E, F, G, TopologyChain>
766where
767 E: EntityTrait,
768 F: EntityTrait,
769 G: EntityTrait,
770{
771 /// Execute query and consolidate rows in two passes, first by E, then by F
772 pub async fn all<C>(
773 self,
774 db: &C,
775 ) -> Result<Vec<(E::Model, Vec<(F::Model, Vec<G::Model>)>)>, DbErr>
776 where
777 C: ConnectionTrait,
778 {
779 let rows = self.into_model().all(db).await?;
780 Ok(consolidate_query_result_chain::<E, F, G>(rows))
781 }
782}
783
784impl<S> Selector<S>
785where
786 S: SelectorTrait,
787{
788 /// Get the SQL statement
789 pub fn into_statement(self, builder: DbBackend) -> Statement {
790 builder.build(&self.query)
791 }
792
793 /// Get an item from the Select query
794 pub async fn one<C>(mut self, db: &C) -> Result<Option<S::Item>, DbErr>
795 where
796 C: ConnectionTrait,
797 {
798 self.query.limit(1);
799 let row = db.query_one(&self.query).await?;
800 match row {
801 Some(row) => Ok(Some(S::from_raw_query_result(row)?)),
802 None => Ok(None),
803 }
804 }
805
806 /// Get all items from the Select query
807 pub async fn all<C>(self, db: &C) -> Result<Vec<S::Item>, DbErr>
808 where
809 C: ConnectionTrait,
810 {
811 let rows = db.query_all(&self.query).await?;
812 let mut models = Vec::new();
813 for row in rows.into_iter() {
814 models.push(S::from_raw_query_result(row)?);
815 }
816 Ok(models)
817 }
818
819 /// Stream the results of the Select operation
820 pub async fn stream<'a: 'b, 'b, C>(
821 self,
822 db: &'a C,
823 ) -> Result<Pin<Box<dyn Stream<Item = Result<S::Item, DbErr>> + 'b + Send>>, DbErr>
824 where
825 C: ConnectionTrait + StreamTrait + Send,
826 S: 'b,
827 S::Item: Send,
828 {
829 let stream = db.stream(&self.query).await?;
830 Ok(Box::pin(stream.and_then(|row| {
831 futures_util::future::ready(S::from_raw_query_result(row))
832 })))
833 }
834}
835
836impl<S> SelectorRaw<S>
837where
838 S: SelectorTrait,
839{
840 /// Select a custom Model from a raw SQL [Statement].
841 pub fn from_statement<M>(stmt: Statement) -> SelectorRaw<SelectModel<M>>
842 where
843 M: FromQueryResult,
844 {
845 SelectorRaw {
846 stmt,
847 selector: PhantomData,
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::{FromQueryResult, entity::*, query::*, tests_cfg::cake};
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: 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: 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::*, raw_sql, tests_cfg::cake};
1012 ///
1013 /// let id = 1;
1014 ///
1015 /// let _: Option<cake::Model> = cake::Entity::find()
1016 /// .from_raw_sql(raw_sql!(
1017 /// Postgres,
1018 /// r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "id" = {id}"#
1019 /// ))
1020 /// .one(&db)
1021 /// .await?;
1022 ///
1023 /// assert_eq!(
1024 /// db.into_transaction_log(),
1025 /// [Transaction::from_sql_and_values(
1026 /// DbBackend::Postgres,
1027 /// r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "id" = $1"#,
1028 /// [1.into()]
1029 /// ),]
1030 /// );
1031 /// #
1032 /// # Ok(())
1033 /// # }
1034 /// ```
1035 pub async fn one<C>(self, db: &C) -> Result<Option<S::Item>, DbErr>
1036 where
1037 C: ConnectionTrait,
1038 {
1039 let row = db.query_one_raw(self.stmt).await?;
1040 match row {
1041 Some(row) => Ok(Some(S::from_raw_query_result(row)?)),
1042 None => Ok(None),
1043 }
1044 }
1045
1046 /// Get all items from the Select query
1047 /// ```
1048 /// # use sea_orm::{error::*, tests_cfg::*, *};
1049 /// #
1050 /// # #[smol_potat::main]
1051 /// # #[cfg(feature = "mock")]
1052 /// # pub async fn main() -> Result<(), DbErr> {
1053 /// #
1054 /// # let db = MockDatabase::new(DbBackend::Postgres)
1055 /// # .append_query_results([
1056 /// # [cake::Model {
1057 /// # id: 1,
1058 /// # name: "Cake".to_owned(),
1059 /// # }],
1060 /// # ])
1061 /// # .into_connection();
1062 /// #
1063 /// use sea_orm::{entity::*, query::*, raw_sql, tests_cfg::cake};
1064 ///
1065 /// let _: Vec<cake::Model> = cake::Entity::find()
1066 /// .from_raw_sql(raw_sql!(
1067 /// Postgres,
1068 /// r#"SELECT "cake"."id", "cake"."name" FROM "cake""#
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_raw(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_raw(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}