Skip to main content

qcraft_core/ast/
dml.rs

1use super::common::SchemaRef;
2use super::conditions::Conditions;
3use super::custom::CustomMutation;
4use super::expr::Expr;
5use super::query::{CteDef, SelectColumn, TableSource};
6
7/// Data manipulation statements.
8#[derive(Debug, Clone)]
9pub enum MutationStmt {
10    Insert(InsertStmt),
11    Update(UpdateStmt),
12    Delete(DeleteStmt),
13    Custom(Box<dyn CustomMutation>),
14}
15
16// ---------------------------------------------------------------------------
17// INSERT
18// ---------------------------------------------------------------------------
19
20/// INSERT INTO ... VALUES / SELECT / DEFAULT VALUES.
21#[derive(Debug, Clone)]
22pub struct InsertStmt {
23    pub table: SchemaRef,
24    pub columns: Option<Vec<String>>,
25    pub source: InsertSource,
26    /// Multiple ON CONFLICT clauses (SQLite processes in order; last may omit target).
27    pub on_conflict: Option<Vec<OnConflictDef>>,
28    pub returning: Option<Vec<SelectColumn>>,
29    pub ctes: Option<Vec<CteDef>>,
30    /// PG: OVERRIDING { SYSTEM | USER } VALUE (for identity columns).
31    pub overriding: Option<OverridingKind>,
32    /// SQLite: INSERT OR REPLACE / OR IGNORE / OR ABORT / etc.
33    pub conflict_resolution: Option<ConflictResolution>,
34    /// MySQL/Oracle: PARTITION targeting.
35    pub partition: Option<Vec<String>>,
36    /// MySQL: IGNORE modifier (downgrades errors to warnings).
37    pub ignore: bool,
38}
39
40impl Default for InsertStmt {
41    fn default() -> Self {
42        Self {
43            table: SchemaRef::new(""),
44            columns: None,
45            source: InsertSource::DefaultValues,
46            on_conflict: None,
47            returning: None,
48            ctes: None,
49            overriding: None,
50            conflict_resolution: None,
51            partition: None,
52            ignore: false,
53        }
54    }
55}
56
57impl InsertStmt {
58    pub fn values(table: &str, columns: Vec<&str>, rows: Vec<Vec<Expr>>) -> Self {
59        Self {
60            table: SchemaRef::new(table),
61            columns: Some(columns.into_iter().map(String::from).collect()),
62            source: InsertSource::Values(rows),
63            ..Default::default()
64        }
65    }
66
67    pub fn from_select(table: &str, columns: Vec<&str>, query: super::query::QueryStmt) -> Self {
68        Self {
69            table: SchemaRef::new(table),
70            columns: Some(columns.into_iter().map(String::from).collect()),
71            source: InsertSource::Select(Box::new(query)),
72            ..Default::default()
73        }
74    }
75
76    pub fn default_values(table: &str) -> Self {
77        Self {
78            table: SchemaRef::new(table),
79            ..Default::default()
80        }
81    }
82
83    pub fn returning(mut self, cols: Vec<SelectColumn>) -> Self {
84        self.returning = Some(cols);
85        self
86    }
87
88    pub fn on_conflict(mut self, def: OnConflictDef) -> Self {
89        self.on_conflict = Some(vec![def]);
90        self
91    }
92}
93
94/// Source of data for INSERT.
95#[derive(Debug, Clone)]
96pub enum InsertSource {
97    /// VALUES (expr, ...), (expr, ...), ...
98    Values(Vec<Vec<Expr>>),
99    /// INSERT INTO ... SELECT ...
100    Select(Box<super::query::QueryStmt>),
101    /// DEFAULT VALUES (PG, SQLite, SQL Server).
102    DefaultValues,
103}
104
105/// PG identity column override.
106#[derive(Debug, Clone, Copy, PartialEq, Eq)]
107pub enum OverridingKind {
108    System,
109    User,
110}
111
112/// SQLite conflict resolution for INSERT/UPDATE.
113#[derive(Debug, Clone, Copy, PartialEq, Eq)]
114pub enum ConflictResolution {
115    Rollback,
116    Abort,
117    Fail,
118    Ignore,
119    Replace,
120}
121
122// ---------------------------------------------------------------------------
123// ON CONFLICT (upsert)
124// ---------------------------------------------------------------------------
125
126/// ON CONFLICT clause (PG / SQLite upsert).
127#[derive(Debug, Clone)]
128pub struct OnConflictDef {
129    /// Conflict target. None = catch-all (SQLite last clause).
130    pub target: Option<ConflictTarget>,
131    pub action: ConflictAction,
132}
133
134/// What triggers the conflict.
135#[derive(Debug, Clone)]
136pub enum ConflictTarget {
137    /// ON CONFLICT (col1, col2, ...) [WHERE ...]
138    Columns {
139        columns: Vec<String>,
140        where_clause: Option<Conditions>,
141    },
142    /// ON CONSTRAINT constraint_name (PG only).
143    Constraint(String),
144}
145
146/// What to do on conflict.
147#[derive(Debug, Clone)]
148pub enum ConflictAction {
149    DoNothing,
150    DoUpdate {
151        assignments: Vec<(String, Expr)>,
152        where_clause: Option<Conditions>,
153    },
154}
155
156impl OnConflictDef {
157    pub fn do_nothing() -> Self {
158        Self {
159            target: None,
160            action: ConflictAction::DoNothing,
161        }
162    }
163
164    pub fn do_update(columns: Vec<&str>, assignments: Vec<(&str, Expr)>) -> Self {
165        Self {
166            target: Some(ConflictTarget::Columns {
167                columns: columns.into_iter().map(String::from).collect(),
168                where_clause: None,
169            }),
170            action: ConflictAction::DoUpdate {
171                assignments: assignments
172                    .into_iter()
173                    .map(|(k, v)| (k.to_string(), v))
174                    .collect(),
175                where_clause: None,
176            },
177        }
178    }
179}
180
181// ---------------------------------------------------------------------------
182// UPDATE
183// ---------------------------------------------------------------------------
184
185/// UPDATE ... SET ... WHERE ...
186#[derive(Debug, Clone)]
187pub struct UpdateStmt {
188    pub table: SchemaRef,
189    pub assignments: Vec<(String, Expr)>,
190    pub from: Option<Vec<TableSource>>,
191    pub where_clause: Option<Conditions>,
192    pub returning: Option<Vec<SelectColumn>>,
193    pub ctes: Option<Vec<CteDef>>,
194    /// SQLite: UPDATE OR REPLACE / OR IGNORE / etc.
195    pub conflict_resolution: Option<ConflictResolution>,
196    /// SQLite/MySQL: ORDER BY for UPDATE.
197    pub order_by: Option<Vec<super::common::OrderByDef>>,
198    /// SQLite/MySQL: LIMIT for UPDATE.
199    pub limit: Option<u64>,
200    /// SQLite: LIMIT ... OFFSET ...
201    pub offset: Option<u64>,
202    /// PG: UPDATE ONLY table (exclude inherited/child tables).
203    pub only: bool,
204    /// MySQL/Oracle: PARTITION targeting.
205    pub partition: Option<Vec<String>>,
206    /// MySQL: IGNORE modifier (UpdateStmt).
207    pub ignore: bool,
208}
209
210impl Default for UpdateStmt {
211    fn default() -> Self {
212        Self {
213            table: SchemaRef::new(""),
214            assignments: vec![],
215            from: None,
216            where_clause: None,
217            returning: None,
218            ctes: None,
219            conflict_resolution: None,
220            order_by: None,
221            limit: None,
222            offset: None,
223            only: false,
224            partition: None,
225            ignore: false,
226        }
227    }
228}
229
230impl UpdateStmt {
231    pub fn new(table: &str, assignments: Vec<(&str, Expr)>) -> Self {
232        Self {
233            table: SchemaRef::new(table),
234            assignments: assignments
235                .into_iter()
236                .map(|(k, v)| (k.to_string(), v))
237                .collect(),
238            ..Default::default()
239        }
240    }
241
242    pub fn where_clause(mut self, cond: Conditions) -> Self {
243        self.where_clause = Some(cond);
244        self
245    }
246
247    pub fn returning(mut self, cols: Vec<SelectColumn>) -> Self {
248        self.returning = Some(cols);
249        self
250    }
251}
252
253// ---------------------------------------------------------------------------
254// DELETE
255// ---------------------------------------------------------------------------
256
257/// DELETE FROM ... WHERE ...
258#[derive(Debug, Clone)]
259pub struct DeleteStmt {
260    pub table: SchemaRef,
261    /// PG: USING from_item [, ...]; SQL Server: FROM table_source [, ...]
262    pub using: Option<Vec<TableSource>>,
263    pub where_clause: Option<Conditions>,
264    pub returning: Option<Vec<SelectColumn>>,
265    pub ctes: Option<Vec<CteDef>>,
266    /// SQLite/MySQL: ORDER BY for DELETE.
267    pub order_by: Option<Vec<super::common::OrderByDef>>,
268    /// SQLite/MySQL: LIMIT for DELETE.
269    pub limit: Option<u64>,
270    /// SQLite: LIMIT ... OFFSET ...
271    pub offset: Option<u64>,
272    /// PG: DELETE FROM ONLY table (exclude inherited/child tables).
273    pub only: bool,
274    /// MySQL/Oracle: PARTITION targeting.
275    pub partition: Option<Vec<String>>,
276    /// MySQL: IGNORE modifier.
277    pub ignore: bool,
278}
279
280impl Default for DeleteStmt {
281    fn default() -> Self {
282        Self {
283            table: SchemaRef::new(""),
284            using: None,
285            where_clause: None,
286            returning: None,
287            ctes: None,
288            order_by: None,
289            limit: None,
290            offset: None,
291            only: false,
292            partition: None,
293            ignore: false,
294        }
295    }
296}
297
298impl DeleteStmt {
299    pub fn new(table: &str) -> Self {
300        Self {
301            table: SchemaRef::new(table),
302            ..Default::default()
303        }
304    }
305
306    pub fn where_clause(mut self, cond: Conditions) -> Self {
307        self.where_clause = Some(cond);
308        self
309    }
310
311    pub fn returning(mut self, cols: Vec<SelectColumn>) -> Self {
312        self.returning = Some(cols);
313        self
314    }
315}