Skip to main content

keelson_psql/statement/
insert.rs

1use keelson_core::clause::{
2    Conflict, HasConflict, HasReturning, HasTableRef, HasValues, HasWith, Returning, TableRef,
3    Values, With,
4};
5use keelson_core::expr::{Expr, IntoExpr, IntoExprList};
6use keelson_core::{Dialect, Error, Expression, Mod, Query, QueryExtensions, QueryType, SqlWriter};
7
8use crate::Psql;
9use crate::extras::Overriding;
10
11/// A PostgreSQL `INSERT`.
12///
13/// From <https://www.postgresql.org/docs/17/sql-insert.html>:
14///
15/// ```text
16/// [ WITH [ RECURSIVE ] with_query [, ...] ]
17/// INSERT INTO table_name [ AS alias ] [ ( column_name [, ...] ) ]
18///     [ OVERRIDING { SYSTEM | USER } VALUE ]
19///     { DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }
20///     [ ON CONFLICT [ conflict_target ] conflict_action ]
21///     [ RETURNING … ]
22/// ```
23///
24/// The row source is one of three alternatives, and `DEFAULT VALUES` is the one
25/// [`Values`] cannot represent — an absent clause has to render nothing, and the
26/// spelling is not shared with MySQL anyway. So an empty `Values` is what
27/// `DEFAULT VALUES` *is* here, and this query writes the keywords itself.
28#[derive(Debug, Clone, Default)]
29pub struct InsertQuery {
30    /// `WITH …`.
31    pub with: With,
32    /// The target: table, optional alias, and the insert column list.
33    pub table: TableRef,
34    /// `OVERRIDING … VALUE`.
35    pub overriding: Option<Overriding>,
36    /// The rows, or the query to insert the results of. Empty means
37    /// `DEFAULT VALUES`.
38    pub values: Values,
39    /// `ON CONFLICT …`.
40    pub conflict: Conflict,
41    /// `RETURNING …`.
42    pub returning: Returning,
43}
44
45impl InsertQuery {
46    /// An `INSERT` with nothing set yet.
47    pub fn new() -> InsertQuery {
48        InsertQuery::default()
49    }
50
51    /// Apply more mods to an existing query.
52    pub fn apply(&mut self, mods: impl Mod<InsertQuery>) {
53        mods.apply(self);
54    }
55}
56
57impl Expression for InsertQuery {
58    fn write_sql(&self, w: &mut SqlWriter<'_>) {
59        w.write_if(!self.with.is_empty(), "", &self.with, " ");
60
61        if self.table.is_empty() {
62            // Unlike a `SELECT`, which is a statement without a table, an `INSERT`
63            // has nowhere to put the rows.
64            w.record_error(Error::Incomplete("the target table of an INSERT"));
65            return;
66        }
67        w.push_str("INSERT INTO ");
68        w.write_expr(&self.table);
69
70        if let Some(overriding) = &self.overriding {
71            w.push_str(" OVERRIDING ");
72            w.push_str(overriding.as_str());
73            w.push_str(" VALUE");
74        }
75
76        if self.values.is_empty() {
77            w.push_str(" DEFAULT VALUES");
78        } else {
79            w.push_str(" ");
80            w.write_expr(&self.values);
81        }
82
83        w.write_if(!self.conflict.is_empty(), " ", &self.conflict, "");
84        w.write_if(!self.returning.is_empty(), " ", &self.returning, "");
85    }
86}
87
88impl Query for InsertQuery {
89    fn query_type(&self) -> QueryType {
90        QueryType::Insert
91    }
92
93    fn dialect(&self) -> &dyn Dialect {
94        &Psql
95    }
96}
97
98impl<H, L, M> QueryExtensions<H, L, M> for InsertQuery {}
99
100impl IntoExpr for InsertQuery {
101    fn into_expr(self) -> Expr {
102        crate::query(self)
103    }
104}
105
106impl IntoExprList for InsertQuery {
107    fn into_expr_list(self) -> Vec<Expr> {
108        vec![self.into_expr()]
109    }
110}
111
112impl HasWith for InsertQuery {
113    fn with_mut(&mut self) -> &mut With {
114        &mut self.with
115    }
116}
117
118impl HasTableRef for InsertQuery {
119    fn table_ref_mut(&mut self) -> &mut TableRef {
120        &mut self.table
121    }
122}
123
124impl HasValues for InsertQuery {
125    fn values_mut(&mut self) -> &mut Values {
126        &mut self.values
127    }
128}
129
130impl HasConflict for InsertQuery {
131    fn conflict_mut(&mut self) -> &mut Conflict {
132        &mut self.conflict
133    }
134}
135
136impl HasReturning for InsertQuery {
137    fn returning_mut(&mut self) -> &mut Returning {
138        &mut self.returning
139    }
140}