toasty_core/stmt/
select.rs

1use super::{Node, Path, Query, Returning, Source, SourceModel, Statement, Visit, VisitMut};
2use crate::{
3    schema::db::TableId,
4    stmt::{ExprSet, Filter},
5};
6
7#[derive(Debug, Clone, PartialEq)]
8pub struct Select {
9    /// The projection part of a SQL query.
10    pub returning: Returning,
11
12    /// The `FROM` part of a SQL query. For model-level, this is the model being
13    /// selected with any "includes". For table-level, this is the table with
14    /// joins.
15    pub source: Source,
16
17    /// Query filter
18    pub filter: Filter,
19}
20
21impl Select {
22    pub fn new(source: impl Into<Source>, filter: impl Into<Filter>) -> Self {
23        Self {
24            returning: Returning::Model { include: vec![] },
25            source: source.into(),
26            filter: filter.into(),
27        }
28    }
29
30    pub(crate) fn include(&mut self, path: impl Into<Path>) {
31        match &mut self.returning {
32            Returning::Model { include } => include.push(path.into()),
33            _ => panic!("Expected Returning::Model for include operation"),
34        }
35    }
36
37    pub fn add_filter(&mut self, filter: impl Into<Filter>) {
38        self.filter.add_filter(filter);
39    }
40}
41
42impl Statement {
43    pub fn as_select(&self) -> Option<&Select> {
44        self.as_query().and_then(|query| query.body.as_select())
45    }
46
47    #[track_caller]
48    pub fn as_select_unwrap(&self) -> &Select {
49        match self {
50            Statement::Query(query) => match &query.body {
51                ExprSet::Select(select) => select,
52                _ => todo!("expected `Select`; actual={self:#?}"),
53            },
54            _ => todo!("expected `Select`; actual={self:#?}"),
55        }
56    }
57}
58
59impl Query {
60    pub fn into_select(self) -> Select {
61        self.body.into_select()
62    }
63}
64
65impl ExprSet {
66    pub fn as_select(&self) -> Option<&Select> {
67        match self {
68            Self::Select(expr) => Some(expr),
69            _ => None,
70        }
71    }
72
73    #[track_caller]
74    pub fn as_select_unwrap(&self) -> &Select {
75        self.as_select()
76            .unwrap_or_else(|| panic!("expected `Select`; actual={self:#?}"))
77    }
78
79    pub fn as_select_mut(&mut self) -> Option<&mut Select> {
80        match self {
81            Self::Select(expr) => Some(expr),
82            _ => None,
83        }
84    }
85
86    pub fn as_select_mut_unwrap(&mut self) -> &mut Select {
87        match self {
88            Self::Select(select) => select,
89            _ => panic!("expected `Select`; actual={self:#?}"),
90        }
91    }
92
93    #[track_caller]
94    pub fn into_select(self) -> Select {
95        match self {
96            Self::Select(expr) => *expr,
97            _ => todo!(),
98        }
99    }
100
101    pub fn is_select(&self) -> bool {
102        matches!(self, Self::Select(_))
103    }
104}
105
106impl From<Select> for Statement {
107    fn from(value: Select) -> Self {
108        Self::Query(value.into())
109    }
110}
111
112impl From<Select> for Query {
113    fn from(value: Select) -> Self {
114        Self::builder(value).build()
115    }
116}
117
118impl From<TableId> for Select {
119    fn from(value: TableId) -> Self {
120        Self::new(Source::table(value), true)
121    }
122}
123
124impl From<SourceModel> for Select {
125    fn from(value: SourceModel) -> Self {
126        Self::new(Source::Model(value), true)
127    }
128}
129
130impl Node for Select {
131    fn visit<V: Visit>(&self, mut visit: V) {
132        visit.visit_stmt_select(self);
133    }
134
135    fn visit_mut<V: VisitMut>(&mut self, mut visit: V) {
136        visit.visit_stmt_select_mut(self);
137    }
138}