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