sea_orm/entity/partial_model.rs
1use crate::{EntityTrait, FromQueryResult, IdenStatic, Iterable, ModelTrait, QuerySelect};
2use sea_query::Expr;
3
4/// A partial projection of a [`Model`](super::model::ModelTrait) — a struct
5/// that holds only some of the entity's columns, used to avoid overfetching
6/// in `SELECT` queries.
7///
8/// Derive it on a custom struct with `#[derive(DerivePartialModel)]` and
9/// `#[sea_orm(entity = "...")]`, then call
10/// [`Select::into_partial_model`](crate::Select::into_partial_model) to
11/// restrict the query to just those columns. Nested partial models can be
12/// composed with `#[sea_orm(nested)]` fields.
13pub trait PartialModelTrait: FromQueryResult {
14 /// Add the partial model's columns to a [`QuerySelect`]'s projection.
15 ///
16 /// No need to implement this method; implement `select_cols_nested` instead.
17 fn select_cols<S: QuerySelect>(select: S) -> S {
18 Self::select_cols_nested(select, None, None)
19 }
20
21 /// Used when nesting these structs into each other.
22 ///
23 /// Example impl
24 ///
25 /// ```ignore
26 /// fn select_cols_nested<S: QuerySelect>(mut select: S, prefix: Option<&str>) -> S {
27 /// if let Some(prefix) = prefix {
28 /// for col in <<T::Entity as EntityTrait>::Column as Iterable>::iter() {
29 /// let alias = format!("{prefix}{}", col.as_str());
30 /// select = select.column_as(col, alias);
31 /// }
32 /// } else {
33 /// for col in <<T::Entity as EntityTrait>::Column as Iterable>::iter() {
34 /// select = select.column(col);
35 /// }
36 /// }
37 /// select
38 /// }
39 /// ```
40 fn select_cols_nested<S: QuerySelect>(
41 select: S,
42 prefix: Option<&str>,
43 alias: Option<&'static str>,
44 ) -> S;
45}
46
47impl<T: PartialModelTrait> PartialModelTrait for Option<T> {
48 fn select_cols_nested<S: QuerySelect>(
49 select: S,
50 prefix: Option<&str>,
51 alias: Option<&'static str>,
52 ) -> S {
53 T::select_cols_nested(select, prefix, alias)
54 }
55}
56
57impl<T: ModelTrait + FromQueryResult> PartialModelTrait for T {
58 fn select_cols_nested<S: QuerySelect>(
59 mut select: S,
60 prefix: Option<&str>,
61 alias: Option<&'static str>,
62 ) -> S {
63 match (prefix, alias) {
64 (Some(prefix), Some(alias)) => {
65 for col in <<T::Entity as EntityTrait>::Column as Iterable>::iter() {
66 let select_as = format!("{prefix}{}", col.as_str());
67 select = select.column_as(Expr::col((alias, col)), select_as);
68 }
69 }
70 (Some(prefix), None) => {
71 for col in <<T::Entity as EntityTrait>::Column as Iterable>::iter() {
72 let select_as = format!("{prefix}{}", col.as_str());
73 select = select.column_as(col, select_as);
74 }
75 }
76 (None, Some(alias)) => {
77 for col in <<T::Entity as EntityTrait>::Column as Iterable>::iter() {
78 select = select.column_as(Expr::col((alias, col)), col.as_str());
79 }
80 }
81 (None, None) => {
82 for col in <<T::Entity as EntityTrait>::Column as Iterable>::iter() {
83 select = select.column(col);
84 }
85 }
86 }
87 select
88 }
89}