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