Skip to main content

vecdb_core/planner/sql/
parser.rs

1use std::mem::discriminant;
2
3use crate::errors::{Result, VecDbError};
4
5use super::ast::{
6    Condition, Literal, Operator, OrderBy, ScalarCondition, SelectStatement, VectorCondition,
7};
8use super::lexer::{Lexer, Token};
9
10// ─────────────────────────────────────────────────────────────────
11// SqlParser
12// ─────────────────────────────────────────────────────────────────
13
14pub struct SqlParser {
15    tokens: Vec<Token>,
16    pos: usize,
17}
18
19impl SqlParser {
20    /// Parse a SQL string into a `SelectStatement`.
21    pub fn parse(sql: &str) -> Result<SelectStatement> {
22        let mut lexer = Lexer::new(sql);
23        let tokens = lexer.tokenize()?;
24        let mut parser = SqlParser { tokens, pos: 0 };
25        parser.parse_select()
26    }
27
28    // ── Token navigation ─────────────────────────────────────────
29
30    /// Peek at the current token without consuming it.
31    fn peek(&self) -> Token {
32        self.tokens.get(self.pos).cloned().unwrap_or(Token::Eof)
33    }
34
35    /// Consume and return the current token.
36    fn advance(&mut self) -> Token {
37        if self.pos < self.tokens.len() {
38            let tok = self.tokens[self.pos].clone();
39            self.pos += 1;
40            tok
41        } else {
42            Token::Eof
43        }
44    }
45
46    /// Consume the current token, returning an error if its variant does not
47    /// match `expected`.  Only the variant discriminant is compared — inner
48    /// values are ignored (e.g. `expect(Token::Identifier(String::new()))` will
49    /// match any `Identifier(_)`).
50    fn expect(&mut self, expected: Token) -> Result<()> {
51        let tok = self.advance();
52        if discriminant(&tok) == discriminant(&expected) {
53            Ok(())
54        } else {
55            Err(VecDbError::InvalidQuery(format!(
56                "expected {:?}, got {:?}",
57                expected, tok
58            )))
59        }
60    }
61
62    /// Return `true` if the current token's variant matches `expected`.
63    fn is_next(&self, expected: &Token) -> bool {
64        discriminant(&self.peek()) == discriminant(expected)
65    }
66
67    // ── Grammar rules ─────────────────────────────────────────────
68
69    fn parse_select(&mut self) -> Result<SelectStatement> {
70        self.expect(Token::Select)?;
71        let columns = self.parse_columns()?;
72        self.expect(Token::From)?;
73
74        let table = match self.advance() {
75            Token::Identifier(s) => s,
76            tok => {
77                return Err(VecDbError::InvalidQuery(format!(
78                    "expected table name, got {:?}",
79                    tok
80                )))
81            }
82        };
83
84        let where_clause = if self.is_next(&Token::Where) {
85            self.advance(); // consume WHERE
86            Some(self.parse_where_clause()?)
87        } else {
88            None
89        };
90
91        let order_by = if self.is_next(&Token::Order) {
92            self.advance(); // consume ORDER
93            self.expect(Token::By)?;
94            Some(self.parse_order_by()?)
95        } else {
96            None
97        };
98
99        let limit = if self.is_next(&Token::Limit) {
100            self.advance(); // consume LIMIT
101            match self.advance() {
102                Token::IntLit(n) => Some(n as usize),
103                tok => {
104                    return Err(VecDbError::InvalidQuery(format!(
105                        "expected integer after LIMIT, got {:?}",
106                        tok
107                    )))
108                }
109            }
110        } else {
111            None
112        };
113
114        // Optional trailing semicolon.
115        if self.is_next(&Token::Semicolon) {
116            self.advance();
117        }
118
119        Ok(SelectStatement {
120            table,
121            columns,
122            where_clause,
123            order_by,
124            limit,
125        })
126    }
127
128    fn parse_columns(&mut self) -> Result<Vec<String>> {
129        if self.is_next(&Token::Star) {
130            self.advance();
131            return Ok(vec![]);
132        }
133
134        let mut cols = Vec::new();
135        loop {
136            match self.peek() {
137                Token::Star => {
138                    self.advance();
139                    return Ok(vec![]);
140                }
141                Token::Identifier(_) => {
142                    if let Token::Identifier(s) = self.advance() {
143                        cols.push(s);
144                    }
145                }
146                tok => {
147                    return Err(VecDbError::InvalidQuery(format!(
148                        "expected column name or '*', got {:?}",
149                        tok
150                    )))
151                }
152            }
153            if self.is_next(&Token::Comma) {
154                self.advance();
155            } else {
156                break;
157            }
158        }
159        Ok(cols)
160    }
161
162    fn parse_where_clause(&mut self) -> Result<Condition> {
163        self.parse_or_condition()
164    }
165
166    fn parse_or_condition(&mut self) -> Result<Condition> {
167        let mut left = self.parse_and_condition()?;
168        while self.is_next(&Token::Or) {
169            self.advance(); // consume OR
170            let right = self.parse_and_condition()?;
171            left = Condition::Or(Box::new(left), Box::new(right));
172        }
173        Ok(left)
174    }
175
176    fn parse_and_condition(&mut self) -> Result<Condition> {
177        let mut left = self.parse_atom_condition()?;
178        while self.is_next(&Token::And) {
179            self.advance(); // consume AND
180            let right = self.parse_atom_condition()?;
181            left = Condition::And(Box::new(left), Box::new(right));
182        }
183        Ok(left)
184    }
185
186    fn parse_atom_condition(&mut self) -> Result<Condition> {
187        // NOT <condition>
188        if self.is_next(&Token::Not) {
189            self.advance();
190            let inner = self.parse_atom_condition()?;
191            return Ok(Condition::Not(Box::new(inner)));
192        }
193
194        // Parenthesised condition
195        if self.is_next(&Token::LParen) {
196            self.advance(); // consume (
197            let cond = self.parse_or_condition()?;
198            self.expect(Token::RParen)?;
199            return Ok(cond);
200        }
201
202        // VECTOR_SIM(...)
203        if self.is_next(&Token::VectorSim) {
204            let vc = self.parse_vector_condition()?;
205            return Ok(Condition::Vector(vc));
206        }
207
208        // Scalar condition
209        let sc = self.parse_scalar_condition()?;
210        Ok(Condition::Scalar(sc))
211    }
212
213    fn parse_vector_condition(&mut self) -> Result<VectorCondition> {
214        self.expect(Token::VectorSim)?;
215        self.expect(Token::LParen)?;
216
217        let column = match self.advance() {
218            Token::Identifier(s) => s,
219            tok => {
220                return Err(VecDbError::InvalidQuery(format!(
221                    "expected column name in VECTOR_SIM, got {:?}",
222                    tok
223                )))
224            }
225        };
226
227        self.expect(Token::Comma)?;
228
229        let vector = match self.advance() {
230            Token::VectorLit(v) => v,
231            tok => {
232                return Err(VecDbError::InvalidQuery(format!(
233                    "expected vector literal in VECTOR_SIM, got {:?}",
234                    tok
235                )))
236            }
237        };
238
239        self.expect(Token::RParen)?;
240
241        let op = self.parse_operator()?;
242
243        let threshold = match self.advance() {
244            Token::FloatLit(f) => f as f32,
245            Token::IntLit(i) => i as f32,
246            tok => {
247                return Err(VecDbError::InvalidQuery(format!(
248                    "expected similarity threshold, got {:?}",
249                    tok
250                )))
251            }
252        };
253
254        Ok(VectorCondition {
255            column,
256            vector,
257            op,
258            threshold,
259        })
260    }
261
262    fn parse_scalar_condition(&mut self) -> Result<ScalarCondition> {
263        let field = self.parse_field_path()?;
264        let op = self.parse_operator()?;
265        let value = self.parse_literal()?;
266        Ok(ScalarCondition { field, op, value })
267    }
268
269    /// Parse a (possibly path-qualified) field name.
270    ///
271    /// Handles:
272    /// - `field`
273    /// - `table.field`
274    /// - `field->'key'`
275    /// - `field->>'key'`
276    fn parse_field_path(&mut self) -> Result<String> {
277        let mut path = match self.advance() {
278            Token::Identifier(s) => s,
279            tok => {
280                return Err(VecDbError::InvalidQuery(format!(
281                    "expected field name, got {:?}",
282                    tok
283                )))
284            }
285        };
286
287        loop {
288            match self.peek() {
289                Token::Dot => {
290                    self.advance();
291                    match self.advance() {
292                        Token::Identifier(s) => path = format!("{path}.{s}"),
293                        tok => {
294                            return Err(VecDbError::InvalidQuery(format!(
295                                "expected field after '.', got {:?}",
296                                tok
297                            )))
298                        }
299                    }
300                }
301                Token::Arrow => {
302                    self.advance();
303                    match self.advance() {
304                        Token::StringLit(s) => path = format!("{path}->'{s}'"),
305                        Token::Identifier(s) => path = format!("{path}->{s}"),
306                        tok => {
307                            return Err(VecDbError::InvalidQuery(format!(
308                                "expected key after '->', got {:?}",
309                                tok
310                            )))
311                        }
312                    }
313                }
314                Token::ArrowText => {
315                    self.advance();
316                    match self.advance() {
317                        Token::StringLit(s) => path = format!("{path}->>'{}'", s),
318                        Token::Identifier(s) => path = format!("{path}->>{s}"),
319                        tok => {
320                            return Err(VecDbError::InvalidQuery(format!(
321                                "expected key after '->>', got {:?}",
322                                tok
323                            )))
324                        }
325                    }
326                }
327                _ => break,
328            }
329        }
330        Ok(path)
331    }
332
333    fn parse_operator(&mut self) -> Result<Operator> {
334        match self.advance() {
335            Token::Eq => Ok(Operator::Eq),
336            Token::NotEq => Ok(Operator::NotEq),
337            Token::Lt => Ok(Operator::Lt),
338            Token::LtEq => Ok(Operator::LtEq),
339            Token::Gt => Ok(Operator::Gt),
340            Token::GtEq => Ok(Operator::GtEq),
341            Token::Like => Ok(Operator::Like),
342            tok => Err(VecDbError::InvalidQuery(format!(
343                "expected comparison operator, got {:?}",
344                tok
345            ))),
346        }
347    }
348
349    fn parse_literal(&mut self) -> Result<Literal> {
350        match self.advance() {
351            Token::StringLit(s) => Ok(Literal::String(s)),
352            Token::FloatLit(f) => Ok(Literal::Float(f)),
353            Token::IntLit(i) => Ok(Literal::Integer(i)),
354            Token::True => Ok(Literal::Bool(true)),
355            Token::False => Ok(Literal::Bool(false)),
356            tok => Err(VecDbError::InvalidQuery(format!(
357                "expected literal value, got {:?}",
358                tok
359            ))),
360        }
361    }
362
363    fn parse_order_by(&mut self) -> Result<OrderBy> {
364        let field = match self.advance() {
365            Token::Identifier(s) => s,
366            tok => {
367                return Err(VecDbError::InvalidQuery(format!(
368                    "expected field for ORDER BY, got {:?}",
369                    tok
370                )))
371            }
372        };
373        let descending = if self.is_next(&Token::Desc) {
374            self.advance();
375            true
376        } else if self.is_next(&Token::Asc) {
377            self.advance();
378            false
379        } else {
380            false // default: ascending
381        };
382        Ok(OrderBy { field, descending })
383    }
384}