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