Skip to main content

sea_orm/query/
select.rs

1use crate::{
2    ColumnTrait, EntityTrait, Iterable, Order, PrimaryKeyToColumn, QueryFilter, QueryOrder,
3    QuerySelect, QueryTrait,
4};
5use core::fmt::Debug;
6use core::marker::PhantomData;
7use sea_query::{FunctionCall, IntoColumnRef, IntoIden, SelectExpr, SelectStatement, SimpleExpr};
8
9/// A `SELECT` query against entity `E`. Returned by
10/// [`EntityTrait::find`](crate::EntityTrait::find); chain filters, joins,
11/// ordering, and projections onto it, then run it on a
12/// [`ConnectionTrait`](crate::ConnectionTrait) with `.one(db)` /
13/// `.all(db)` / `.stream(db)` / `.paginate(db, n)`.
14#[derive(Clone, Debug)]
15pub struct Select<E>
16where
17    E: EntityTrait,
18{
19    pub(crate) query: SelectStatement,
20    pub(crate) entity: PhantomData<E>,
21    pub(crate) linked_index: usize,
22}
23
24/// A `SELECT` joining two entities, yielding `(E::Model, Option<F::Model>)`
25/// per row — the right side is `None` for outer-join rows with no match.
26/// Returned by [`Select::find_also_related`] and similar helpers.
27#[derive(Clone, Debug)]
28pub struct SelectTwo<E, F>
29where
30    E: EntityTrait,
31    F: EntityTrait,
32{
33    pub(crate) query: SelectStatement,
34    pub(crate) entity: PhantomData<(E, F)>,
35}
36
37/// A `SELECT` joining two entities, with results grouped into
38/// `(E::Model, Vec<F::Model>)` per left model. Returned by
39/// [`Select::find_with_related`].
40#[derive(Clone, Debug)]
41pub struct SelectTwoMany<E, F>
42where
43    E: EntityTrait,
44    F: EntityTrait,
45{
46    pub(crate) query: SelectStatement,
47    pub(crate) entity: PhantomData<(E, F)>,
48}
49
50/// A `SELECT` joining two entities where both sides are required, yielding
51/// `(E::Model, F::Model)` per row (no `Option`).
52#[derive(Clone, Debug)]
53pub struct SelectTwoRequired<E, F>
54where
55    E: EntityTrait,
56    F: EntityTrait,
57{
58    pub(crate) query: SelectStatement,
59    pub(crate) entity: PhantomData<(E, F)>,
60}
61
62/// Marker trait describing how 3+ tables are joined: from one centre entity
63/// to several siblings ([`TopologyStar`]) or in a sequential chain
64/// ([`TopologyChain`]).
65pub trait Topology {}
66
67/// Star join: a centre entity joined separately to each of the others.
68#[derive(Debug, Clone)]
69pub struct TopologyStar;
70
71/// Chain join: each entity joined to the previous one in sequence.
72#[derive(Debug, Clone)]
73pub struct TopologyChain;
74
75impl Topology for TopologyStar {}
76impl Topology for TopologyChain {}
77
78/// Three-way join select, yielding `(E::Model, Option<F::Model>, Option<G::Model>)`.
79/// The `TOP` parameter is the join [`Topology`].
80#[derive(Clone, Debug)]
81pub struct SelectThree<E, F, G, TOP>
82where
83    E: EntityTrait,
84    F: EntityTrait,
85    G: EntityTrait,
86    TOP: Topology,
87{
88    pub(crate) query: SelectStatement,
89    pub(crate) entity: PhantomData<(E, F, G, TOP)>,
90}
91
92/// Like [`SelectThree`], but results are consolidated under the left model:
93/// `(E::Model, Vec<F::Model>, Vec<G::Model>)`.
94#[derive(Clone, Debug)]
95pub struct SelectThreeMany<E, F, G, TOP>
96where
97    E: EntityTrait,
98    F: EntityTrait,
99    G: EntityTrait,
100    TOP: Topology,
101{
102    pub(crate) query: SelectStatement,
103    pub(crate) entity: PhantomData<(E, F, G, TOP)>,
104}
105
106/// Four-way join select.
107#[derive(Clone, Debug)]
108pub struct SelectFour<E, F, G, H, TOP>
109where
110    E: EntityTrait,
111    F: EntityTrait,
112    G: EntityTrait,
113    H: EntityTrait,
114    TOP: Topology,
115{
116    pub(crate) query: SelectStatement,
117    pub(crate) entity: PhantomData<(E, F, G, H, TOP)>,
118}
119
120/// Like [`SelectFour`], but results are consolidated under the left model.
121#[derive(Clone, Debug)]
122pub struct SelectFourMany<E, F, G, H, TOP>
123where
124    E: EntityTrait,
125    F: EntityTrait,
126    G: EntityTrait,
127    H: EntityTrait,
128    TOP: Topology,
129{
130    pub(crate) query: SelectStatement,
131    pub(crate) entity: PhantomData<(E, F, G, H, TOP)>,
132}
133
134/// Five-way join select.
135#[derive(Clone, Debug)]
136pub struct SelectFive<E, F, G, H, I, TOP>
137where
138    E: EntityTrait,
139    F: EntityTrait,
140    G: EntityTrait,
141    H: EntityTrait,
142    I: EntityTrait,
143    TOP: Topology,
144{
145    pub(crate) query: SelectStatement,
146    pub(crate) entity: PhantomData<(E, F, G, H, I, TOP)>,
147}
148
149/// Six-way join select.
150#[derive(Clone, Debug)]
151pub struct SelectSix<E, F, G, H, I, J, TOP>
152where
153    E: EntityTrait,
154    F: EntityTrait,
155    G: EntityTrait,
156    H: EntityTrait,
157    I: EntityTrait,
158    J: EntityTrait,
159    TOP: Topology,
160{
161    pub(crate) query: SelectStatement,
162    pub(crate) entity: PhantomData<(E, F, G, H, I, J, TOP)>,
163}
164
165/// Conversion into a [`SimpleExpr`]. Implemented for entity columns so they
166/// can be used anywhere a `sea_query` expression is expected.
167pub trait IntoSimpleExpr {
168    /// Build the [`SimpleExpr`].
169    fn into_simple_expr(self) -> SimpleExpr;
170}
171
172/// Like [`IntoSimpleExpr`] but applies SeaORM's enum-to-text cast for
173/// `ActiveEnum` columns appearing in a SELECT list.
174pub trait ColumnAsExpr: IntoSimpleExpr {
175    /// Build the [`SimpleExpr`], casting `ActiveEnum` columns to text;
176    /// otherwise identical to [`IntoSimpleExpr::into_simple_expr`].
177    fn into_column_as_expr(self) -> SimpleExpr;
178}
179
180macro_rules! impl_query_trait {
181    ( $trait: ident ) => {
182        impl<E> $trait for Select<E>
183        where
184            E: EntityTrait,
185        {
186            type QueryStatement = SelectStatement;
187
188            fn query(&mut self) -> &mut SelectStatement {
189                &mut self.query
190            }
191        }
192
193        impl<E, F> $trait for SelectTwo<E, F>
194        where
195            E: EntityTrait,
196            F: EntityTrait,
197        {
198            type QueryStatement = SelectStatement;
199
200            fn query(&mut self) -> &mut SelectStatement {
201                &mut self.query
202            }
203        }
204
205        impl<E, F> $trait for SelectTwoMany<E, F>
206        where
207            E: EntityTrait,
208            F: EntityTrait,
209        {
210            type QueryStatement = SelectStatement;
211
212            fn query(&mut self) -> &mut SelectStatement {
213                &mut self.query
214            }
215        }
216
217        impl<E, F> $trait for SelectTwoRequired<E, F>
218        where
219            E: EntityTrait,
220            F: EntityTrait,
221        {
222            type QueryStatement = SelectStatement;
223
224            fn query(&mut self) -> &mut SelectStatement {
225                &mut self.query
226            }
227        }
228    };
229}
230
231impl_query_trait!(QuerySelect);
232impl_query_trait!(QueryFilter);
233impl_query_trait!(QueryOrder);
234
235impl<C> ColumnAsExpr for C
236where
237    C: ColumnTrait,
238{
239    fn into_column_as_expr(self) -> SimpleExpr {
240        self.select_as(self.as_column_ref().into_column_ref().into())
241    }
242}
243
244impl ColumnAsExpr for SimpleExpr {
245    fn into_column_as_expr(self) -> SimpleExpr {
246        self.into_simple_expr()
247    }
248}
249
250impl<C> IntoSimpleExpr for C
251where
252    C: ColumnTrait,
253{
254    fn into_simple_expr(self) -> SimpleExpr {
255        SimpleExpr::Column(self.as_column_ref().into_column_ref())
256    }
257}
258
259impl IntoSimpleExpr for SimpleExpr {
260    fn into_simple_expr(self) -> SimpleExpr {
261        self
262    }
263}
264
265impl IntoSimpleExpr for FunctionCall {
266    fn into_simple_expr(self) -> SimpleExpr {
267        SimpleExpr::FunctionCall(self)
268    }
269}
270
271pub(crate) trait ColumnSelectExt: ColumnTrait {
272    fn into_select_expr(self) -> SelectExpr;
273}
274
275impl<C> ColumnSelectExt for C
276where
277    C: ColumnTrait,
278{
279    fn into_select_expr(self) -> SelectExpr {
280        let column = self.into_expr();
281        let expr = self.select_as(column.clone());
282
283        let alias = match &expr {
284            SimpleExpr::Column(_) if expr == column => None,
285            SimpleExpr::AsEnum(_, inner) if inner.as_ref() == &column => None,
286            _ => Some(self.as_str().into_iden()),
287        };
288
289        SelectExpr {
290            expr,
291            alias,
292            window: None,
293        }
294    }
295}
296
297impl<E> Select<E>
298where
299    E: EntityTrait,
300{
301    pub(crate) fn new() -> Self {
302        Self {
303            query: SelectStatement::new(),
304            entity: PhantomData,
305            linked_index: 0,
306        }
307        .prepare_select()
308        .prepare_from()
309    }
310
311    fn prepare_select(mut self) -> Self {
312        self.query.exprs(self.column_list());
313        self
314    }
315
316    fn column_list(&self) -> Vec<SelectExpr> {
317        E::Column::iter()
318            .map(ColumnSelectExt::into_select_expr)
319            .collect()
320    }
321
322    fn prepare_from(mut self) -> Self {
323        self.query.from(E::default().table_ref());
324        self
325    }
326
327    /// Apply order by primary key to the query statement
328    pub fn order_by_id_asc(self) -> Self {
329        self.order_by_id(Order::Asc)
330    }
331
332    /// Apply order by primary key to the query statement
333    pub fn order_by_id_desc(self) -> Self {
334        self.order_by_id(Order::Desc)
335    }
336
337    /// Apply order by primary key to the query statement
338    pub fn order_by_id(mut self, order: Order) -> Self {
339        for key in E::PrimaryKey::iter() {
340            let col = key.into_column();
341            self.query
342                .order_by_expr(col.into_simple_expr(), order.clone());
343        }
344        self
345    }
346}
347
348impl<E> QueryTrait for Select<E>
349where
350    E: EntityTrait,
351{
352    type QueryStatement = SelectStatement;
353    fn query(&mut self) -> &mut SelectStatement {
354        &mut self.query
355    }
356    fn as_query(&self) -> &SelectStatement {
357        &self.query
358    }
359    fn into_query(self) -> SelectStatement {
360        self.query
361    }
362}
363
364macro_rules! select_two {
365    ( $selector: ident ) => {
366        impl<E, F> QueryTrait for $selector<E, F>
367        where
368            E: EntityTrait,
369            F: EntityTrait,
370        {
371            type QueryStatement = SelectStatement;
372            fn query(&mut self) -> &mut SelectStatement {
373                &mut self.query
374            }
375            fn as_query(&self) -> &SelectStatement {
376                &self.query
377            }
378            fn into_query(self) -> SelectStatement {
379                self.query
380            }
381        }
382    };
383}
384
385select_two!(SelectTwo);
386select_two!(SelectTwoMany);
387select_two!(SelectTwoRequired);