alopex_sql/parser/
dml.rs

1use crate::ast::span::Spanned;
2use crate::ast::{Assignment, Delete, Insert, OrderByExpr, Select, SelectItem, TableRef, Update};
3use crate::error::Result;
4use crate::tokenizer::keyword::Keyword;
5use crate::tokenizer::token::{Token, Word};
6
7use super::Parser;
8
9impl<'a> Parser<'a> {
10    pub fn parse_select(&mut self) -> Result<Select> {
11        let start_span = self.expect_keyword("SELECT", Keyword::SELECT)?;
12        let distinct = self.consume_keyword(Keyword::DISTINCT);
13
14        let projection = self.parse_projection_list()?;
15
16        self.expect_keyword("FROM", Keyword::FROM)?;
17        let from = self.parse_table_ref()?;
18        let mut end_span = from.span;
19
20        let selection = if self.consume_keyword(Keyword::WHERE) {
21            let expr = self.parse_expr()?;
22            end_span = end_span.union(&expr.span());
23            Some(expr)
24        } else {
25            None
26        };
27
28        let order_by = if self.consume_keyword(Keyword::ORDER) {
29            self.expect_keyword("BY", Keyword::BY)?;
30            let items = self.parse_order_by()?;
31            if let Some(last) = items.last() {
32                end_span = end_span.union(&last.span);
33            }
34            items
35        } else {
36            Vec::new()
37        };
38
39        let mut limit = None;
40        let mut offset = None;
41        if self.consume_keyword(Keyword::LIMIT) {
42            let lim = self.parse_expr()?;
43            end_span = end_span.union(&lim.span());
44            limit = Some(lim);
45
46            if self.consume_keyword(Keyword::OFFSET) {
47                let off = self.parse_expr()?;
48                end_span = end_span.union(&off.span());
49                offset = Some(off);
50            }
51        }
52
53        let span = start_span.union(&end_span);
54        Ok(Select {
55            distinct,
56            projection,
57            from,
58            selection,
59            order_by,
60            limit,
61            offset,
62            span,
63        })
64    }
65
66    fn parse_projection_list(&mut self) -> Result<Vec<SelectItem>> {
67        let mut items = Vec::new();
68        loop {
69            items.push(self.parse_select_item()?);
70            if matches!(self.peek().token, Token::Comma) {
71                self.advance();
72                continue;
73            }
74            break;
75        }
76        Ok(items)
77    }
78
79    fn parse_select_item(&mut self) -> Result<SelectItem> {
80        let tok = self.peek().clone();
81        if matches!(tok.token, Token::Mul) {
82            self.advance();
83            return Ok(SelectItem::Wildcard { span: tok.span });
84        }
85
86        let expr = self.parse_expr()?;
87        let mut span = expr.span();
88        let mut alias = None;
89
90        if self.consume_keyword(Keyword::AS) {
91            let (name, alias_span) = self.parse_identifier()?;
92            span = span.union(&alias_span);
93            alias = Some(name);
94        } else if let Token::Word(Word {
95            keyword: Keyword::NoKeyword,
96            ..
97        }) = &self.peek().token
98        {
99            let alias_tok = self.advance();
100            if let Token::Word(Word { value, .. }) = alias_tok.token {
101                span = span.union(&alias_tok.span);
102                alias = Some(value);
103            }
104        }
105
106        Ok(SelectItem::Expr { expr, alias, span })
107    }
108
109    fn parse_table_ref(&mut self) -> Result<TableRef> {
110        let (name, name_span) = self.parse_identifier()?;
111        let mut alias = None;
112        let mut span = name_span;
113
114        if self.consume_keyword(Keyword::AS) {
115            let (a, alias_span) = self.parse_identifier()?;
116            alias = Some(a);
117            span = span.union(&alias_span);
118        } else if let Token::Word(Word {
119            keyword: Keyword::NoKeyword,
120            ..
121        }) = &self.peek().token
122        {
123            let alias_tok = self.advance();
124            if let Token::Word(Word { value, .. }) = alias_tok.token {
125                span = span.union(&alias_tok.span);
126                alias = Some(value);
127            }
128        }
129
130        Ok(TableRef { name, alias, span })
131    }
132
133    fn parse_order_by(&mut self) -> Result<Vec<OrderByExpr>> {
134        let mut items = Vec::new();
135        loop {
136            let expr = self.parse_expr()?;
137            let mut span = expr.span();
138            let mut asc = None;
139            let mut nulls_first = None;
140
141            if let Token::Word(Word { keyword, .. }) = &self.peek().token {
142                match keyword {
143                    Keyword::ASC => {
144                        let s = self.advance().span;
145                        span = span.union(&s);
146                        asc = Some(true);
147                    }
148                    Keyword::DESC => {
149                        let s = self.advance().span;
150                        span = span.union(&s);
151                        asc = Some(false);
152                    }
153                    _ => {}
154                }
155            }
156
157            if let Token::Word(Word {
158                keyword: Keyword::NULLS,
159                ..
160            }) = &self.peek().token
161            {
162                let nulls_tok = self.advance();
163                let dir_tok = self.expect_token("FIRST or LAST", |t| {
164                    matches!(
165                        t,
166                        Token::Word(Word {
167                            keyword: Keyword::FIRST | Keyword::LAST,
168                            ..
169                        })
170                    )
171                })?;
172                nulls_first = Some(matches!(
173                    dir_tok.token,
174                    Token::Word(Word {
175                        keyword: Keyword::FIRST,
176                        ..
177                    })
178                ));
179                span = span.union(&nulls_tok.span).union(&dir_tok.span);
180            }
181
182            items.push(OrderByExpr {
183                expr,
184                asc,
185                nulls_first,
186                span,
187            });
188
189            if matches!(self.peek().token, Token::Comma) {
190                self.advance();
191                continue;
192            }
193            break;
194        }
195
196        Ok(items)
197    }
198
199    pub fn parse_insert(&mut self) -> Result<Insert> {
200        let start_span = self.expect_keyword("INSERT", Keyword::INSERT)?;
201        self.expect_keyword("INTO", Keyword::INTO)?;
202        let (table, table_span) = self.parse_identifier()?;
203        let mut end_span = table_span;
204        let mut columns = None;
205
206        if matches!(self.peek().token, Token::LParen) {
207            self.advance();
208            let mut cols = Vec::new();
209            loop {
210                let (col, col_span) = self.parse_identifier()?;
211                end_span = end_span.union(&col_span);
212                cols.push(col);
213                if matches!(self.peek().token, Token::Comma) {
214                    self.advance();
215                    continue;
216                }
217                break;
218            }
219            let close = self
220                .expect_token("')'", |t| matches!(t, Token::RParen))?
221                .span;
222            end_span = end_span.union(&close);
223            columns = Some(cols);
224        }
225
226        self.expect_keyword("VALUES", Keyword::VALUES)?;
227        let mut values = Vec::new();
228        loop {
229            self.expect_token("'('", |t| matches!(t, Token::LParen))?;
230            let mut row = Vec::new();
231            row.push(self.parse_expr()?);
232            while matches!(self.peek().token, Token::Comma) {
233                self.advance();
234                row.push(self.parse_expr()?);
235            }
236            let row_end = self
237                .expect_token("')'", |t| matches!(t, Token::RParen))?
238                .span;
239            end_span = end_span.union(&row_end);
240            values.push(row);
241
242            if matches!(self.peek().token, Token::Comma) {
243                self.advance();
244                continue;
245            }
246            break;
247        }
248
249        let span = start_span.union(&end_span);
250        Ok(Insert {
251            table,
252            columns,
253            values,
254            span,
255        })
256    }
257
258    pub fn parse_update(&mut self) -> Result<Update> {
259        let start_span = self.expect_keyword("UPDATE", Keyword::UPDATE)?;
260        let (table, table_span) = self.parse_identifier()?;
261        self.expect_keyword("SET", Keyword::SET)?;
262
263        let mut assignments = Vec::new();
264        loop {
265            let (column, col_span) = self.parse_identifier()?;
266            self.expect_token("'='", |t| matches!(t, Token::Eq))?;
267            let value = self.parse_expr()?;
268            let span = col_span.union(&value.span());
269            assignments.push(Assignment {
270                column,
271                value,
272                span,
273            });
274
275            if matches!(self.peek().token, Token::Comma) {
276                self.advance();
277                continue;
278            }
279            break;
280        }
281
282        let mut end_span = assignments.last().map(|a| a.span).unwrap_or(table_span);
283
284        let selection = if self.consume_keyword(Keyword::WHERE) {
285            let expr = self.parse_expr()?;
286            end_span = end_span.union(&expr.span());
287            Some(expr)
288        } else {
289            None
290        };
291
292        let span = start_span.union(&end_span);
293        Ok(Update {
294            table,
295            assignments,
296            selection,
297            span,
298        })
299    }
300
301    pub fn parse_delete(&mut self) -> Result<Delete> {
302        let start_span = self.expect_keyword("DELETE", Keyword::DELETE)?;
303        self.expect_keyword("FROM", Keyword::FROM)?;
304        let (table, table_span) = self.parse_identifier()?;
305        let mut end_span = table_span;
306
307        let selection = if self.consume_keyword(Keyword::WHERE) {
308            let expr = self.parse_expr()?;
309            end_span = end_span.union(&expr.span());
310            Some(expr)
311        } else {
312            None
313        };
314
315        let span = start_span.union(&end_span);
316        Ok(Delete {
317            table,
318            selection,
319            span,
320        })
321    }
322}