sea_orm/executor/select.rs
1use super::{
2 consolidate_query_result, consolidate_query_result_chain, consolidate_query_result_quad_star,
3 consolidate_query_result_tee,
4};
5use crate::{
6 ConnectionTrait, DbBackend, EntityTrait, FromQueryResult, IdenStatic, PartialModelTrait,
7 QueryResult, QuerySelect, Select, SelectA, SelectB, SelectTwo, SelectTwoMany,
8 SelectTwoRequired, Statement, TryGetableMany, error::*,
9};
10
11#[cfg(feature = "stream")]
12pub use crate::StreamTrait;
13
14use itertools::Itertools;
15use sea_query::SelectStatement;
16use std::marker::PhantomData;
17
18mod five;
19mod four;
20mod six;
21mod three;
22
23#[cfg(feature = "with-json")]
24use crate::JsonValue;
25
26#[cfg(all(not(feature = "sync"), feature = "stream"))]
27type PinBoxStream<'b, S> = std::pin::Pin<Box<dyn Stream<Item = Result<S, DbErr>> + 'b>>;
28#[cfg(feature = "sync")]
29type PinBoxStream<'b, S> = Box<dyn Iterator<Item = Result<S, DbErr>> + 'b>;
30
31/// A ready-to-execute `SELECT` query backed by a [`SelectStatement`]. The
32/// type parameter `S` (a [`SelectorTrait`]) determines what each row is
33/// decoded into. Build one via
34/// [`Select::into_model`](crate::Select::into_model) or
35/// [`Select::into_partial_model`](crate::Select::into_partial_model), then
36/// call `.one(db)` / `.all(db)` / `.paginate(db, n)`.
37#[derive(Clone, Debug)]
38pub struct Selector<S>
39where
40 S: SelectorTrait,
41{
42 pub(crate) query: SelectStatement,
43 selector: PhantomData<S>,
44}
45
46/// Like [`Selector`] but executes a raw [`Statement`] (e.g. built with the
47/// [`raw_sql!`](crate::raw_sql) macro) instead of a `sea_query` query.
48#[derive(Clone, Debug)]
49pub struct SelectorRaw<S>
50where
51 S: SelectorTrait,
52{
53 pub(crate) stmt: Statement,
54 pub(super) selector: PhantomData<S>,
55}
56
57/// Decodes one row of a [`Selector`] / [`SelectorRaw`] result into a value of
58/// type [`Item`](Self::Item). Implemented by the `SelectModel*` types below;
59/// you usually never name this trait directly.
60pub trait SelectorTrait {
61 /// Type produced for each row.
62 type Item: Sized;
63
64 /// Decode one row.
65 fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr>;
66}
67
68/// [`SelectorTrait`] adapter that decodes each row as a tuple `T` whose
69/// columns are addressed by the iden enum `C` (rather than positionally).
70#[derive(Debug)]
71pub struct SelectGetableValue<T, C>
72where
73 T: TryGetableMany,
74 C: strum::IntoEnumIterator + sea_query::Iden,
75{
76 columns: PhantomData<C>,
77 model: PhantomData<T>,
78}
79
80/// [`SelectorTrait`] adapter that decodes each row positionally into the
81/// tuple type `T`.
82#[derive(Debug)]
83pub struct SelectGetableTuple<T>
84where
85 T: TryGetableMany,
86{
87 model: PhantomData<T>,
88}
89
90/// [`SelectorTrait`] for a query that yields a single model per row.
91#[derive(Debug)]
92pub struct SelectModel<M>
93where
94 M: FromQueryResult,
95{
96 model: PhantomData<M>,
97}
98
99/// [`SelectorTrait`] for a join that yields `(M, Option<N>)` per row — the
100/// right side is `None` for outer-join rows with no match.
101#[derive(Clone, Debug)]
102pub struct SelectTwoModel<M, N>
103where
104 M: FromQueryResult,
105 N: FromQueryResult,
106{
107 model: PhantomData<(M, N)>,
108}
109
110/// [`SelectorTrait`] for a join that yields `(M, N)` per row (both sides
111/// required, e.g. an inner join).
112#[derive(Clone, Debug)]
113pub struct SelectTwoRequiredModel<M, N>
114where
115 M: FromQueryResult,
116 N: FromQueryResult,
117{
118 model: PhantomData<(M, N)>,
119}
120
121/// [`SelectorTrait`] for a three-way join that yields `(M, Option<N>, Option<O>)`.
122#[derive(Clone, Debug)]
123pub struct SelectThreeModel<M, N, O>
124where
125 M: FromQueryResult,
126 N: FromQueryResult,
127 O: FromQueryResult,
128{
129 model: PhantomData<(M, N, O)>,
130}
131
132/// [`SelectorTrait`] for a four-way join that yields
133/// `(M, Option<N>, Option<O>, Option<P>)`.
134#[derive(Clone, Debug)]
135pub struct SelectFourModel<M, N, O, P>
136where
137 M: FromQueryResult,
138 N: FromQueryResult,
139 O: FromQueryResult,
140 P: FromQueryResult,
141{
142 model: PhantomData<(M, N, O, P)>,
143}
144
145/// [`SelectorTrait`] for a five-way join that yields
146/// `(M, Option<N>, Option<O>, Option<P>, Option<Q>)`.
147#[derive(Clone, Debug)]
148pub struct SelectFiveModel<M, N, O, P, Q>
149where
150 M: FromQueryResult,
151 N: FromQueryResult,
152 O: FromQueryResult,
153 P: FromQueryResult,
154 Q: FromQueryResult,
155{
156 model: PhantomData<(M, N, O, P, Q)>,
157}
158
159/// [`SelectorTrait`] for a six-way join that yields
160/// `(M, Option<N>, Option<O>, Option<P>, Option<Q>, Option<R>)`.
161#[derive(Clone, Debug)]
162pub struct SelectSixModel<M, N, O, P, Q, R>
163where
164 M: FromQueryResult,
165 N: FromQueryResult,
166 O: FromQueryResult,
167 P: FromQueryResult,
168 Q: FromQueryResult,
169 R: FromQueryResult,
170{
171 model: PhantomData<(M, N, O, P, Q, R)>,
172}
173
174impl<T, C> Default for SelectGetableValue<T, C>
175where
176 T: TryGetableMany,
177 C: strum::IntoEnumIterator + sea_query::Iden,
178{
179 fn default() -> Self {
180 Self {
181 columns: PhantomData,
182 model: PhantomData,
183 }
184 }
185}
186
187impl<T, C> SelectorTrait for SelectGetableValue<T, C>
188where
189 T: TryGetableMany,
190 C: strum::IntoEnumIterator + sea_query::Iden,
191{
192 type Item = T;
193
194 fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
195 let cols: Vec<String> = C::iter().map(|col| col.to_string()).collect();
196 T::try_get_many(&res, "", &cols).map_err(Into::into)
197 }
198}
199
200impl<T> SelectorTrait for SelectGetableTuple<T>
201where
202 T: TryGetableMany,
203{
204 type Item = T;
205
206 fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
207 T::try_get_many_by_index(&res).map_err(Into::into)
208 }
209}
210
211impl<M> SelectorTrait for SelectModel<M>
212where
213 M: FromQueryResult + Sized,
214{
215 type Item = M;
216
217 fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
218 M::from_query_result(&res, "")
219 }
220}
221
222impl<M, N> SelectorTrait for SelectTwoModel<M, N>
223where
224 M: FromQueryResult + Sized,
225 N: FromQueryResult + Sized,
226{
227 type Item = (M, Option<N>);
228
229 fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
230 Ok((
231 M::from_query_result(&res, SelectA.as_str())?,
232 N::from_query_result_optional(&res, SelectB.as_str())?,
233 ))
234 }
235}
236
237impl<M, N> SelectorTrait for SelectTwoRequiredModel<M, N>
238where
239 M: FromQueryResult + Sized,
240 N: FromQueryResult + Sized,
241{
242 type Item = (M, N);
243
244 fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
245 Ok((
246 M::from_query_result(&res, SelectA.as_str())?,
247 N::from_query_result(&res, SelectB.as_str())?,
248 ))
249 }
250}
251
252impl<E> Select<E>
253where
254 E: EntityTrait,
255{
256 /// Perform a Select operation on a Model using a [Statement]
257 #[allow(clippy::wrong_self_convention)]
258 pub fn from_raw_sql(self, stmt: Statement) -> SelectorRaw<SelectModel<E::Model>> {
259 SelectorRaw {
260 stmt,
261 selector: PhantomData,
262 }
263 }
264
265 /// Return a [Selector] from `Self` that wraps a [SelectModel]
266 pub fn into_model<M>(self) -> Selector<SelectModel<M>>
267 where
268 M: FromQueryResult,
269 {
270 Selector {
271 query: self.query,
272 selector: PhantomData,
273 }
274 }
275
276 /// Return a [Selector] from `Self` that wraps a [SelectModel] with a [PartialModel](PartialModelTrait)
277 ///
278 /// ```
279 /// # #[cfg(feature = "macros")]
280 /// # {
281 /// use sea_orm::{
282 /// entity::*,
283 /// query::*,
284 /// tests_cfg::cake::{self, Entity as Cake},
285 /// DbBackend, DerivePartialModel,
286 /// };
287 /// use sea_query::{Expr, Func, SimpleExpr};
288 ///
289 /// #[derive(DerivePartialModel)]
290 /// #[sea_orm(entity = "Cake")]
291 /// struct PartialCake {
292 /// name: String,
293 /// #[sea_orm(
294 /// from_expr = r#"SimpleExpr::FunctionCall(Func::upper(Expr::col((Cake, cake::Column::Name))))"#
295 /// )]
296 /// name_upper: String,
297 /// }
298 ///
299 /// assert_eq!(
300 /// cake::Entity::find()
301 /// .into_partial_model::<PartialCake>()
302 /// .into_statement(DbBackend::Sqlite)
303 /// .to_string(),
304 /// r#"SELECT "cake"."name" AS "name", UPPER("cake"."name") AS "name_upper" FROM "cake""#
305 /// );
306 /// # }
307 /// ```
308 pub fn into_partial_model<M>(self) -> Selector<SelectModel<M>>
309 where
310 M: PartialModelTrait,
311 {
312 M::select_cols(QuerySelect::select_only(self)).into_model::<M>()
313 }
314
315 /// Get a selectable Model as a [JsonValue] for SQL JSON operations
316 #[cfg(feature = "with-json")]
317 pub fn into_json(self) -> Selector<SelectModel<JsonValue>> {
318 Selector {
319 query: self.query,
320 selector: PhantomData,
321 }
322 }
323
324 /// ```
325 /// # use sea_orm::{error::*, tests_cfg::*, *};
326 /// #
327 /// # #[cfg(all(feature = "mock", feature = "macros"))]
328 /// # pub fn main() -> Result<(), DbErr> {
329 /// #
330 /// # let db = MockDatabase::new(DbBackend::Postgres)
331 /// # .append_query_results([[
332 /// # maplit::btreemap! {
333 /// # "cake_name" => Into::<Value>::into("Chocolate Forest"),
334 /// # },
335 /// # maplit::btreemap! {
336 /// # "cake_name" => Into::<Value>::into("New York Cheese"),
337 /// # },
338 /// # ]])
339 /// # .into_connection();
340 /// #
341 /// use sea_orm::{DeriveColumn, EnumIter, entity::*, query::*, tests_cfg::cake};
342 ///
343 /// #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
344 /// enum QueryAs {
345 /// CakeName,
346 /// }
347 ///
348 /// let res: Vec<String> = cake::Entity::find()
349 /// .select_only()
350 /// .column_as(cake::Column::Name, QueryAs::CakeName)
351 /// .into_values::<_, QueryAs>()
352 /// .all(&db)?;
353 ///
354 /// assert_eq!(
355 /// res,
356 /// ["Chocolate Forest".to_owned(), "New York Cheese".to_owned()]
357 /// );
358 ///
359 /// assert_eq!(
360 /// db.into_transaction_log(),
361 /// [Transaction::from_sql_and_values(
362 /// DbBackend::Postgres,
363 /// r#"SELECT "cake"."name" AS "cake_name" FROM "cake""#,
364 /// []
365 /// )]
366 /// );
367 /// #
368 /// # Ok(())
369 /// # }
370 /// ```
371 ///
372 /// ```
373 /// # use sea_orm::{error::*, tests_cfg::*, *};
374 /// #
375 /// # #[cfg(all(feature = "mock", feature = "macros"))]
376 /// # pub fn main() -> Result<(), DbErr> {
377 /// #
378 /// # let db = MockDatabase::new(DbBackend::Postgres)
379 /// # .append_query_results([[
380 /// # maplit::btreemap! {
381 /// # "cake_name" => Into::<Value>::into("Chocolate Forest"),
382 /// # "num_of_cakes" => Into::<Value>::into(2i64),
383 /// # },
384 /// # ]])
385 /// # .into_connection();
386 /// #
387 /// use sea_orm::{DeriveColumn, EnumIter, entity::*, query::*, tests_cfg::cake};
388 ///
389 /// #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
390 /// enum QueryAs {
391 /// CakeName,
392 /// NumOfCakes,
393 /// }
394 ///
395 /// let res: Vec<(String, i64)> = cake::Entity::find()
396 /// .select_only()
397 /// .column_as(cake::Column::Name, QueryAs::CakeName)
398 /// .column_as(cake::Column::Id.count(), QueryAs::NumOfCakes)
399 /// .group_by(cake::Column::Name)
400 /// .into_values::<_, QueryAs>()
401 /// .all(&db)?;
402 ///
403 /// assert_eq!(res, [("Chocolate Forest".to_owned(), 2i64)]);
404 ///
405 /// assert_eq!(
406 /// db.into_transaction_log(),
407 /// [Transaction::from_sql_and_values(
408 /// DbBackend::Postgres,
409 /// [
410 /// r#"SELECT "cake"."name" AS "cake_name", COUNT("cake"."id") AS "num_of_cakes""#,
411 /// r#"FROM "cake" GROUP BY "cake"."name""#,
412 /// ]
413 /// .join(" ")
414 /// .as_str(),
415 /// []
416 /// )]
417 /// );
418 /// #
419 /// # Ok(())
420 /// # }
421 /// ```
422 pub fn into_values<T, C>(self) -> Selector<SelectGetableValue<T, C>>
423 where
424 T: TryGetableMany,
425 C: strum::IntoEnumIterator + sea_query::Iden,
426 {
427 Selector {
428 query: self.query,
429 selector: PhantomData,
430 }
431 }
432
433 /// ```
434 /// # use sea_orm::{error::*, tests_cfg::*, *};
435 /// #
436 /// # #[cfg(all(feature = "mock", feature = "macros"))]
437 /// # pub fn main() -> Result<(), DbErr> {
438 /// #
439 /// # let db = MockDatabase::new(DbBackend::Postgres)
440 /// # .append_query_results(vec![vec![
441 /// # maplit::btreemap! {
442 /// # "cake_name" => Into::<Value>::into("Chocolate Forest"),
443 /// # },
444 /// # maplit::btreemap! {
445 /// # "cake_name" => Into::<Value>::into("New York Cheese"),
446 /// # },
447 /// # ]])
448 /// # .into_connection();
449 /// #
450 /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
451 ///
452 /// let res: Vec<String> = cake::Entity::find()
453 /// .select_only()
454 /// .column(cake::Column::Name)
455 /// .into_tuple()
456 /// .all(&db)?;
457 ///
458 /// assert_eq!(
459 /// res,
460 /// vec!["Chocolate Forest".to_owned(), "New York Cheese".to_owned()]
461 /// );
462 ///
463 /// assert_eq!(
464 /// db.into_transaction_log(),
465 /// vec![Transaction::from_sql_and_values(
466 /// DbBackend::Postgres,
467 /// r#"SELECT "cake"."name" FROM "cake""#,
468 /// vec![]
469 /// )]
470 /// );
471 /// #
472 /// # Ok(())
473 /// # }
474 /// ```
475 ///
476 /// ```
477 /// # use sea_orm::{error::*, tests_cfg::*, *};
478 /// #
479 /// # #[cfg(all(feature = "mock", feature = "macros"))]
480 /// # pub fn main() -> Result<(), DbErr> {
481 /// #
482 /// # let db = MockDatabase::new(DbBackend::Postgres)
483 /// # .append_query_results(vec![vec![
484 /// # maplit::btreemap! {
485 /// # "cake_name" => Into::<Value>::into("Chocolate Forest"),
486 /// # "num_of_cakes" => Into::<Value>::into(2i64),
487 /// # },
488 /// # ]])
489 /// # .into_connection();
490 /// #
491 /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
492 ///
493 /// let res: Vec<(String, i64)> = cake::Entity::find()
494 /// .select_only()
495 /// .column(cake::Column::Name)
496 /// .column(cake::Column::Id)
497 /// .group_by(cake::Column::Name)
498 /// .into_tuple()
499 /// .all(&db)?;
500 ///
501 /// assert_eq!(res, vec![("Chocolate Forest".to_owned(), 2i64)]);
502 ///
503 /// assert_eq!(
504 /// db.into_transaction_log(),
505 /// vec![Transaction::from_sql_and_values(
506 /// DbBackend::Postgres,
507 /// vec![
508 /// r#"SELECT "cake"."name", "cake"."id""#,
509 /// r#"FROM "cake" GROUP BY "cake"."name""#,
510 /// ]
511 /// .join(" ")
512 /// .as_str(),
513 /// vec![]
514 /// )]
515 /// );
516 /// #
517 /// # Ok(())
518 /// # }
519 /// ```
520 pub fn into_tuple<T>(self) -> Selector<SelectGetableTuple<T>>
521 where
522 T: TryGetableMany,
523 {
524 Selector {
525 query: self.query,
526 selector: PhantomData,
527 }
528 }
529
530 /// Get one Model from the SELECT query
531 pub fn one<C>(self, db: &C) -> Result<Option<E::Model>, DbErr>
532 where
533 C: ConnectionTrait,
534 {
535 self.into_model().one(db)
536 }
537
538 /// Get all Models from the SELECT query
539 pub fn all<C>(self, db: &C) -> Result<Vec<E::Model>, DbErr>
540 where
541 C: ConnectionTrait,
542 {
543 self.into_model().all(db)
544 }
545
546 /// Stream the results of a SELECT operation on a Model
547 #[cfg(feature = "stream")]
548 pub fn stream<'a: 'b, 'b, C>(
549 self,
550 db: &'a C,
551 ) -> Result<impl Iterator<Item = Result<E::Model, DbErr>> + 'b, DbErr>
552 where
553 C: ConnectionTrait + StreamTrait,
554 {
555 self.into_model().stream(db)
556 }
557
558 /// Stream the result of the operation with PartialModel
559 #[cfg(feature = "stream")]
560 pub fn stream_partial_model<'a: 'b, 'b, C, M>(
561 self,
562 db: &'a C,
563 ) -> Result<impl Iterator<Item = Result<M, DbErr>> + 'b, DbErr>
564 where
565 C: ConnectionTrait + StreamTrait,
566 M: PartialModelTrait + 'b,
567 {
568 self.into_partial_model().stream(db)
569 }
570}
571
572impl<E, F> SelectTwo<E, F>
573where
574 E: EntityTrait,
575 F: EntityTrait,
576{
577 /// Perform a conversion into a [SelectTwoModel]
578 pub fn into_model<M, N>(self) -> Selector<SelectTwoModel<M, N>>
579 where
580 M: FromQueryResult,
581 N: FromQueryResult,
582 {
583 Selector {
584 query: self.query,
585 selector: PhantomData,
586 }
587 }
588
589 /// Perform a conversion into a [SelectTwoModel] with [PartialModel](PartialModelTrait)
590 pub fn into_partial_model<M, N>(self) -> Selector<SelectTwoModel<M, N>>
591 where
592 M: PartialModelTrait,
593 N: PartialModelTrait,
594 {
595 let select = QuerySelect::select_only(self);
596 let select = M::select_cols(select);
597 let select = N::select_cols(select);
598 select.into_model::<M, N>()
599 }
600
601 /// Convert the Models into JsonValue
602 #[cfg(feature = "with-json")]
603 pub fn into_json(self) -> Selector<SelectTwoModel<JsonValue, JsonValue>> {
604 Selector {
605 query: self.query,
606 selector: PhantomData,
607 }
608 }
609
610 /// Get one Model from the Select query
611 pub fn one<C>(self, db: &C) -> Result<Option<(E::Model, Option<F::Model>)>, DbErr>
612 where
613 C: ConnectionTrait,
614 {
615 self.into_model().one(db)
616 }
617
618 /// Get all Models from the Select query
619 pub fn all<C>(self, db: &C) -> Result<Vec<(E::Model, Option<F::Model>)>, DbErr>
620 where
621 C: ConnectionTrait,
622 {
623 self.into_model().all(db)
624 }
625
626 /// Stream the results of a Select operation on a Model
627 #[cfg(feature = "stream")]
628 pub fn stream<'a: 'b, 'b, C>(
629 self,
630 db: &'a C,
631 ) -> Result<impl Iterator<Item = Result<(E::Model, Option<F::Model>), DbErr>> + 'b, DbErr>
632 where
633 C: ConnectionTrait + StreamTrait,
634 {
635 self.into_model().stream(db)
636 }
637
638 /// Stream the result of the operation with PartialModel
639 #[cfg(feature = "stream")]
640 pub fn stream_partial_model<'a: 'b, 'b, C, M, N>(
641 self,
642 db: &'a C,
643 ) -> Result<impl Iterator<Item = Result<(M, Option<N>), DbErr>> + 'b, DbErr>
644 where
645 C: ConnectionTrait + StreamTrait,
646 M: PartialModelTrait + 'b,
647 N: PartialModelTrait + 'b,
648 {
649 self.into_partial_model().stream(db)
650 }
651}
652
653impl<E, F> SelectTwoMany<E, F>
654where
655 E: EntityTrait,
656 F: EntityTrait,
657{
658 /// Performs a conversion to [Selector]
659 fn into_model<M, N>(self) -> Selector<SelectTwoModel<M, N>>
660 where
661 M: FromQueryResult,
662 N: FromQueryResult,
663 {
664 Selector {
665 query: self.query,
666 selector: PhantomData,
667 }
668 }
669
670 /// Run the select and return all matching parent models, each paired
671 /// with its related models (rows are deduplicated and grouped by left
672 /// model).
673 ///
674 /// > `SelectTwoMany::one()` method has been dropped (#486)
675 /// >
676 /// > You can get `(Entity, Vec<relatedEntity>)` by first querying a single model from Entity,
677 /// > then use [`ModelTrait::find_related`](crate::ModelTrait::find_related) on the model.
678 /// >
679 /// > See <https://www.sea-ql.org/SeaORM/docs/basic-crud/select#lazy-loading> for details.
680 pub fn all<C>(self, db: &C) -> Result<Vec<(E::Model, Vec<F::Model>)>, DbErr>
681 where
682 C: ConnectionTrait,
683 {
684 let rows = self.into_model().all(db)?;
685 Ok(consolidate_query_result::<E, F>(rows))
686 }
687
688 // pub fn paginate()
689 // we could not implement paginate easily, if the number of children for a
690 // parent is larger than one page, then we will end up splitting it in two pages
691 // so the correct way is actually perform query in two stages
692 // paginate the parent model and then populate the children
693
694 // pub fn count()
695 // we should only count the number of items of the parent model
696}
697
698impl<E, F> SelectTwoRequired<E, F>
699where
700 E: EntityTrait,
701 F: EntityTrait,
702{
703 /// Perform a conversion into a [SelectTwoRequiredModel]
704 pub fn into_model<M, N>(self) -> Selector<SelectTwoRequiredModel<M, N>>
705 where
706 M: FromQueryResult,
707 N: FromQueryResult,
708 {
709 Selector {
710 query: self.query,
711 selector: PhantomData,
712 }
713 }
714
715 /// Perform a conversion into a [SelectTwoRequiredModel] with [PartialModel](PartialModelTrait)
716 pub fn into_partial_model<M, N>(self) -> Selector<SelectTwoRequiredModel<M, N>>
717 where
718 M: PartialModelTrait,
719 N: PartialModelTrait,
720 {
721 let select = QuerySelect::select_only(self);
722 let select = M::select_cols(select);
723 let select = N::select_cols(select);
724 select.into_model::<M, N>()
725 }
726
727 /// Convert the Models into JsonValue
728 #[cfg(feature = "with-json")]
729 pub fn into_json(self) -> Selector<SelectTwoRequiredModel<JsonValue, JsonValue>> {
730 Selector {
731 query: self.query,
732 selector: PhantomData,
733 }
734 }
735
736 /// Get one Model from the Select query
737 pub fn one<C>(self, db: &C) -> Result<Option<(E::Model, F::Model)>, DbErr>
738 where
739 C: ConnectionTrait,
740 {
741 self.into_model().one(db)
742 }
743
744 /// Get all Models from the Select query
745 pub fn all<C>(self, db: &C) -> Result<Vec<(E::Model, F::Model)>, DbErr>
746 where
747 C: ConnectionTrait,
748 {
749 self.into_model().all(db)
750 }
751
752 /// Stream the results of a Select operation on a Model
753 #[cfg(feature = "stream")]
754 pub fn stream<'a: 'b, 'b, C>(
755 self,
756 db: &'a C,
757 ) -> Result<impl Iterator<Item = Result<(E::Model, F::Model), DbErr>> + 'b, DbErr>
758 where
759 C: ConnectionTrait + StreamTrait,
760 {
761 self.into_model().stream(db)
762 }
763
764 /// Stream the result of the operation with PartialModel
765 #[cfg(feature = "stream")]
766 pub fn stream_partial_model<'a: 'b, 'b, C, M, N>(
767 self,
768 db: &'a C,
769 ) -> Result<impl Iterator<Item = Result<(M, N), DbErr>> + 'b, DbErr>
770 where
771 C: ConnectionTrait + StreamTrait,
772 M: PartialModelTrait + 'b,
773 N: PartialModelTrait + 'b,
774 {
775 self.into_partial_model().stream(db)
776 }
777}
778
779impl<S> Selector<S>
780where
781 S: SelectorTrait,
782{
783 /// Get the SQL statement
784 pub fn into_statement(self, builder: DbBackend) -> Statement {
785 builder.build(&self.query)
786 }
787
788 /// Get an item from the Select query
789 pub fn one<C>(mut self, db: &C) -> Result<Option<S::Item>, DbErr>
790 where
791 C: ConnectionTrait,
792 {
793 self.query.limit(1);
794 let row = db.query_one(&self.query)?;
795 match row {
796 Some(row) => Ok(Some(S::from_raw_query_result(row)?)),
797 None => Ok(None),
798 }
799 }
800
801 /// Get all items from the Select query
802 pub fn all<C>(self, db: &C) -> Result<Vec<S::Item>, DbErr>
803 where
804 C: ConnectionTrait,
805 {
806 db.query_all(&self.query)?
807 .into_iter()
808 .map(|row| S::from_raw_query_result(row))
809 .try_collect()
810 }
811
812 /// Stream the results of the Select operation
813 #[cfg(feature = "stream")]
814 pub fn stream<'a: 'b, 'b, C>(self, db: &'a C) -> Result<PinBoxStream<'b, S::Item>, DbErr>
815 where
816 C: ConnectionTrait + StreamTrait,
817 S: 'b,
818 {
819 let stream = db.stream(&self.query)?;
820
821 #[cfg(not(feature = "sync"))]
822 {
823 Ok(Box::new(stream.and_then(|row| {
824 futures_util::future::ready(S::from_raw_query_result(row))
825 })))
826 }
827 #[cfg(feature = "sync")]
828 {
829 Ok(Box::new(
830 stream.map(|item| item.and_then(S::from_raw_query_result)),
831 ))
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 /// # #[cfg(feature = "mock")]
855 /// # pub fn main() -> Result<(), DbErr> {
856 /// #
857 /// # let db = MockDatabase::new(DbBackend::Postgres)
858 /// # .append_query_results([[
859 /// # maplit::btreemap! {
860 /// # "name" => Into::<Value>::into("Chocolate Forest"),
861 /// # "num_of_cakes" => Into::<Value>::into(1),
862 /// # },
863 /// # maplit::btreemap! {
864 /// # "name" => Into::<Value>::into("New York Cheese"),
865 /// # "num_of_cakes" => Into::<Value>::into(1),
866 /// # },
867 /// # ]])
868 /// # .into_connection();
869 /// #
870 /// use sea_orm::{FromQueryResult, entity::*, query::*, tests_cfg::cake};
871 ///
872 /// #[derive(Debug, PartialEq, FromQueryResult)]
873 /// struct SelectResult {
874 /// name: String,
875 /// num_of_cakes: i32,
876 /// }
877 ///
878 /// let res: Vec<SelectResult> = cake::Entity::find()
879 /// .from_raw_sql(Statement::from_sql_and_values(
880 /// DbBackend::Postgres,
881 /// r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
882 /// [],
883 /// ))
884 /// .into_model::<SelectResult>()
885 /// .all(&db)?;
886 ///
887 /// assert_eq!(
888 /// res,
889 /// [
890 /// SelectResult {
891 /// name: "Chocolate Forest".to_owned(),
892 /// num_of_cakes: 1,
893 /// },
894 /// SelectResult {
895 /// name: "New York Cheese".to_owned(),
896 /// num_of_cakes: 1,
897 /// },
898 /// ]
899 /// );
900 ///
901 /// assert_eq!(
902 /// db.into_transaction_log(),
903 /// [Transaction::from_sql_and_values(
904 /// DbBackend::Postgres,
905 /// r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
906 /// []
907 /// ),]
908 /// );
909 /// #
910 /// # Ok(())
911 /// # }
912 /// ```
913 pub fn into_model<M>(self) -> SelectorRaw<SelectModel<M>>
914 where
915 M: FromQueryResult,
916 {
917 SelectorRaw {
918 stmt: self.stmt,
919 selector: PhantomData,
920 }
921 }
922
923 /// ```
924 /// # use sea_orm::{error::*, tests_cfg::*, *};
925 /// #
926 /// # #[cfg(feature = "mock")]
927 /// # pub fn main() -> Result<(), DbErr> {
928 /// #
929 /// # let db = MockDatabase::new(DbBackend::Postgres)
930 /// # .append_query_results([[
931 /// # maplit::btreemap! {
932 /// # "name" => Into::<Value>::into("Chocolate Forest"),
933 /// # "num_of_cakes" => Into::<Value>::into(1),
934 /// # },
935 /// # maplit::btreemap! {
936 /// # "name" => Into::<Value>::into("New York Cheese"),
937 /// # "num_of_cakes" => Into::<Value>::into(1),
938 /// # },
939 /// # ]])
940 /// # .into_connection();
941 /// #
942 /// use sea_orm::{entity::*, query::*, tests_cfg::cake};
943 ///
944 /// let res: Vec<serde_json::Value> = cake::Entity::find().from_raw_sql(
945 /// Statement::from_sql_and_values(
946 /// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, []
947 /// )
948 /// )
949 /// .into_json()
950 /// .all(&db)
951 /// ?;
952 ///
953 /// assert_eq!(
954 /// res,
955 /// [
956 /// serde_json::json!({
957 /// "name": "Chocolate Forest",
958 /// "num_of_cakes": 1,
959 /// }),
960 /// serde_json::json!({
961 /// "name": "New York Cheese",
962 /// "num_of_cakes": 1,
963 /// }),
964 /// ]
965 /// );
966 ///
967 /// assert_eq!(
968 /// db.into_transaction_log(),
969 /// [
970 /// Transaction::from_sql_and_values(
971 /// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, []
972 /// ),
973 /// ]);
974 /// #
975 /// # Ok(())
976 /// # }
977 /// ```
978 #[cfg(feature = "with-json")]
979 pub fn into_json(self) -> SelectorRaw<SelectModel<JsonValue>> {
980 SelectorRaw {
981 stmt: self.stmt,
982 selector: PhantomData,
983 }
984 }
985
986 /// Get the SQL statement
987 pub fn into_statement(self) -> Statement {
988 self.stmt
989 }
990
991 /// Get an item from the Select query
992 /// ```
993 /// # use sea_orm::{error::*, tests_cfg::*, *};
994 /// #
995 /// # #[cfg(feature = "mock")]
996 /// # pub fn main() -> Result<(), DbErr> {
997 /// #
998 /// # let db = MockDatabase::new(DbBackend::Postgres)
999 /// # .append_query_results([
1000 /// # [cake::Model {
1001 /// # id: 1,
1002 /// # name: "Cake".to_owned(),
1003 /// # }],
1004 /// # ])
1005 /// # .into_connection();
1006 /// #
1007 /// use sea_orm::{entity::*, query::*, raw_sql, tests_cfg::cake};
1008 ///
1009 /// let id = 1;
1010 ///
1011 /// let _: Option<cake::Model> = cake::Entity::find()
1012 /// .from_raw_sql(raw_sql!(
1013 /// Postgres,
1014 /// r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "id" = {id}"#
1015 /// ))
1016 /// .one(&db)?;
1017 ///
1018 /// assert_eq!(
1019 /// db.into_transaction_log(),
1020 /// [Transaction::from_sql_and_values(
1021 /// DbBackend::Postgres,
1022 /// r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "id" = $1"#,
1023 /// [1.into()]
1024 /// ),]
1025 /// );
1026 /// #
1027 /// # Ok(())
1028 /// # }
1029 /// ```
1030 pub fn one<C>(self, db: &C) -> Result<Option<S::Item>, DbErr>
1031 where
1032 C: ConnectionTrait,
1033 {
1034 let row = db.query_one_raw(self.stmt)?;
1035 match row {
1036 Some(row) => Ok(Some(S::from_raw_query_result(row)?)),
1037 None => Ok(None),
1038 }
1039 }
1040
1041 /// Get all items from the Select query
1042 /// ```
1043 /// # use sea_orm::{error::*, tests_cfg::*, *};
1044 /// #
1045 /// # #[cfg(feature = "mock")]
1046 /// # pub fn main() -> Result<(), DbErr> {
1047 /// #
1048 /// # let db = MockDatabase::new(DbBackend::Postgres)
1049 /// # .append_query_results([
1050 /// # [cake::Model {
1051 /// # id: 1,
1052 /// # name: "Cake".to_owned(),
1053 /// # }],
1054 /// # ])
1055 /// # .into_connection();
1056 /// #
1057 /// use sea_orm::{entity::*, query::*, raw_sql, tests_cfg::cake};
1058 ///
1059 /// let _: Vec<cake::Model> = cake::Entity::find()
1060 /// .from_raw_sql(raw_sql!(
1061 /// Postgres,
1062 /// r#"SELECT "cake"."id", "cake"."name" FROM "cake""#
1063 /// ))
1064 /// .all(&db)?;
1065 ///
1066 /// assert_eq!(
1067 /// db.into_transaction_log(),
1068 /// [Transaction::from_sql_and_values(
1069 /// DbBackend::Postgres,
1070 /// r#"SELECT "cake"."id", "cake"."name" FROM "cake""#,
1071 /// []
1072 /// ),]
1073 /// );
1074 /// #
1075 /// # Ok(())
1076 /// # }
1077 /// ```
1078 pub fn all<C>(self, db: &C) -> Result<Vec<S::Item>, DbErr>
1079 where
1080 C: ConnectionTrait,
1081 {
1082 db.query_all_raw(self.stmt)?
1083 .into_iter()
1084 .map(|row| S::from_raw_query_result(row))
1085 .try_collect()
1086 }
1087
1088 /// Stream the results of the Select operation
1089 #[cfg(feature = "stream")]
1090 pub fn stream<'a: 'b, 'b, C>(self, db: &'a C) -> Result<PinBoxStream<'b, S::Item>, DbErr>
1091 where
1092 C: ConnectionTrait + StreamTrait,
1093 S: 'b,
1094 {
1095 let stream = db.stream_raw(self.stmt)?;
1096
1097 #[cfg(not(feature = "sync"))]
1098 {
1099 Ok(Box::new(stream.and_then(|row| {
1100 futures_util::future::ready(S::from_raw_query_result(row))
1101 })))
1102 }
1103 #[cfg(feature = "sync")]
1104 {
1105 Ok(Box::new(
1106 stream.map(|item| item.and_then(S::from_raw_query_result)),
1107 ))
1108 }
1109 }
1110}