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