Skip to main content

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}