sqlint/ast/
insert.rs

1use crate::ast::*;
2use std::borrow::Cow;
3
4/// A builder for an `INSERT` statement.
5#[derive(Clone, Debug, PartialEq)]
6pub struct Insert<'a> {
7    pub(crate) table: Option<Table<'a>>,
8    pub(crate) columns: Vec<Column<'a>>,
9    pub(crate) values: Expression<'a>,
10    pub(crate) on_conflict: Option<OnConflict<'a>>,
11    pub(crate) returning: Option<Vec<Column<'a>>>,
12    pub(crate) comment: Option<Cow<'a, str>>,
13}
14
15/// A builder for an `INSERT` statement for a single row.
16#[derive(Clone, Debug, PartialEq)]
17pub struct SingleRowInsert<'a> {
18    pub(crate) table: Option<Table<'a>>,
19    pub(crate) columns: Vec<Column<'a>>,
20    pub(crate) values: Row<'a>,
21}
22
23/// A builder for an `INSERT` statement for multiple rows.
24#[derive(Clone, Debug, PartialEq)]
25pub struct MultiRowInsert<'a> {
26    pub(crate) table: Option<Table<'a>>,
27    pub(crate) columns: Vec<Column<'a>>,
28    pub(crate) values: Vec<Row<'a>>,
29}
30
31/// `INSERT` conflict resolution strategies.
32#[allow(clippy::large_enum_variant)]
33#[derive(Clone, Debug, PartialEq)]
34pub enum OnConflict<'a> {
35    /// When a row already exists, do nothing. Works with PostgreSQL, MySQL or
36    /// SQLite without schema information.
37    ///
38    /// ```rust
39    /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
40    /// # fn main() -> Result<(), sqlint::error::Error> {
41    /// let query: Insert = Insert::single_into("users").into();
42    /// let (sql, _) = Sqlite::build(query.on_conflict(OnConflict::DoNothing))?;
43    /// assert_eq!("INSERT OR IGNORE INTO `users` DEFAULT VALUES", sql);
44    /// # Ok(())
45    /// # }
46    /// ```
47    ///
48    /// With Microsoft SQL server not supporting `IGNORE` in the `INSERT`
49    /// statement, the `INSERT` is converted to a `MERGE` statement. For it to work
50    /// in a correct way, the table should know all unique indices of the actual table.
51    ///
52    /// In this example our `users` table holds one unique index for the `id` column.
53    ///
54    /// ```rust
55    /// # use sqlint::{ast::*, visitor::{Visitor, Mssql}};
56    /// # use indoc::indoc;
57    /// # fn main() -> Result<(), sqlint::error::Error> {
58    /// let id = Column::from("id").table("users");
59    /// let table = Table::from("users").add_unique_index(id.clone());
60    /// let query: Insert = Insert::single_into(table).value(id, 1).into();
61    /// let (sql, _) = Mssql::build(query.on_conflict(OnConflict::DoNothing))?;
62    ///
63    /// let expected_sql = indoc!(
64    ///     "
65    ///     MERGE INTO [users]
66    ///     USING (SELECT @P1 AS [id]) AS [dual] ([id])
67    ///     ON [dual].[id] = [users].[id]
68    ///     WHEN NOT MATCHED THEN
69    ///     INSERT ([id]) VALUES ([dual].[id]);
70    /// "
71    /// );
72    ///
73    /// assert_eq!(expected_sql.replace('\n', " ").trim(), sql);
74    /// # Ok(())
75    /// # }
76    /// ```
77    ///
78    /// If the `INSERT` statement misses a value for a unique column that does
79    /// not have default value set, the visitor will raise a panic. For compound
80    /// unique indices, the `add_unique_index` takes a vector as a parameter.
81    ///
82    /// If the [column has a default value], it should be added to the `Column`
83    /// definition to allow inserting missing unique values with the `Insert`
84    /// statement. If default is set to [`DefaultValue::Generated`], the value
85    /// is considered to be always unique and not added to the join.
86    ///
87    /// [`DefaultValue::Generated`]: enum.DefaultValue.html#variant.Generated
88    /// [column has a default value]: struct.Column.html#method.default
89    DoNothing,
90    /// ON CONFLICT UPDATE is supported for Sqlite and Postgres
91    Update(Update<'a>, Vec<Column<'a>>),
92}
93
94impl<'a> From<Insert<'a>> for Query<'a> {
95    fn from(insert: Insert<'a>) -> Self {
96        Query::Insert(Box::new(insert))
97    }
98}
99
100impl<'a> From<SingleRowInsert<'a>> for Insert<'a> {
101    fn from(insert: SingleRowInsert<'a>) -> Self {
102        let values =
103            if insert.values.is_empty() { Expression::from(Row::new()) } else { Expression::from(insert.values) };
104
105        Insert {
106            table: insert.table,
107            columns: insert.columns,
108            values,
109            on_conflict: None,
110            returning: None,
111            comment: None,
112        }
113    }
114}
115
116impl<'a> From<MultiRowInsert<'a>> for Insert<'a> {
117    fn from(insert: MultiRowInsert<'a>) -> Self {
118        let values = Expression::from(Values::new(insert.values));
119
120        Insert {
121            table: insert.table,
122            columns: insert.columns,
123            values,
124            on_conflict: None,
125            returning: None,
126            comment: None,
127        }
128    }
129}
130
131impl<'a> From<SingleRowInsert<'a>> for Query<'a> {
132    fn from(insert: SingleRowInsert<'a>) -> Query<'a> {
133        Query::from(Insert::from(insert))
134    }
135}
136
137impl<'a> From<MultiRowInsert<'a>> for Query<'a> {
138    fn from(insert: MultiRowInsert<'a>) -> Query<'a> {
139        Query::from(Insert::from(insert))
140    }
141}
142
143impl<'a> Insert<'a> {
144    /// Creates a new single row `INSERT` statement for the given table.
145    ///
146    /// ```rust
147    /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
148    /// # fn main() -> Result<(), sqlint::error::Error> {
149    /// let query = Insert::single_into("users");
150    /// let (sql, _) = Sqlite::build(query)?;
151    ///
152    /// assert_eq!("INSERT INTO `users` DEFAULT VALUES", sql);
153    /// # Ok(())
154    /// # }
155    /// ```
156    pub fn single_into<T>(table: T) -> SingleRowInsert<'a>
157    where
158        T: Into<Table<'a>>,
159    {
160        SingleRowInsert { table: Some(table.into()), columns: Vec::new(), values: Row::new() }
161    }
162
163    pub fn single() -> SingleRowInsert<'a> {
164        SingleRowInsert { table: None, columns: Vec::new(), values: Row::new() }
165    }
166
167    /// Creates a new multi row `INSERT` statement for the given table.
168    pub fn multi_into<T, K, I>(table: T, columns: I) -> MultiRowInsert<'a>
169    where
170        T: Into<Table<'a>>,
171        K: Into<Column<'a>>,
172        I: IntoIterator<Item = K>,
173    {
174        MultiRowInsert {
175            table: Some(table.into()),
176            columns: columns.into_iter().map(|c| c.into()).collect(),
177            values: Vec::new(),
178        }
179    }
180
181    pub fn multi<K, I>(columns: I) -> MultiRowInsert<'a>
182    where
183        K: Into<Column<'a>>,
184        I: IntoIterator<Item = K>,
185    {
186        MultiRowInsert { table: None, columns: columns.into_iter().map(|c| c.into()).collect(), values: Vec::new() }
187    }
188
189    pub fn expression_into<T, I, K, E>(table: T, columns: I, expression: E) -> Self
190    where
191        T: Into<Table<'a>>,
192        I: IntoIterator<Item = K>,
193        K: Into<Column<'a>>,
194        E: Into<Expression<'a>>,
195    {
196        Insert {
197            table: Some(table.into()),
198            columns: columns.into_iter().map(|c| c.into()).collect(),
199            values: expression.into(),
200            on_conflict: None,
201            returning: None,
202            comment: None,
203        }
204    }
205
206    /// Sets the conflict resolution strategy.
207    pub fn on_conflict(mut self, on_conflict: OnConflict<'a>) -> Self {
208        self.on_conflict = Some(on_conflict);
209        self
210    }
211
212    /// Adds a comment to the insert.
213    ///
214    /// ```rust
215    /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
216    /// # fn main() -> Result<(), sqlint::error::Error> {
217    /// let query = Insert::single_into("users");
218    /// let insert = Insert::from(query).comment("trace_id='5bd66ef5095369c7b0d1f8f4bd33716a', parent_id='c532cb4098ac3dd2'");
219    /// let (sql, _) = Sqlite::build(insert)?;
220    ///
221    /// assert_eq!("INSERT INTO `users` DEFAULT VALUES; /* trace_id='5bd66ef5095369c7b0d1f8f4bd33716a', parent_id='c532cb4098ac3dd2' */", sql);
222    /// # Ok(())
223    /// # }
224    /// ```
225    pub fn comment<C: Into<Cow<'a, str>>>(mut self, comment: C) -> Self {
226        self.comment = Some(comment.into());
227        self
228    }
229
230    /// Sets the returned columns.
231    ///
232    /// ```rust
233    /// # use sqlint::{ast::*, visitor::{Visitor, Postgres}};
234    /// # fn main() -> Result<(), sqlint::error::Error> {
235    /// let query = Insert::single_into("users");
236    /// let insert = Insert::from(query).returning(vec!["id"]);
237    /// let (sql, _) = Postgres::build(insert)?;
238    ///
239    /// assert_eq!("INSERT INTO \"users\" DEFAULT VALUES RETURNING \"id\"", sql);
240    /// # Ok(())
241    /// # }
242    /// ```
243    #[cfg(any(feature = "postgresql", feature = "mssql", feature = "sqlite"))]
244    #[cfg_attr(feature = "docs", doc(cfg(any(feature = "postgresql", feature = "mssql", feature = "sqlite"))))]
245    pub fn returning<K, I>(mut self, columns: I) -> Self
246    where
247        K: Into<Column<'a>>,
248        I: IntoIterator<Item = K>,
249    {
250        self.returning = Some(columns.into_iter().map(|k| k.into()).collect());
251        self
252    }
253}
254
255impl<'a> SingleRowInsert<'a> {
256    /// Adds a new value to the `INSERT` statement
257    ///
258    /// ```rust
259    /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
260    /// # fn main() -> Result<(), sqlint::error::Error> {
261    /// let query = Insert::single_into("users").value("foo", 10);
262    /// let (sql, params) = Sqlite::build(query)?;
263    ///
264    /// assert_eq!("INSERT INTO `users` (`foo`) VALUES (?)", sql);
265    /// assert_eq!(vec![Value::from(10)], params);
266    /// # Ok(())
267    /// # }
268    /// ```
269    pub fn value<K, V>(mut self, key: K, val: V) -> SingleRowInsert<'a>
270    where
271        K: Into<Column<'a>>,
272        V: Into<Expression<'a>>,
273    {
274        self.columns.push(key.into());
275        self.values.push(val.into());
276
277        self
278    }
279
280    /// Convert into a common `Insert` statement.
281    pub fn build(self) -> Insert<'a> {
282        Insert::from(self)
283    }
284}
285
286impl<'a> MultiRowInsert<'a> {
287    /// Adds a new row to be inserted.
288    ///
289    /// ```rust
290    /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
291    /// # fn main() -> Result<(), sqlint::error::Error> {
292    /// let query = Insert::multi_into("users", vec!["foo"])
293    ///     .values(vec![1])
294    ///     .values(vec![2]);
295    ///
296    /// let (sql, params) = Sqlite::build(query)?;
297    ///
298    /// assert_eq!("INSERT INTO `users` (`foo`) VALUES (?), (?)", sql);
299    ///
300    /// assert_eq!(
301    ///     vec![
302    ///         Value::from(1),
303    ///         Value::from(2),
304    ///     ], params);
305    /// # Ok(())
306    /// # }
307    /// ```
308    pub fn values<V>(mut self, values: V) -> Self
309    where
310        V: Into<Row<'a>>,
311    {
312        self.values.push(values.into());
313        self
314    }
315
316    /// Convert into a common `Insert` statement.
317    pub fn build(self) -> Insert<'a> {
318        Insert::from(self)
319    }
320}