vibesql_parser/parser/
introspection.rs

1//! Database introspection statement parsing (SHOW, DESCRIBE)
2
3use super::{ParseError, Parser};
4use crate::keywords::Keyword;
5use crate::token::Token;
6
7impl Parser {
8    /// Helper to parse a string literal
9    fn parse_string(&mut self) -> Result<String, ParseError> {
10        match self.peek() {
11            Token::String(s) => {
12                let string_val = s.clone();
13                self.advance();
14                Ok(string_val)
15            }
16            _ => Err(ParseError {
17                message: format!("Expected string literal, found {:?}", self.peek()),
18            }),
19        }
20    }
21
22    /// Parse SHOW statement
23    pub fn parse_show_statement(&mut self) -> Result<vibesql_ast::Statement, ParseError> {
24        self.expect_keyword(Keyword::Show)?;
25
26        // Determine which SHOW variant
27        match self.peek() {
28            Token::Keyword(Keyword::Tables) => {
29                Ok(vibesql_ast::Statement::ShowTables(self.parse_show_tables()?))
30            }
31            Token::Keyword(Keyword::Databases) => {
32                Ok(vibesql_ast::Statement::ShowDatabases(self.parse_show_databases()?))
33            }
34            Token::Keyword(Keyword::Full) => {
35                // SHOW FULL COLUMNS - handle FULL modifier for SHOW COLUMNS
36                Ok(vibesql_ast::Statement::ShowColumns(self.parse_show_columns()?))
37            }
38            Token::Keyword(Keyword::Columns) | Token::Keyword(Keyword::Fields) => {
39                Ok(vibesql_ast::Statement::ShowColumns(self.parse_show_columns()?))
40            }
41            Token::Keyword(Keyword::Index)
42            | Token::Keyword(Keyword::Indexes)
43            | Token::Keyword(Keyword::Keys) => {
44                Ok(vibesql_ast::Statement::ShowIndex(self.parse_show_index()?))
45            }
46            Token::Keyword(Keyword::Create) => {
47                self.advance(); // consume CREATE
48                if self.peek_keyword(Keyword::Table) {
49                    Ok(vibesql_ast::Statement::ShowCreateTable(self.parse_show_create_table()?))
50                } else {
51                    Err(ParseError { message: "Expected TABLE after SHOW CREATE".to_string() })
52                }
53            }
54            _ => Err(ParseError {
55                message: format!(
56                    "Expected TABLES, DATABASES, COLUMNS, INDEX, or CREATE after SHOW, found {:?}",
57                    self.peek()
58                ),
59            }),
60        }
61    }
62
63    /// Parse SHOW TABLES [FROM database] [LIKE pattern | WHERE expr]
64    fn parse_show_tables(&mut self) -> Result<vibesql_ast::ShowTablesStmt, ParseError> {
65        self.expect_keyword(Keyword::Tables)?;
66
67        // Optional FROM database
68        let database = if self.peek_keyword(Keyword::From) {
69            self.advance();
70            Some(self.parse_identifier()?)
71        } else {
72            None
73        };
74
75        // Optional LIKE pattern
76        let like_pattern = if self.peek_keyword(Keyword::Like) {
77            self.advance();
78            Some(self.parse_string()?)
79        } else {
80            None
81        };
82
83        // Optional WHERE clause
84        let where_clause = if self.peek_keyword(Keyword::Where) {
85            self.advance();
86            Some(self.parse_expression()?)
87        } else {
88            None
89        };
90
91        Ok(vibesql_ast::ShowTablesStmt { database, like_pattern, where_clause })
92    }
93
94    /// Parse SHOW DATABASES [LIKE pattern | WHERE expr]
95    fn parse_show_databases(&mut self) -> Result<vibesql_ast::ShowDatabasesStmt, ParseError> {
96        self.expect_keyword(Keyword::Databases)?;
97
98        // Optional LIKE pattern
99        let like_pattern = if self.peek_keyword(Keyword::Like) {
100            self.advance();
101            Some(self.parse_string()?)
102        } else {
103            None
104        };
105
106        // Optional WHERE clause
107        let where_clause = if self.peek_keyword(Keyword::Where) {
108            self.advance();
109            Some(self.parse_expression()?)
110        } else {
111            None
112        };
113
114        Ok(vibesql_ast::ShowDatabasesStmt { like_pattern, where_clause })
115    }
116
117    /// Parse SHOW [FULL] COLUMNS FROM table [FROM database] [LIKE pattern | WHERE expr]
118    fn parse_show_columns(&mut self) -> Result<vibesql_ast::ShowColumnsStmt, ParseError> {
119        // Check for FULL modifier
120        let full = if self.peek_keyword(Keyword::Full) {
121            self.advance();
122            true
123        } else {
124            false
125        };
126
127        // COLUMNS or FIELDS (synonyms)
128        if !self.peek_keyword(Keyword::Columns) && !self.peek_keyword(Keyword::Fields) {
129            return Err(ParseError { message: "Expected COLUMNS or FIELDS".to_string() });
130        }
131        self.advance();
132
133        // FROM table_name
134        self.expect_keyword(Keyword::From)?;
135        let table_name = self.parse_identifier()?;
136
137        // Optional FROM database (second FROM)
138        let database = if self.peek_keyword(Keyword::From) {
139            self.advance();
140            Some(self.parse_identifier()?)
141        } else {
142            None
143        };
144
145        // Optional LIKE pattern
146        let like_pattern = if self.peek_keyword(Keyword::Like) {
147            self.advance();
148            Some(self.parse_string()?)
149        } else {
150            None
151        };
152
153        // Optional WHERE clause
154        let where_clause = if self.peek_keyword(Keyword::Where) {
155            self.advance();
156            Some(self.parse_expression()?)
157        } else {
158            None
159        };
160
161        Ok(vibesql_ast::ShowColumnsStmt { table_name, database, full, like_pattern, where_clause })
162    }
163
164    /// Parse SHOW INDEX FROM table [FROM database]
165    fn parse_show_index(&mut self) -> Result<vibesql_ast::ShowIndexStmt, ParseError> {
166        // INDEX, INDEXES, or KEYS (synonyms)
167        self.advance(); // consume the keyword
168
169        // FROM table_name
170        self.expect_keyword(Keyword::From)?;
171        let table_name = self.parse_identifier()?;
172
173        // Optional FROM database
174        let database = if self.peek_keyword(Keyword::From) {
175            self.advance();
176            Some(self.parse_identifier()?)
177        } else {
178            None
179        };
180
181        Ok(vibesql_ast::ShowIndexStmt { table_name, database })
182    }
183
184    /// Parse SHOW CREATE TABLE table_name
185    fn parse_show_create_table(&mut self) -> Result<vibesql_ast::ShowCreateTableStmt, ParseError> {
186        self.expect_keyword(Keyword::Table)?;
187        let table_name = self.parse_identifier()?;
188
189        Ok(vibesql_ast::ShowCreateTableStmt { table_name })
190    }
191
192    /// Parse DESCRIBE table [column_pattern]
193    pub fn parse_describe_statement(&mut self) -> Result<vibesql_ast::DescribeStmt, ParseError> {
194        self.expect_keyword(Keyword::Describe)?;
195
196        let table_name = self.parse_identifier()?;
197
198        // Optional column name or pattern
199        let column_pattern = if matches!(self.peek(), Token::Identifier(_) | Token::String(_)) {
200            Some(match self.peek() {
201                Token::String(_) => self.parse_string()?,
202                _ => self.parse_identifier()?,
203            })
204        } else {
205            None
206        };
207
208        Ok(vibesql_ast::DescribeStmt { table_name, column_pattern })
209    }
210
211    /// Parse EXPLAIN [ANALYZE] statement
212    ///
213    /// Syntax: EXPLAIN [ANALYZE] [FORMAT {TEXT | JSON}] statement
214    pub fn parse_explain_statement(&mut self) -> Result<vibesql_ast::ExplainStmt, ParseError> {
215        self.expect_keyword(Keyword::Explain)?;
216
217        // Check for ANALYZE option
218        let analyze = if matches!(self.peek(), Token::Keyword(Keyword::Analyze)) {
219            self.advance();
220            true
221        } else {
222            false
223        };
224
225        // Check for FORMAT option (optional)
226        let format = if matches!(self.peek(), Token::Identifier(ref s) if s.to_uppercase() == "FORMAT")
227        {
228            self.advance(); // consume FORMAT
229            match self.peek() {
230                Token::Identifier(ref s) if s.to_uppercase() == "TEXT" => {
231                    self.advance();
232                    vibesql_ast::ExplainFormat::Text
233                }
234                Token::Identifier(ref s) if s.to_uppercase() == "JSON" => {
235                    self.advance();
236                    vibesql_ast::ExplainFormat::Json
237                }
238                _ => {
239                    return Err(ParseError {
240                        message: format!(
241                            "Expected TEXT or JSON after FORMAT, found {:?}",
242                            self.peek()
243                        ),
244                    });
245                }
246            }
247        } else {
248            vibesql_ast::ExplainFormat::Text
249        };
250
251        // Parse the inner statement (SELECT, INSERT, UPDATE, DELETE)
252        let statement = match self.peek() {
253            Token::Keyword(Keyword::Select) | Token::Keyword(Keyword::With) => {
254                let select_stmt = self.parse_select_statement()?;
255                vibesql_ast::Statement::Select(Box::new(select_stmt))
256            }
257            Token::Keyword(Keyword::Insert) => {
258                let insert_stmt = self.parse_insert_statement()?;
259                vibesql_ast::Statement::Insert(insert_stmt)
260            }
261            Token::Keyword(Keyword::Update) => {
262                let update_stmt = self.parse_update_statement()?;
263                vibesql_ast::Statement::Update(update_stmt)
264            }
265            Token::Keyword(Keyword::Delete) => {
266                let delete_stmt = self.parse_delete_statement()?;
267                vibesql_ast::Statement::Delete(delete_stmt)
268            }
269            _ => {
270                return Err(ParseError {
271                    message: format!(
272                        "EXPLAIN requires SELECT, INSERT, UPDATE, or DELETE statement, found {:?}",
273                        self.peek()
274                    ),
275                });
276            }
277        };
278
279        Ok(vibesql_ast::ExplainStmt { statement: Box::new(statement), format, analyze })
280    }
281}