toasty_core/stmt/
insert.rs

1use super::{InsertTarget, Node, Query, Returning, Statement, Visit, VisitMut};
2use crate::stmt;
3
4/// An `INSERT` statement that creates new records.
5///
6/// Combines an [`InsertTarget`] (where to insert), a [`Query`] source
7/// (the values to insert), and an optional [`Returning`] clause.
8///
9/// # Examples
10///
11/// ```ignore
12/// use toasty_core::stmt::{Insert, InsertTarget, Query, Values, Expr};
13/// use toasty_core::schema::app::ModelId;
14///
15/// let insert = Insert {
16///     target: InsertTarget::Model(ModelId(0)),
17///     source: Query::values(Values::new(vec![Expr::null()])),
18///     returning: None,
19/// };
20/// assert!(insert.target.is_model());
21/// ```
22#[derive(Debug, Clone, PartialEq)]
23pub struct Insert {
24    /// The target to insert into (model, table, or scoped query).
25    pub target: InsertTarget,
26
27    /// The source query providing values to insert.
28    pub source: Query,
29
30    /// Optional `RETURNING` clause to return data from the insertion.
31    pub returning: Option<Returning>,
32}
33
34impl Insert {
35    /// Merges another `Insert` into this one by appending its value rows.
36    ///
37    /// Both inserts must target the same model, and both sources must be
38    /// `VALUES` expressions.
39    pub fn merge(&mut self, other: Self) {
40        match (&self.target, &other.target) {
41            (InsertTarget::Model(a), InsertTarget::Model(b)) if a == b => {}
42            _ => todo!("handle this case"),
43        }
44
45        match (&mut self.source.body, other.source.body) {
46            (stmt::ExprSet::Values(self_values), stmt::ExprSet::Values(other_values)) => {
47                for expr in other_values.rows {
48                    self_values.rows.push(expr);
49                }
50            }
51            (self_source, other) => todo!("self={:#?}; other={:#?}", self_source, other),
52        }
53    }
54}
55
56impl Statement {
57    /// Returns `true` if this statement is an [`Insert`].
58    pub fn is_insert(&self) -> bool {
59        matches!(self, Statement::Insert(..))
60    }
61
62    /// Attempts to return a reference to an inner [`Insert`].
63    ///
64    /// * If `self` is a [`Statement::Insert`], a reference to the inner [`Insert`] is
65    ///   returned wrapped in [`Some`].
66    /// * Else, [`None`] is returned.
67    pub fn as_insert(&self) -> Option<&Insert> {
68        match self {
69            Self::Insert(insert) => Some(insert),
70            _ => None,
71        }
72    }
73
74    /// Consumes `self` and attempts to return the inner [`Insert`].
75    ///
76    /// * If `self` is a [`Statement::Insert`], inner [`Insert`] is returned wrapped in
77    ///   [`Some`].
78    /// * Else, [`None`] is returned.
79    pub fn into_insert(self) -> Option<Insert> {
80        match self {
81            Self::Insert(insert) => Some(insert),
82            _ => None,
83        }
84    }
85
86    /// Consumes `self` and returns the inner [`Insert`].
87    ///
88    /// # Panics
89    ///
90    /// If `self` is not a [`Statement::Insert`].
91    pub fn into_insert_unwrap(self) -> Insert {
92        match self {
93            Self::Insert(insert) => insert,
94            v => panic!("expected `Insert`, found {v:#?}"),
95        }
96    }
97}
98
99impl From<Insert> for Statement {
100    fn from(src: Insert) -> Self {
101        Self::Insert(src)
102    }
103}
104
105impl Node for Insert {
106    fn visit<V: Visit>(&self, mut visit: V) {
107        visit.visit_stmt_insert(self);
108    }
109
110    fn visit_mut<V: VisitMut>(&mut self, mut visit: V) {
111        visit.visit_stmt_insert_mut(self);
112    }
113}