Skip to main content

linkrs_query/parser/parsing/
explain_parser.rs

1//! Explain / Profile / Analyze Statement Parsing Module
2//!
3//! Responsible for parsing EXPLAIN, PROFILE, and ANALYZE statements.
4
5use crate::parser::ast::stmt::*;
6use crate::parser::core::error::{ParseError, ParseErrorKind};
7use crate::parser::parsing::parse_context::ParseContext;
8use crate::parser::parsing::stmt_parser::StmtParser;
9use crate::parser::TokenKind;
10
11/// Explain / Profile / Analyze Parser
12pub struct ExplainParser;
13
14impl Default for ExplainParser {
15    fn default() -> Self {
16        Self
17    }
18}
19
20impl ExplainParser {
21    pub fn new() -> Self {
22        Self
23    }
24
25    /// Parse EXPLAIN statement (contains a sub-statement)
26    pub fn parse_explain_statement(&mut self, ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
27        let start_span = ctx.current_span();
28        ctx.expect_token(TokenKind::Explain)?;
29
30        let analyze = ctx.match_token(TokenKind::Analyze);
31
32        let format = if ctx.match_token(TokenKind::Format) {
33            ctx.expect_token(TokenKind::Assign)?;
34            let format_name = ctx.expect_identifier()?;
35            match format_name.to_uppercase().as_str() {
36                "DOT" => ExplainFormat::Dot,
37                "TABLE" => ExplainFormat::Table,
38                _ => {
39                    return Err(ParseError::new(
40                        ParseErrorKind::SyntaxError,
41                        format!(
42                            "Unknown EXPLAIN format: {}, expects DOT or TABLE",
43                            format_name
44                        ),
45                        ctx.current_position(),
46                    ));
47                }
48            }
49        } else {
50            ExplainFormat::default()
51        };
52
53        let statement = Box::new(StmtParser::parse_statement(ctx)?);
54
55        Ok(Stmt::Explain(ExplainStmt {
56            span: start_span,
57            statement,
58            format,
59            analyze,
60        }))
61    }
62
63    /// Parse PROFILE statement
64    pub fn parse_profile_statement(&mut self, ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
65        let start_span = ctx.current_span();
66        ctx.expect_token(TokenKind::Profile)?;
67
68        let format = if ctx.match_token(TokenKind::Format) {
69            ctx.expect_token(TokenKind::Assign)?;
70            let format_name = ctx.expect_identifier()?;
71            match format_name.to_uppercase().as_str() {
72                "DOT" => ExplainFormat::Dot,
73                "TABLE" => ExplainFormat::Table,
74                _ => {
75                    return Err(ParseError::new(
76                        ParseErrorKind::SyntaxError,
77                        format!(
78                            "Unknown PROFILE format: {}, expects DOT or TABLE",
79                            format_name
80                        ),
81                        ctx.current_position(),
82                    ));
83                }
84            }
85        } else {
86            ExplainFormat::default()
87        };
88
89        let statement = Box::new(StmtParser::parse_statement(ctx)?);
90
91        Ok(Stmt::Profile(ProfileStmt {
92            span: start_span,
93            statement,
94            format,
95        }))
96    }
97
98    /// Parse ANALYZE statement: `ANALYZE` or `ANALYZE SPACE <name>`.
99    pub fn parse_analyze_statement(&mut self, ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
100        let start_span = ctx.current_span();
101        ctx.expect_token(TokenKind::Analyze)?;
102
103        let space = if ctx.match_token(TokenKind::Space) {
104            Some(ctx.expect_identifier()?)
105        } else {
106            None
107        };
108
109        Ok(Stmt::Analyze(AnalyzeStmt {
110            span: start_span,
111            space,
112        }))
113    }
114}