Skip to main content

toasty_core/stmt/
expr_set.rs

1use std::fmt;
2
3use super::{Delete, Expr, ExprSetOp, Insert, Select, SourceModel, Update, Values};
4use crate::schema::db::TableId;
5
6/// A set of rows produced by a query, set operation, or explicit values.
7///
8/// Represents the different ways to produce a collection of rows in SQL.
9///
10/// # Examples
11///
12/// ```text
13/// SELECT * FROM users           // ExprSet::Select
14/// SELECT ... UNION SELECT ...   // ExprSet::SetOp
15/// VALUES (1, 'a'), (2, 'b')     // ExprSet::Values
16/// ```
17#[derive(Clone, PartialEq)]
18pub enum ExprSet {
19    /// A select query, possibly with a filter.
20    Select(Box<Select>),
21
22    /// A set operation (union, intersection, ...) on two queries.
23    SetOp(ExprSetOp),
24
25    /// An update expression.
26    Update(Box<Update>),
27
28    /// A delete expression (used as a data-modifying CTE for conditional deletes).
29    Delete(Box<Delete>),
30
31    /// Explicitly listed values (as expressions).
32    Values(Values),
33
34    /// An insert statement (used for UNION-style batch inserts)
35    Insert(Box<Insert>),
36}
37
38impl ExprSet {
39    /// Creates an `ExprSet::Values` from explicit values.
40    pub fn values(values: impl Into<Values>) -> ExprSet {
41        ExprSet::Values(values.into())
42    }
43
44    /// Returns `true` if this is an [`ExprSet::Values`] variant.
45    ///
46    /// # Examples
47    ///
48    /// ```
49    /// # use toasty_core::stmt::{ExprSet, Values};
50    /// let values = ExprSet::values(Values::default());
51    /// assert!(values.is_values());
52    ///
53    /// let select = ExprSet::from(toasty_core::schema::db::TableId(0));
54    /// assert!(!select.is_values());
55    /// ```
56    pub fn is_values(&self) -> bool {
57        matches!(self, ExprSet::Values(_))
58    }
59
60    /// Returns a reference to the inner [`Values`] if this is an [`ExprSet::Values`].
61    ///
62    /// Returns `None` for all other [`ExprSet`] variants.
63    #[track_caller]
64    pub fn as_values(&self) -> Option<&Values> {
65        match self {
66            Self::Values(values) => Some(values),
67            _ => None,
68        }
69    }
70
71    /// Returns a reference to the inner [`Values`].
72    ///
73    /// # Panics
74    ///
75    /// Panics if `self` is not an [`ExprSet::Values`].
76    #[track_caller]
77    pub fn as_values_unwrap(&self) -> &Values {
78        self.as_values()
79            .unwrap_or_else(|| panic!("expected `Values`, found {self:#?}"))
80    }
81
82    /// Returns a mutable reference to the inner [`Values`] if this is an
83    /// [`ExprSet::Values`], or `None` otherwise.
84    pub fn as_values_mut(&mut self) -> Option<&mut Values> {
85        match self {
86            Self::Values(expr) => Some(expr),
87            _ => None,
88        }
89    }
90
91    /// Returns a mutable reference to the inner [`Values`].
92    ///
93    /// # Panics
94    ///
95    /// Panics if `self` is not an [`ExprSet::Values`].
96    #[track_caller]
97    pub fn as_values_mut_unwrap(&mut self) -> &mut Values {
98        match self {
99            Self::Values(expr) => expr,
100            _ => panic!("expected `Values`; actual={self:#?}"),
101        }
102    }
103
104    /// Consumes the expression set and returns the inner [`Values`].
105    ///
106    /// # Panics
107    ///
108    /// Panics (via `todo!()`) if `self` is not an [`ExprSet::Values`].
109    #[track_caller]
110    pub fn into_values(self) -> Values {
111        match self {
112            Self::Values(expr) => expr,
113            _ => todo!(),
114        }
115    }
116
117    /// Returns `true` if this expression set contains only constant
118    /// expressions (no references, subqueries, or other external data).
119    pub fn is_const(&self) -> bool {
120        match self {
121            ExprSet::Select(..) => false,
122            ExprSet::SetOp(expr_set_op) => expr_set_op
123                .operands
124                .iter()
125                .all(|operand| operand.is_const()),
126            ExprSet::Update(..) => false,
127            ExprSet::Delete(..) => false,
128            ExprSet::Values(values) => values.is_const(),
129            ExprSet::Insert(..) => false,
130        }
131    }
132}
133
134impl fmt::Debug for ExprSet {
135    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136        match self {
137            Self::Select(e) => e.fmt(f),
138            Self::SetOp(e) => e.fmt(f),
139            Self::Update(e) => e.fmt(f),
140            Self::Delete(e) => e.fmt(f),
141            Self::Values(e) => e.fmt(f),
142            Self::Insert(e) => e.fmt(f),
143        }
144    }
145}
146
147impl Default for ExprSet {
148    fn default() -> Self {
149        Self::Values(Values::default())
150    }
151}
152
153impl From<Select> for ExprSet {
154    fn from(value: Select) -> Self {
155        Self::Select(Box::new(value))
156    }
157}
158
159impl From<Update> for ExprSet {
160    fn from(value: Update) -> Self {
161        Self::Update(Box::new(value))
162    }
163}
164
165impl From<Delete> for ExprSet {
166    fn from(value: Delete) -> Self {
167        Self::Delete(Box::new(value))
168    }
169}
170
171impl From<Insert> for ExprSet {
172    fn from(value: Insert) -> Self {
173        Self::Insert(Box::new(value))
174    }
175}
176
177impl From<TableId> for ExprSet {
178    fn from(value: TableId) -> Self {
179        Self::Select(Box::new(Select::from(value)))
180    }
181}
182
183impl From<SourceModel> for ExprSet {
184    fn from(value: SourceModel) -> Self {
185        Self::Select(Box::new(Select::from(value)))
186    }
187}
188
189impl From<Vec<Expr>> for ExprSet {
190    fn from(value: Vec<Expr>) -> Self {
191        Self::Values(Values::new(value))
192    }
193}